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.log('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', this.setActive);
99 this.listenTo(this, 'add', this.setActive);
102 setActive: function() {
103 _.each(this.initial(), function(bit) {
104 bit.set('active', false);
107 this.last().set('active', true);
111 return this.pluck('path').join('/') || '/';
116 // ------------------------------------------------------------------------
118 // ------------------------------------------------------------------------
120 Filex.ListingItem = Backbone.View.extend({
124 'click .link': 'selected',
125 'click input[type=checkbox]': 'toggle'
128 initialize: function(options) {
129 this.view = options.view;
131 this.listenTo(this.model, 'change', this.render);
132 this.listenTo(this.model, 'remove', this.remove);
133 this.listenTo(this.model, 'hidden', this.toggleHidden);
136 template: function() {
137 var templateSelector = this.model.isDir() ? '#dir-template' : '#file-template';
139 return _.template($(templateSelector).html());
143 var data = this.model.toJSON();
144 data['url_params'] = $.param({
145 host: this.view.host,
146 path: this.view.path.full(),
147 name: this.model.get('name')
149 data['cid'] = this.model.cid;
151 this.$el.html(this.template()(data));
157 toggleHidden: function() {
158 this.$el.toggleClass('hidden', this.model.isHidden() && !this.view.showHidden());
161 selected: function(e) {
163 if (this.model.isDir()) {
164 this.model.trigger('selected:dir', this.model);
167 this.model.trigger('selected:file', this.model);
177 Filex.Breadcrumb = Backbone.View.extend({
181 'click a': 'selected'
184 initialize: function() {
185 this.listenTo(this.model, 'change:active', this.render);
186 this.listenTo(this.model, 'remove', this.remove);
190 if (this.model.get('active')) {
191 this.$el.text(this.model.get('text'));
194 this.$el.html($('<a/>', {
196 text: this.model.get('text')
199 this.$el.toggleClass('active', this.model.get('active'));
204 selected: function(e) {
206 this.model.trigger('selected', this.model);
210 Filex.FilexView = Backbone.View.extend({
214 'change #show-hidden': 'toggleHidden',
215 'click #host-controls .view': 'hostEdit',
216 'click #select-all': 'selectAll'
219 initialize: function(options) {
220 this.$noItems = $('#no-items');
221 this.$error = $('#error');
222 this.$showHidden = $('#show-hidden');
223 this.$host = $('#host-controls');
224 this.$selectAll = $('#select-all');
226 this.host = options.host;
227 this.path = new Filex.Path();
228 this.files = new Filex.FileList();
230 this.listenTo(this.path, 'reset', this.resetPath);
231 this.listenTo(this.path, 'add', this.reloadFiles);
232 this.listenTo(this.path, 'add', this.addPath);
233 this.listenTo(this.path, 'selected', this.selectedPath);
234 this.listenTo(this.files, 'reset', this.resetFiles);
235 this.listenTo(this.files, 'selected:dir', this.selectedDir);
236 this.listenTo(this.files, 'selected:file', this.selectedFile);
237 this.listenTo(this.files, 'change:checked', this.updateSelectAll);
239 // used in selectize callbacks
241 optionTemplate = _.template('<div><div><%= host %></div><div class="small text-muted"><%= path %></div></div>');
243 this.$('#host-selector').selectize({
246 searchField: ['host', 'path'],
248 {field: 'host', direction: 'asc'},
249 {field: 'path', direction: 'asc'}
252 options: options.hostOptions,
254 option: function(item) {
255 return optionTemplate(item);
258 onDropdownClose: function() {
262 view.$host.toggleClass('editing');
264 var value = this.getValue();
266 this.addItem(view.host, true);
270 if (value != view.host) {
271 var location = this.options[value];
273 view.host = location.host;
274 view.navigate(location.path);
278 this.hostSelectize = this.$('#host-selector')[0].selectize;
281 this.navigate(this.hostSelectize.options[this.host].path);
285 this.updateSelectAll();
286 this.$host.find('.view').text(this.host);
287 this.$noItems.toggle(!Boolean(this.visibleFiles().length));
291 navigate: function(path) {
292 var pathBits = [new Filex.PathBit({'text': '/', 'path': ''})];
294 pathBits = pathBits.concat(_.map(path.replace(/(^\/+|\/+$)/g, '').split('/'), function(name) {
295 return new Filex.PathBit({'text': name, 'path': name});
298 this.path.reset(pathBits);
301 reloadFiles: function() {
308 data: {host: this.host, path: this.path.full()},
309 success: function() {
313 error: function(collection, response) {
316 var msg = (response.responseJSON || {}).msg || 'Błąd serwera';
318 view.$noItems.hide();
319 view.$error.find('.msg').text(msg);
326 addPath: function(bit) {
327 var view = new Filex.Breadcrumb({model: bit});
328 this.$('.path').append(view.render().el);
331 resetPath: function(models, options) {
334 _.each(options.previousModels, function(model) {
335 model.trigger('remove');
338 this.path.each(this.addPath, this);
341 resetFiles: function(models, options) {
342 _.each(options.previousModels, function(model) {
343 model.trigger('remove');
346 this.files.each(function(file) {
347 var view = new Filex.ListingItem({model: file, view: this});
348 this.$('tbody').append(view.render().el);
352 toggleHidden: function() {
353 this.files.each(function(item) { item.trigger('hidden'); }, this);
357 selectedDir: function(dir) {
358 this.path.add({'text': dir.get('name'), 'path': dir.get('name')});
361 selectedFile: function(file) {
362 this.trigger('selected:file', this.host + this.path.full() + '/' + file.get('name'));
365 selectedPath: function(bit) {
366 var newPath = this.path.slice(0, this.path.indexOf(bit) + 1);
367 this.path.set(newPath);
371 showHidden: function() {
372 return this.$showHidden[0].checked;
375 hostEdit: function() {
376 this.$host.toggleClass('editing');
377 this.hostSelectize.focus();
381 this.$el.addClass('busy');
385 this.$el.removeClass('busy');
388 visibleFiles: function() {
389 return this.showHidden() ? this.files.models : this.files.visible();
392 selectedFiles: function() {
393 return _.filter(this.visibleFiles(), function(item) {
394 return item.get('checked');
398 selectAll: function() {
399 var checked = this.$selectAll[0].checked;
401 _.each(this.visibleFiles(), function(item) {
402 item.set('checked', checked);
406 updateSelectAll: function() {
407 this.$selectAll.prop('checked', this.selectedFiles().length == this.visibleFiles().length);
410 clearSelection: function() {
411 _.each(this.visibleFiles(), function(item) {
412 item.set('checked', false);
415 this.updateSelectAll();