PageRenderTime 14ms CodeModel.GetById 5ms app.highlight 94ms RepoModel.GetById 1ms app.codeStats 1ms

/django_bfm/static/django_bfm/application.js

http://github.com/simukis/django-bfm
JavaScript | 1011 lines | 989 code | 22 blank | 0 comment | 75 complexity | 8c43256497c515dc13fde3cfabab715b MD5 | raw file
   1(function() {
   2  var ContextMenu, Dialog, DirectoriesView, Directory, DirectoryBrowser, DirectoryCollection, DirectoryView, File, FileBrowser, FileCollection, FilePaginatorView, FileTableView, FileUploadView, FileUploader, FileView, RootDirectoryView, UploaderView, Urls, directory_upload_support, readable_size,
   3    __indexOf = Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
   4    _this = this;
   5
   6  File = Backbone.Model.extend({
   7    url: 'file/',
   8    initialize: function() {
   9      this.set({
  10        'date': new Date(this.get('date'))
  11      });
  12      return this.set({
  13        'pdate': this.parseDate(),
  14        'psize': this.parseSize()
  15      });
  16    },
  17    parseDate: function() {
  18      var d;
  19      d = this.get("date");
  20      return "" + (d.getFullYear()) + "-" + (d.getMonth() + 1) + "-" + (d.getDate());
  21    },
  22    parseSize: function() {
  23      return readable_size(this.get('size'));
  24    },
  25    delete_file: function() {
  26      var _this = this;
  27      return $.ajax({
  28        'url': this.url,
  29        'data': {
  30          action: 'delete',
  31          file: this.get('filename'),
  32          directory: this.get('rel_dir')
  33        },
  34        'success': function() {
  35          return FileBrowser.files.remove(_this);
  36        }
  37      });
  38    },
  39    rename_file: function() {
  40      var dialog,
  41        _this = this;
  42      dialog = new Dialog({
  43        'url': this.url,
  44        'model': this,
  45        'template': '#file_rename_tpl',
  46        'callback': function(data) {
  47          return _this.rename_file_callback(data);
  48        }
  49      });
  50      return dialog.render();
  51    },
  52    rename_file_callback: function(dialog_data) {
  53      var _this = this;
  54      return $.ajax({
  55        'url': this.url,
  56        'data': $.extend(dialog_data, {
  57          'action': 'rename'
  58        }),
  59        'success': function(data) {
  60          _this.set(JSON.parse(data));
  61          _this.initialize();
  62          return FileBrowser.files.sort();
  63        }
  64      });
  65    },
  66    touch_file: function() {
  67      var _this = this;
  68      return $.ajax({
  69        'url': this.url,
  70        'data': {
  71          action: 'touch',
  72          file: this.get('filename'),
  73          directory: this.get('rel_dir')
  74        },
  75        'success': function(data) {
  76          _this.set(JSON.parse(data));
  77          _this.initialize();
  78          return FileBrowser.files.sort();
  79        }
  80      });
  81    },
  82    resize_image: function() {
  83      var dialog;
  84      dialog = new Dialog({
  85        'url': 'image/',
  86        'model': this,
  87        'template': '#image_resize_tpl',
  88        'callback': function(dialog_data) {
  89          var _this = this;
  90          return $.ajax({
  91            url: 'image/',
  92            data: $.extend(dialog_data, {
  93              action: 'resize'
  94            }),
  95            success: function(data) {
  96              FileBrowser.files.add(JSON.parse(data));
  97              return FileBrowser.files.sort();
  98            }
  99          });
 100        },
 101        'hook': function(dialog) {
 102          $.ajax({
 103            'url': 'image/',
 104            'dataType': 'json',
 105            'data': {
 106              'action': 'info',
 107              'file': dialog.model.get('filename'),
 108              'directory': dialog.model.get('rel_dir')
 109            },
 110            'success': function(data) {
 111              $(dialog.el).find('input[name="new_h"]').val(data.height);
 112              $(dialog.el).find('input[name="new_w"]').val(data.width);
 113              return $(dialog.el).data('ratio', data.height / data.width);
 114            }
 115          });
 116          $(dialog.el).find('input[name="new_h"]').keyup(function() {
 117            var h, ratio;
 118            if ($(dialog.el).find('input[name="keepratio"]').is(':checked')) {
 119              ratio = $(dialog.el).data('ratio');
 120              h = $(dialog.el).find('input[name="new_h"]').val();
 121              return $(dialog.el).find('input[name="new_w"]').val(~~(h / ratio + 0.5));
 122            }
 123          });
 124          return $(dialog.el).find('input[name="new_w"]').keyup(function() {
 125            var ratio, w;
 126            if ($(dialog.el).find('input[name="keepratio"]').is(':checked')) {
 127              ratio = $(dialog.el).data('ratio');
 128              w = $(dialog.el).find('input[name="new_w"]').val();
 129              return $(dialog.el).find('input[name="new_h"]').val(~~(w * ratio + 0.5));
 130            }
 131          });
 132        }
 133      });
 134      return dialog.render();
 135    }
 136  });
 137
 138  FileCollection = Backbone.Collection.extend({
 139    url: 'list_files/',
 140    model: File,
 141    comparators: {
 142      date: function(model) {
 143        return model.get('date') - 0;
 144      },
 145      size: function(model) {
 146        return model.get('size');
 147      },
 148      filename: function(model) {
 149        return model.get("filename");
 150      },
 151      mime: function(model) {
 152        return model.get('mimetype');
 153      }
 154    },
 155    sort: function(options) {
 156      options || (options = {});
 157      if (!this.comparator) {
 158        throw new Error('Cannot sort a set without a comparator');
 159      }
 160      this.models = this.sortBy(this.comparator);
 161      if (options.reverse) this.models.reverse();
 162      if (!options.silent) this.trigger('reset', this, options);
 163      return this;
 164    },
 165    initialize: function() {
 166      this.base_url = this.url;
 167      this.comparator = this.comparators.date;
 168      this.bind('reset', this.updated);
 169      return this.bind('remove', this.updated);
 170    },
 171    update_directory: function() {
 172      return this.url = "" + this.base_url + "?directory=" + FileBrowser.path;
 173    },
 174    updated: function() {
 175      return FileBrowser.paginator.render();
 176    }
 177  });
 178
 179  FileTableView = Backbone.View.extend({
 180    events: {
 181      'click th': 'resort_data'
 182    },
 183    sorted: {
 184      'by': 'date',
 185      'reversed': true
 186    },
 187    initialize: function() {
 188      this.el = $('table#result_list');
 189      return this.delegateEvents(this.events);
 190    },
 191    resort_data: function(e) {
 192      var files, name;
 193      files = FileBrowser.files;
 194      name = e.currentTarget.getAttribute('data-name');
 195      if (!files.comparators[name]) return false;
 196      if (this.sorted.by === name) {
 197        this.sorted.reversed = !this.sorted.reversed;
 198      } else {
 199        this.sorted.by = name;
 200      }
 201      files.comparator = files.comparators[name];
 202      return files.sort({
 203        'reverse': this.sorted.reversed
 204      });
 205    },
 206    render: function(models) {
 207      var c, cls_name, tpl,
 208        _this = this;
 209      this.current_row = 1;
 210      this.el.html('');
 211      this.el.append($('<thead/>').append($('<tr/>')));
 212      c = {
 213        filename: '',
 214        size: '',
 215        date: '',
 216        mime: ''
 217      };
 218      cls_name = this.sorted.reversed ? 'descending' : 'ascending';
 219      c[this.sorted.by] = "" + cls_name + " sorted";
 220      tpl = _.template($('#browse_head_tpl').html(), c);
 221      this.el.find('tr:first').append(tpl);
 222      _.forEach(models, function(model) {
 223        var file;
 224        file = new FileView({
 225          'model': model
 226        });
 227        return _this.el.append(file.srender());
 228      });
 229      return this.delegateEvents(this.events);
 230    },
 231    new_row_class: function() {
 232      this.current_row = (this.current_row + 1) % 2;
 233      return "row" + (this.current_row + 1);
 234    }
 235  });
 236
 237  FileView = Backbone.View.extend({
 238    tagName: 'tr',
 239    events: {
 240      "click .delete": 'delete',
 241      "click .touch": 'touch',
 242      "click .rename": 'rename',
 243      "click .resize": 'resize'
 244    },
 245    initialize: function(attrs) {
 246      this.table = FileBrowser.table;
 247      this.attrs = attrs.model.attributes;
 248      return this.model = attrs.model;
 249    },
 250    srender: function() {
 251      var elm, resizable_mimetypes, tpl, _ref;
 252      tpl = _.template($('#browse_file_tpl').html(), this.attrs);
 253      elm = $(this.el).html(tpl);
 254      elm.addClass(this.table.new_row_class());
 255      resizable_mimetypes = ['image/png', 'image/jpeg', 'image/bmp', 'image/gif'];
 256      if (!(_ref = this.attrs.mimetype, __indexOf.call(resizable_mimetypes, _ref) >= 0) || !BFMOptions.pil) {
 257        elm.find('.icons .resize').css('display', 'none');
 258      }
 259      return elm;
 260    },
 261    "delete": function(e) {
 262      return this.model.delete_file();
 263    },
 264    touch: function(e) {
 265      return this.model.touch_file();
 266    },
 267    rename: function(e) {
 268      return this.model.rename_file();
 269    },
 270    resize: function(e) {
 271      return this.model.resize_image();
 272    }
 273  });
 274
 275  FilePaginatorView = Backbone.View.extend({
 276    events: {
 277      'click a': 'page_click',
 278      'click .firstpage': 'first_page',
 279      'click .lastpage': 'last_page'
 280    },
 281    initialize: function() {
 282      this.el = $('p.paginator');
 283      return this.last_page_count = -1;
 284    },
 285    get_page_models: function() {
 286      var files, page, per_page, start;
 287      per_page = BFMOptions.files_in_page;
 288      page = FileBrowser.page;
 289      files = FileBrowser.files;
 290      start = per_page * (page - 1);
 291      return files.models.slice(start, (start + per_page));
 292    },
 293    count_pages: function() {
 294      return ~~(FileBrowser.files.models.length / BFMOptions.files_in_page + 0.99);
 295    },
 296    render: function() {
 297      var page, pages, rn, _ref, _ref2;
 298      FileBrowser.table.render(this.get_page_models());
 299      pages = this.count_pages();
 300      this.el.empty();
 301      if (pages > 5 && FileBrowser.page > 6) {
 302        this.el.append(_.template($('#pgn_first_page_tpl').html())());
 303      }
 304      for (page = _ref = FileBrowser.page - 5, _ref2 = FileBrowser.page + 5; _ref <= _ref2 ? page <= _ref2 : page >= _ref2; _ref <= _ref2 ? page++ : page--) {
 305        if (page < 1 || page > pages) continue;
 306        if (page === FileBrowser.page) {
 307          rn = _.template($('#pgn_current_page_tpl').html(), {
 308            page: page
 309          });
 310        } else {
 311          rn = _.template($('#pgn_page_tpl').html(), {
 312            page: page
 313          });
 314        }
 315        this.el.append(rn);
 316      }
 317      if (pages > 5 && FileBrowser.page < pages - 5) {
 318        this.el.append(_.template($('#pgn_last_page_tpl').html())());
 319      }
 320      return this.delegateEvents(this.events);
 321    },
 322    page_click: function(e) {
 323      var page;
 324      page = parseInt($(e.currentTarget).text());
 325      if (!isNaN(page)) FileBrowser.open_page(page);
 326      return e.preventDefault();
 327    },
 328    first_page: function(e) {
 329      e.preventDefault();
 330      return FileBrowser.open_page(1);
 331    },
 332    last_page: function(e) {
 333      e.preventDefault();
 334      return FileBrowser.open_page(this.count_pages());
 335    }
 336  });
 337
 338  FileBrowser = {
 339    first: true,
 340    path: null,
 341    page: null,
 342    router: null,
 343    last_xhr: {
 344      readyState: 4
 345    },
 346    do_browse: function(path, page) {
 347      var _ref, _ref2,
 348        _this = this;
 349      if (this.first) {
 350        this.files = new FileCollection();
 351        this.table = new FileTableView();
 352        this.paginator = new FilePaginatorView();
 353        this.first = false;
 354      }
 355      _ref = [path, this.path], this.path = _ref[0], path = _ref[1];
 356      _ref2 = [parseInt(page), this.page], this.page = _ref2[0], page = _ref2[1];
 357      if (this.path !== path) {
 358        this.files.update_directory();
 359        if (this.last_xhr.readyState !== 4) this.last_xhr.abort();
 360        return this.last_xhr = this.files.fetch({
 361          'silent': true,
 362          'success': function(collection) {
 363            return collection.sort({
 364              'reverse': _this.table.sorted.reversed
 365            });
 366          }
 367        });
 368      } else if (this.page !== page) {
 369        return this.paginator.render();
 370      }
 371    },
 372    open_page: function(page) {
 373      return this.router.navigate("path=" + this.path + "^page=" + page, true);
 374    }
 375  };
 376
 377  Directory = Backbone.Model.extend({
 378    url: 'directory/',
 379    initialize: function() {
 380      this.id = this.get('rel_dir');
 381      return this.is_child = this.get('rel_dir').indexOf('/') === -1 ? false : true;
 382    },
 383    new_folder: function(data) {
 384      var additional_data;
 385      additional_data = {
 386        'action': 'new',
 387        'directory': this.get('rel_dir')
 388      };
 389      return $.ajax({
 390        'url': this.url,
 391        'data': $.extend(data, additional_data),
 392        'success': function() {
 393          return DirectoryBrowser.directories.fetch();
 394        }
 395      });
 396    },
 397    rename: function(data) {
 398      var additional_data;
 399      additional_data = {
 400        'action': 'rename',
 401        'directory': this.get('rel_dir')
 402      };
 403      return $.ajax({
 404        'url': this.url,
 405        'data': $.extend(data, additional_data),
 406        'success': function() {
 407          return DirectoryBrowser.directories.fetch();
 408        }
 409      });
 410    },
 411    "delete": function(data) {
 412      return $.ajax({
 413        url: this.url,
 414        data: {
 415          'action': 'delete',
 416          'directory': this.get('rel_dir')
 417        },
 418        success: function() {
 419          return DirectoryBrowser.directories.fetch();
 420        }
 421      });
 422    }
 423  });
 424
 425  DirectoryCollection = Backbone.Collection.extend({
 426    url: 'list_directories/',
 427    model: Directory,
 428    initialize: function(attrs) {
 429      this.bind('reset', this.added);
 430      return this.root = new Directory({
 431        name: '',
 432        rel_dir: ''
 433      });
 434    },
 435    added: function() {
 436      var _this = this;
 437      DirectoryBrowser.sidebar.clear();
 438      _.forEach(this.models, function(model) {
 439        if (!model.is_child) {
 440          return DirectoryBrowser.sidebar.append_directory(model);
 441        }
 442      });
 443      return DirectoryBrowser.sidebar.set_active(DirectoryBrowser.path);
 444    }
 445  });
 446
 447  DirectoriesView = Backbone.View.extend({
 448    dirs: {},
 449    active_dir: null,
 450    initialize: function() {
 451      this.el = $('.directory-list');
 452      return new RootDirectoryView();
 453    },
 454    append_directory: function(model) {
 455      var view,
 456        _this = this;
 457      view = new DirectoryView({
 458        'model': model
 459      });
 460      this.dirs[model.id] = view;
 461      this.el.append(view.srender());
 462      return _.forEach(model.get('children'), function(child) {
 463        return _this.append_children(child, view);
 464      });
 465    },
 466    append_children: function(id, parent_view) {
 467      var model, view,
 468        _this = this;
 469      model = DirectoryBrowser.directories.get(id);
 470      view = new DirectoryView({
 471        'model': model
 472      });
 473      this.dirs[model.id] = view;
 474      parent_view.append_child(view.srender());
 475      return _.forEach(model.get('children'), function(child) {
 476        return _this.append_children(child, view);
 477      });
 478    },
 479    set_active: function(path) {
 480      if (path) {
 481        if (this.active_dir) this.active_dir.deactivate();
 482        this.active_dir = this.dirs[path];
 483        return this.active_dir.activate();
 484      } else if (this.active_dir) {
 485        return this.active_dir.deactivate();
 486      }
 487    },
 488    clear: function() {
 489      var active_dir, dirs;
 490      dirs = {};
 491      active_dir = null;
 492      return this.el.children().remove();
 493    }
 494  });
 495
 496  DirectoryView = Backbone.View.extend({
 497    tagName: 'li',
 498    events: {
 499      "click .directory": "load_directory",
 500      "contextmenu .directory": "actions_menu"
 501    },
 502    children_el: false,
 503    context_template: '#directory_actions_tpl',
 504    initialize: function(attrs) {
 505      var _this = this;
 506      this.model = attrs.model;
 507      this.el = $(this.el);
 508      return this.context_callbacks = [
 509        (function() {
 510          return _this.new_folder();
 511        }), (function() {
 512          return _this.rename();
 513        }), (function() {
 514          return _this["delete"]();
 515        })
 516      ];
 517    },
 518    load_directory: function(e) {
 519      e.stopImmediatePropagation();
 520      e.preventDefault();
 521      return DirectoryBrowser.open_path(this.model.get('rel_dir'), true);
 522    },
 523    srender: function() {
 524      return this.el.html("<a class='directory'>" + (this.model.get('name')) + "</a>");
 525    },
 526    activate: function() {
 527      return this.el.children('a').addClass('selected');
 528    },
 529    deactivate: function() {
 530      return this.el.children('a').removeClass('selected');
 531    },
 532    append_child: function(child) {
 533      if (!this.children_el) {
 534        this.children_el = $('<ul />');
 535        this.el.append(this.children_el);
 536      }
 537      return this.children_el.append(child);
 538    },
 539    actions_menu: function(e) {
 540      var entries, menu;
 541      e.stopImmediatePropagation();
 542      e.preventDefault();
 543      entries = $(_.template($(this.context_template).html())());
 544      menu = new ContextMenu();
 545      menu.add_entries(entries, this.context_callbacks);
 546      return menu.render(e);
 547    },
 548    new_folder: function() {
 549      var dialog,
 550        _this = this;
 551      dialog = new Dialog({
 552        'model': this.model,
 553        'template': '#new_directory_tpl',
 554        'callback': function(data) {
 555          return _this.model.new_folder(data);
 556        }
 557      });
 558      return dialog.render();
 559    },
 560    rename: function() {
 561      var dialog,
 562        _this = this;
 563      dialog = new Dialog({
 564        'model': this.model,
 565        'template': '#rename_directory_tpl',
 566        'callback': function(data) {
 567          return _this.model.rename(data);
 568        }
 569      });
 570      return dialog.render();
 571    },
 572    "delete": function() {
 573      var dialog,
 574        _this = this;
 575      dialog = new Dialog({
 576        'model': this.model,
 577        'template': '#delete_directory_tpl',
 578        'callback': function(data) {
 579          return _this.model["delete"](data);
 580        }
 581      });
 582      return dialog.render();
 583    }
 584  });
 585
 586  RootDirectoryView = DirectoryView.extend({
 587    events: {
 588      "click a": "load_directory",
 589      "contextmenu a": "actions_menu"
 590    },
 591    context_template: '#rootdirectory_actions_tpl',
 592    initialize: function() {
 593      var _this = this;
 594      this.el = $('#changelist-filter>h2').first();
 595      this.model = DirectoryBrowser.directories.root;
 596      this.context_callbacks = [
 597        (function() {
 598          return _this.new_folder();
 599        })
 600      ];
 601      return this.delegateEvents();
 602    }
 603  });
 604
 605  DirectoryBrowser = {
 606    first: true,
 607    router: null,
 608    do_browse: function(path) {
 609      this.path = path;
 610      if (this.first) {
 611        this.directories = new DirectoryCollection();
 612        this.sidebar = new DirectoriesView();
 613        this.directories.fetch();
 614        return this.first = false;
 615      } else {
 616        return this.sidebar.set_active(path);
 617      }
 618    },
 619    open_path: function(path) {
 620      return this.router.navigate("path=" + path + "^page=1", true);
 621    }
 622  };
 623
 624  FileUploadView = Backbone.View.extend({
 625    events: {
 626      'click .abort': 'abort'
 627    },
 628    initialize: function(file) {
 629      this.file = file;
 630      return this.directory = FileUploader.path;
 631    },
 632    srender: function() {
 633      var filename;
 634      filename = this.file.name != null ? this.file.name : this.file.fileName;
 635      this.el = $(_.template($('#file_upload_tpl').html(), {
 636        filename: filename
 637      }));
 638      this.status = this.el.find('.status');
 639      this.indicators = {
 640        'percent': this.el.find('.indicators .percent'),
 641        'speed': this.el.find('.indicators .speed')
 642      };
 643      this.delegateEvents(this.events);
 644      return this.el;
 645    },
 646    do_upload: function() {
 647      var csrf_token, directory, url,
 648        _this = this;
 649      if (this.aborted != null) return false;
 650      csrf_token = $('input[name=csrfmiddlewaretoken]').val();
 651      url = "upfile/?directory=" + this.directory;
 652      if (typeof BFMAdminOptions !== "undefined" && BFMAdminOptions !== null) {
 653        directory = BFMAdminOptions.upload_rel_dir;
 654        url = "" + BFMAdminOptions.upload + "?directory=" + directory;
 655      }
 656      this.xhr = $.ajax_upload(this.file, {
 657        'url': url,
 658        'headers': {
 659          "X-CSRFToken": csrf_token
 660        },
 661        'progress': function(e, stats) {
 662          return _this.report_progress(e, stats);
 663        },
 664        'complete': function(e, data) {
 665          return _this.upload_complete(e, data);
 666        },
 667        'error': function(e) {
 668          return _this.upload_error(e);
 669        },
 670        'abort': function(e) {
 671          return _this.upload_abort(e);
 672        }
 673      });
 674      this.el.addClass('current');
 675      return true;
 676    },
 677    report_progress: function(e, stats) {
 678      this.update_status_bar(stats.completion, stats.last_call);
 679      this.indicators.percent.text(~~(stats.completion * 1000 + 0.5) / 10);
 680      return this.indicators.speed.text("" + (readable_size(stats.speed)) + "/s");
 681    },
 682    upload_complete: function(e, data) {
 683      var link,
 684        _this = this;
 685      this.el.removeClass('current');
 686      this.el.find('.abort').hide();
 687      link = $('<a />', {
 688        'class': 'filename',
 689        'href': data.url
 690      });
 691      link.text(data.filename);
 692      this.el.find('.filename').replaceWith(link);
 693      this.update_status_bar(1, 100);
 694      if (!(typeof BFMAdminOptions !== "undefined" && BFMAdminOptions !== null) && this.directory === FileBrowser.path) {
 695        _.defer(function() {
 696          FileBrowser.files.add(data);
 697          return FileBrowser.files.sort();
 698        });
 699      }
 700      return FileUploader.uploader.report_finished(this);
 701    },
 702    upload_abort: function(e) {
 703      this.el.removeClass('current');
 704      this.status.css('background', '#FF9F00');
 705      this.el.find('.indicators').hide();
 706      this.el.find('.aborted').show();
 707      this.el.find('.abort').hide();
 708      return FileUploader.uploader.report_finished(this);
 709    },
 710    upload_error: function(e) {
 711      this.el.removeClass('current');
 712      this.status.css('background', '#DD4032');
 713      this.el.find('.indicators').hide();
 714      this.el.find('.failed').show();
 715      this.el.find('.abort').hide();
 716      return FileUploader.uploader.report_finished(this);
 717    },
 718    abort: function(e) {
 719      if (this.xhr != null) {
 720        return this.xhr.abort();
 721      } else {
 722        this.aborted = true;
 723        this.el.find('.abort').hide();
 724        this.el.find('.indicators').hide();
 725        this.el.find('.aborted').show();
 726        return FileUploader.uploader.finished_uploads.push(this);
 727      }
 728    },
 729    update_status_bar: function(percent, duration) {
 730      var animation_options, css;
 731      css = {
 732        'width': "" + (percent * 100) + "%"
 733      };
 734      animation_options = {
 735        'duration': duration,
 736        'easing': 'linear'
 737      };
 738      return this.status.stop(true).animate(css, animation_options);
 739    }
 740  });
 741
 742  UploaderView = Backbone.View.extend({
 743    to_upload: [],
 744    started_uploads: [],
 745    finished_uploads: [],
 746    visible: false,
 747    uploads_at_once: window.BFMOptions.uploads_at_once,
 748    active_uploads: 0,
 749    events: {
 750      'click .uploader-head>.control': 'toggle_visibility',
 751      'dblclick .uploader-head': 'toggle_visibility',
 752      'change input[type="file"]': 'add_files',
 753      'click .finished': 'clear_finished',
 754      'click .rqueued': 'remove_queue'
 755    },
 756    initialize: function() {
 757      return this.el = $('<div />', {
 758        'class': 'uploader'
 759      });
 760    },
 761    render: function() {
 762      this.el.append(_.template($('#uploader_tpl').html()));
 763      this.el.appendTo($('body'));
 764      this.height = this.el.height();
 765      this.width = this.el.width();
 766      if (directory_upload_support()) {
 767        this.el.find('.selector.directory').css('display', 'inline-block');
 768      }
 769      return this.delegateEvents(this.events);
 770    },
 771    toggle_visibility: function(e) {
 772      var button, css, options;
 773      button = this.el.find('.uploader-head>.control');
 774      button.toggleClass('fullscreen exit-fullscreen');
 775      button.attr = {
 776        'title': button.attr('data-alttitle'),
 777        'data-alttitle': button.attr('title')
 778      };
 779      options = {
 780        'duration': 400,
 781        'queue': false
 782      };
 783      css = {
 784        'width': !this.visible ? '50%' : "" + this.width,
 785        'height': !this.visible ? '50%' : "" + this.height + "px"
 786      };
 787      this.el.animate(css, options);
 788      this.el.children(':not(.uploader-head)').show();
 789      return this.visible = !this.visible;
 790    },
 791    add_files: function(e) {
 792      var _this = this;
 793      return _.forEach(e.currentTarget.files, function(file) {
 794        return _.defer(function() {
 795          return _this.add_file(file);
 796        });
 797      });
 798    },
 799    add_file: function(file) {
 800      var view,
 801        _this = this;
 802      if ((file.name != null ? file.name : file.fileName) === ".") return;
 803      view = new FileUploadView(file);
 804      this.to_upload.unshift(view);
 805      this.el.find('.uploader-table').append(view.srender());
 806      return _.defer(function() {
 807        return _this.upload_next();
 808      });
 809    },
 810    upload_next: function() {
 811      var i, started, upl, _ref;
 812      for (i = 0, _ref = this.uploads_at_once - this.active_uploads; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) {
 813        while (this.to_upload.length > 0 && !started) {
 814          upl = this.to_upload.pop();
 815          started = upl.do_upload();
 816          if (started) {
 817            this.started_uploads.push(upl);
 818            this.active_uploads += 1;
 819          }
 820        }
 821      }
 822      if (window.onbeforeunload !== this.unloading && this.active_uploads > 0) {
 823        return window.onbeforeunload = this.unloading;
 824      } else {
 825        return window.onbeforeunload = null;
 826      }
 827    },
 828    report_finished: function(who) {
 829      var _this = this;
 830      this.finished_uploads.push(who);
 831      this.active_uploads -= 1;
 832      return _.defer(function() {
 833        return _this.upload_next();
 834      });
 835    },
 836    clear_finished: function(e) {
 837      var i, _ref, _results,
 838        _this = this;
 839      e.preventDefault();
 840      _results = [];
 841      for (i = 0, _ref = this.finished_uploads.length; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) {
 842        _results.push(_.defer(function() {
 843          return _this.finished_uploads.pop().remove();
 844        }));
 845      }
 846      return _results;
 847    },
 848    remove_queue: function(e) {
 849      var i, _ref, _results;
 850      e.preventDefault();
 851      _results = [];
 852      for (i = 0, _ref = this.to_upload.length; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) {
 853        _results.push(this.to_upload.pop().remove());
 854      }
 855      return _results;
 856    },
 857    unloading: function() {
 858      return $.trim($('#upload_cancel_tpl').text());
 859    }
 860  });
 861
 862  FileUploader = {
 863    init: function() {
 864      this.uploader = new UploaderView();
 865      return this.uploader.render();
 866    },
 867    do_browse: function(path) {
 868      return this.path = path;
 869    }
 870  };
 871
 872  readable_size = function(size) {
 873    var s, table, _i, _len;
 874    table = [['B', 1024, 0], ['KB', 1048576, 0], ['MB', 1073741824, 1], ['GB', 1099511627776, 2], ['TB', 1125899906842624, 3]];
 875    for (_i = 0, _len = table.length; _i < _len; _i++) {
 876      s = table[_i];
 877      if (size < s[1]) {
 878        return "" + ((size / (s[1] / 1024)).toFixed(s[2])) + " " + s[0];
 879      }
 880    }
 881  };
 882
 883  directory_upload_support = function() {
 884    var input;
 885    input = document.createElement('input');
 886    input.type = "file";
 887    if ((input.directory != null) || (input.webkitdirectory != null) || (input.mozdirectory != null)) {
 888      return true;
 889    }
 890    return false;
 891  };
 892
 893  Dialog = Backbone.View.extend({
 894    tagName: 'form',
 895    className: 'dialog',
 896    events: {
 897      "click .submit": 'call_callback',
 898      "click .cancel": 'cancel'
 899    },
 900    tear_down: function() {
 901      var _this = this;
 902      $(this.el).fadeOut(200, function() {
 903        return _this.remove();
 904      });
 905      return $('.block').fadeOut(200);
 906    },
 907    cancel: function(e) {
 908      this.tear_down();
 909      return e.preventDefault();
 910    },
 911    call_callback: function(e) {
 912      var field, key, object, _ref;
 913      this.tear_down();
 914      e.preventDefault();
 915      object = {};
 916      _ref = $(this.el).serializeArray();
 917      for (key in _ref) {
 918        field = _ref[key];
 919        object[field.name] = field.value;
 920      }
 921      return this.callback(object);
 922    },
 923    initialize: function(attrs) {
 924      this.url = attrs.url;
 925      this.model = attrs.model;
 926      this.template = attrs.template;
 927      this.callback = attrs.callback;
 928      return this.hook = attrs.hook;
 929    },
 930    render: function() {
 931      var element, tpl;
 932      tpl = _.template($(this.template).html(), this.model.attributes);
 933      element = $(this.el).html(tpl);
 934      $('body').append(element.fadeIn(200));
 935      $('.block').fadeIn(300);
 936      if (this.hook != null) return this.hook(this);
 937    }
 938  });
 939
 940  ContextMenu = Backbone.View.extend({
 941    tagName: 'ul',
 942    className: 'contextmenu',
 943    initialize: function() {
 944      return this.el = $(this.el);
 945    },
 946    clicked: function(callback) {
 947      var _this = this;
 948      this.el.hide(200, function() {
 949        return _this.remove();
 950      });
 951      if (callback != null) return callback();
 952    },
 953    add_entry: function(entry, callback) {
 954      var _this = this;
 955      this.el.append(entry);
 956      return $(entry).click(function() {
 957        return _this.clicked(callback);
 958      });
 959    },
 960    add_entries: function(entries, callbacks) {
 961      var _this = this;
 962      entries = entries.filter('li');
 963      return _.each(entries, function(entry, key) {
 964        return _this.add_entry(entry, callbacks[key]);
 965      });
 966    },
 967    render: function(e) {
 968      var left, top, width,
 969        _this = this;
 970      width = this.el.appendTo($('body')).outerWidth();
 971      this.el.hide().show(200);
 972      top = e.pageY;
 973      left = e.pageX;
 974      if (left + width >= $(document).width()) left = $(document).width() - width;
 975      this.el.css({
 976        top: top,
 977        left: left
 978      });
 979      return $(document).one('mousedown', function() {
 980        return _this.clicked();
 981      });
 982    }
 983  });
 984
 985  Urls = Backbone.Router.extend({
 986    routes: {
 987      'path=*path^page=:page': 'do_pass',
 988      '': 'do_navigate'
 989    },
 990    initialize: function() {
 991      return FileBrowser.router = DirectoryBrowser.router = this;
 992    },
 993    do_pass: function(path, page) {
 994      FileBrowser.do_browse(path, page);
 995      DirectoryBrowser.do_browse(path);
 996      FileUploader.do_browse(path);
 997    },
 998    do_navigate: function(path) {
 999      return this.navigate("path=^page=1", true);
1000    }
1001  });
1002
1003  $(function() {
1004    new Urls();
1005    FileUploader.init();
1006    return Backbone.history.start({
1007      root: BFMRoot
1008    });
1009  });
1010
1011}).call(this);