1 var Filex = Filex || {};
6 // ------------------------------------------------------------------------
8 // ------------------------------------------------------------------------
10 var OfflineModel = Backbone.Model.extend({
11 // prevent syncing with server
17 Filex.File = OfflineModel.extend({
30 isHidden: function() {
31 return this.get('name')[0] == '.';
35 this.set('checked', !this.get('checked'));
39 Filex.Directory = Filex.File.extend({
49 Filex.PathBit = OfflineModel.extend({
56 // ------------------------------------------------------------------------
58 // ------------------------------------------------------------------------
60 Filex.FileList = Backbone.Collection.extend({
63 model: function(attrs, options) {
64 switch (attrs['type']) {
66 return new Filex.Directory(attrs, options);
68 return new Filex.File(attrs, options);
70 console.error('Unknown model type:', attrs['type']);
74 comparator: function(a, b) {
75 if (a.isFile() == b.isFile())
76 return a.get('name').toLowerCase().localeCompare(b.get('name').toLowerCase());
78 return (a.isFile() && b.isDir()) ? 1 : -1;
82 return this.filter(function (item) {
83 return item.isHidden();
87 visible: function () {
88 return this.filter(function (item) {
89 return !item.isHidden();
94 Filex.Path = Backbone.Collection.extend({
97 initialize: function() {
98 this.listenTo(this, 'reset add', this.setActive);
101 setActive: function() {
102 _.each(this.initial(), function(bit) {
103 bit.set('active', false);
106 this.last().set('active', true);
110 return this.pluck('name').join('/').replace(/^\/+/, '/');
115 // ------------------------------------------------------------------------
117 // ------------------------------------------------------------------------
119 Filex.ListingItem = Backbone.View.extend({
126 initialize: function(options) {
127 this.view = options.view;
129 this.listenTo(this.model, 'change:checked', this.toggleChecked);
130 this.listenTo(this.model, 'remove', this.remove);
131 this.listenTo(this.model, 'hidden', this.toggleHidden);
134 template: function() {
135 var templateSelector = this.model.isDir() ? '#dir-template' : '#file-template';
137 return _.template($(templateSelector).html());
141 var data = this.model.toJSON();
142 data['url_params'] = $.param({
143 host: this.view.host,
144 path: this.view.path.full() + '/' + this.model.get('name')
146 data['cid'] = this.model.cid;
148 this.$el.html(this.template()(data));
154 toggleHidden: function() {
155 var isHidden = this.model.isHidden() && !this.view.showHidden();
156 this.$el.toggleClass('hidden', isHidden);
158 if (isHidden && this.model.get('checked'))
162 toggleChecked: function(obj, value) {
163 this.$el.toggleClass('active', value);
164 this.$el.find('input[type="checkbox"]').prop('checked', value);
168 if (e.target.className == 'link') {
169 if (this.model.isDir()) {
171 this.model.trigger('selected:dir', this.model);
181 Filex.Breadcrumb = Backbone.View.extend({
185 'click a': 'selected'
188 initialize: function() {
189 this.listenTo(this.model, 'change:active', this.render);
190 this.listenTo(this.model, 'remove', this.remove);
194 if (this.model.get('active')) {
195 this.$el.text(this.model.get('name'));
198 this.$el.html($('<a/>', {
200 text: this.model.get('name')
203 this.$el.toggleClass('active', this.model.get('active'));
208 selected: function(e) {
210 this.model.trigger('selected', this.model);
214 Filex.FilexView = Backbone.View.extend({
218 'change #show-hidden': 'toggleHidden',
219 'click #select-all': 'selectAll',
220 'click #btn-refresh': 'reloadFiles',
221 'click #btn-favorites': 'toggleFavorites',
222 'click #btn-host': 'editHost'
225 initialize: function(options) {
226 this.$noItems = $('#no-items');
227 this.$error = $('#error');
228 this.$showHidden = $('#show-hidden');
229 this.$selectAll = $('#select-all');
230 this.$favorites = $('#btn-favorites');
231 this.$host = $('#btn-host');
233 this.path = new Filex.Path();
234 this.files = new Filex.FileList();
236 this.listenTo(this.path, 'reset', this.resetPath);
237 this.listenTo(this.path, 'add', this.addPath);
238 this.listenTo(this.path, 'add reset', this.changedPath);
239 this.listenTo(this.path, 'selected', this.selectedPath);
240 this.listenTo(this.files, 'reset', this.resetFiles);
241 this.listenTo(this.files, 'selected:dir', this.selectedDir);
242 this.listenTo(this.files, 'change:checked', this.updateSelectAll);
244 // used in selectize callbacks
246 optionTemplate = _.template('<div><div><%= host %></div><div class="small text-muted"><%= path %></div></div>');
248 this.$('#host-selector').selectize({
249 optgroupField: 'group',
251 searchField: ['host', 'path'],
253 {field: 'host', direction: 'asc'},
254 {field: 'path', direction: 'asc'}
256 options: options.locations,
258 {value: 'sys', label: 'Podstawowe'},
259 {value: 'usr', label: 'Użytkownika'}
261 lockOptgroupOrder: true,
262 create: function(input, callback) {
263 var $form = $('#favorite-form'),
264 parts = input.split('/'),
265 callback_called = false;
268 $form.find('.alert-danger').remove();
269 $form.find('#id_host').val(parts.shift());
272 $form.find('#id_path').val(parts.join('/'));
275 $form.on('submit', function(e) {
277 $btn = $this.find('[type="submit"]');
280 $btn.button('loading');
281 $this.find('.alert-danger').remove();
283 $.post($this.attr('action'), $this.serialize(), function(data) {
285 callback_called = true;
288 $btn.button('reset');
289 }, 'json').fail(function(xhr) {
290 console.error(arguments);
291 var error = (xhr.responseJSON || {}).error || undefined;
294 error = 'Podana lokalizacja jest już zapisana'
296 else if (xhr.status == 400) {
297 error = 'Niepoprawna nazwa hosta lub ścieżka'
300 if (typeof error === 'string') {
302 'class': 'alert alert-danger',
303 html: '<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> ' + error
304 }).prependTo($this.find('.modal-body'));
305 $btn.button('reset');
308 $btn.button('error');
313 $form.one('hide.bs.modal', function() {
314 if (!callback_called)
322 option: function(item) {
323 return optionTemplate(item);
325 option_create : function(data, escape) {
326 return '<div class="create">Dodaj <em>' + escape(data.input) + '</em>…</div>';
329 onItemAdd: function(value) {
334 $('#host').removeClass('edit');
338 this.hostSelectize = this.$('#host-selector')[0].selectize;
344 this.updateSelectAll();
345 this.updateFavorites();
346 this.$noItems.toggle(!Boolean(this.visibleFiles().length));
350 load: function(location) {
351 var hostRootPath = location.split(/\/(\/|~)(.*)/),
352 pathBits = [new Filex.PathBit({'name': hostRootPath[1]})].concat(
353 _.chain(hostRootPath[2].split('/'))
355 .map(function(name) { return new Filex.PathBit({'name': name}) })
359 this.host = hostRootPath[0];
360 this.path.reset(pathBits);
362 this.$host.text(this.host);
365 reloadFiles: function() {
372 data: {host: this.host, path: this.path.full()},
373 success: function() {
377 error: function(collection, response) {
380 var msg = (response.responseJSON || {}).error || 'Błąd serwera';
382 view.$noItems.hide();
383 view.$error.find('.msg').text(msg);
390 addPath: function(bit) {
391 var view = new Filex.Breadcrumb({model: bit});
392 this.$('.path').append(view.render().el);
395 resetPath: function(models, options) {
396 _.each(options.previousModels, function(model) {
397 model.trigger('remove');
400 this.path.each(this.addPath, this);
403 resetFiles: function(models, options) {
404 _.each(options.previousModels, function(model) {
405 model.trigger('remove');
408 this.files.each(function(file) {
409 var view = new Filex.ListingItem({model: file, view: this});
410 this.$('tbody').append(view.render().el);
414 toggleHidden: function() {
415 this.files.each(function(item) { item.trigger('hidden'); }, this);
419 selectedDir: function(dir) {
420 this.path.add({'name': dir.get('name')});
423 selectedPath: function(bit) {
424 this.path.reset(this.path.slice(0, this.path.indexOf(bit) + 1));
427 showHidden: function() {
428 return this.$showHidden[0].checked;
432 this.$el.addClass('busy');
436 this.$el.removeClass('busy');
439 visibleFiles: function() {
440 return this.showHidden() ? this.files.models : this.files.visible();
443 selectedFiles: function() {
444 return _.filter(this.visibleFiles(), function(item) {
445 return item.get('checked');
449 selectAll: function() {
450 var checked = this.$selectAll[0].checked;
452 _.each(this.visibleFiles(), function(item) {
453 item.set('checked', checked);
457 updateSelectAll: function() {
458 if (this.visibleFiles().length) {
459 this.$selectAll.prop('disabled', false);
460 this.$selectAll.prop('checked', this.selectedFiles().length == this.visibleFiles().length);
463 this.$selectAll.prop('disabled', true);
464 this.$selectAll.prop('checked', false);
468 clearSelection: function() {
469 _.each(this.visibleFiles(), function(item) {
470 item.set('checked', false);
474 toggleFavorites: function() {
475 var $btn = this.$favorites,
476 locations = this.hostSelectize,
477 is_active = $btn.hasClass('active'),
478 url = is_active ? '/filex/fav/delete/' : '/filex/fav/add/',
481 path: this.path.full()
484 $btn.button('loading');
486 $.post(url, data, 'json').done(function (response) {
487 $btn.button('reset');
490 locations.removeOption(data.host + '/' + data.path);
492 locations.addOption(response);
494 $btn.button('reset');
495 $btn.button('toggle');
497 console.error(arguments);
501 initialLoad: function() {
503 var opts = this.hostSelectize.options;
505 this.load(opts[Object.keys(opts)[0]].value);
509 changedPath: function () {
511 this.updateFavorites();
514 updateFavorites: function() {
515 var loc = this.host + '/' + this.path.full(),
516 favorites = this.hostSelectize.options;
518 if (favorites.hasOwnProperty(loc)) {
519 if (favorites[loc].group == 'sys') {
520 this.$favorites.addClass('disabled').prop('disabled', true);
521 if (this.$favorites.hasClass('active'))
522 this.$favorites.button('toggle');
525 this.$favorites.removeClass('disabled').prop('disabled', false);
526 if (!this.$favorites.hasClass('active'))
527 this.$favorites.button('toggle');
531 this.$favorites.removeClass('disabled').prop('disabled', false);
532 if (this.$favorites.hasClass('active'))
533 this.$favorites.button('toggle');
537 editHost: function() {
538 $('#host').addClass('edit');
539 this.hostSelectize.focus();