PageRenderTime 74ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

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