PageRenderTime 28ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/django_bfm/static/django_bfm/application.coffee

http://github.com/simukis/django-bfm
CoffeeScript | 473 lines | 445 code | 26 blank | 2 comment | 37 complexity | a056c90b78a71309679731413250c80c MD5 | raw file
  1. #TODO: Admin Applet
  2. #TODO: Directory Actions
  3. $ ->
  4. readable_size = (size) ->
  5. table = [['B', 1024, 0],['KB', 1048576, 0],['MB', 1073741824, 1],
  6. ['GB', 1099511627776, 2], ['TB', 1125899906842624, 3]]
  7. for s in table
  8. if size < s[1]
  9. return "#{(size/(s[1]/1024)).toFixed(s[2])} #{s[0]}"
  10. File = Backbone.Model.extend
  11. initialize: () ->
  12. @set
  13. 'date': new Date(@get('date'))
  14. @set
  15. 'pdate': @parseDate()
  16. 'psize': @parseSize()
  17. delete_file: () ->
  18. $.ajax
  19. url: @url
  20. data:
  21. action: 'delete'
  22. file: @get('filename')
  23. directory: @get('rel_dir')
  24. Route.do_reload = true
  25. rename_file: () ->
  26. dialog = new Dialog
  27. url: @url
  28. model: @
  29. template: '#file_rename_tpl'
  30. callback: @rename_file_callback
  31. dialog.render()
  32. rename_file_callback: (dialog_data) ->
  33. $.ajax
  34. url: @url
  35. data: "#{dialog_data}&action=rename"
  36. success: => Route.reload()
  37. touch_file: () ->
  38. $.ajax
  39. url: @url
  40. data:
  41. action: 'touch'
  42. file: @get('filename')
  43. directory: @get('rel_dir')
  44. success: => Route.reload()
  45. url: 'file/'
  46. resize_image: () ->
  47. dialog = new Dialog
  48. url: 'image/'
  49. model: @
  50. template: '#image_resize_tpl'
  51. callback: (dialog_data) ->
  52. $.ajax
  53. url: 'image/'
  54. data: "#{dialog_data}&action=resize"
  55. success: => Route.reload()
  56. hook: (dialog) ->
  57. $.ajax
  58. url: 'image/'
  59. dataType: 'json'
  60. data:
  61. action: 'info'
  62. file: dialog.model.get('filename')
  63. directory: dialog.model.get('rel_dir')
  64. success: (data) ->
  65. $(dialog.el).find('input[name="new_h"]').val(data.height)
  66. $(dialog.el).find('input[name="new_w"]').val(data.width)
  67. $(dialog.el).data 'ratio', data.height/data.width
  68. $(dialog.el).find('input[name="new_h"]').keyup ()->
  69. if $(dialog.el).find('input[name="keepratio"]').is(':checked')
  70. ratio = $(dialog.el).data 'ratio'
  71. h = $(dialog.el).find('input[name="new_h"]').val()
  72. $(dialog.el).find('input[name="new_w"]').val ~~(h/ratio+0.5)
  73. $(dialog.el).find('input[name="new_w"]').keyup ()->
  74. if $(dialog.el).find('input[name="keepratio"]').is(':checked')
  75. ratio = $(dialog.el).data 'ratio'
  76. w = $(dialog.el).find('input[name="new_w"]').val()
  77. $(dialog.el).find('input[name="new_h"]').val ~~(w*ratio+0.5)
  78. dialog.render()
  79. parseDate: () ->
  80. d = @get("date")
  81. "#{d.getFullYear()}-#{d.getMonth()}-#{d.getDate()}"
  82. parseSize: () ->
  83. readable_size(@get('size'))
  84. Files = Backbone.Collection.extend
  85. url: 'list_files/'
  86. initialize: (attrs) ->
  87. @base_url = @url
  88. @bind('reset', @added)
  89. if attrs? and attrs.directory?
  90. @url = @url+'?directory='+attrs.directory
  91. set_directory: (directory) ->
  92. @url = "#{@base_url}?directory=#{directory}"
  93. comparator: (model) ->
  94. date = model.get('date')
  95. dt = date.getFullYear()*10000+date.getMonth()*100+date.getDate()
  96. dh = date.getHours()*100+date.getMinutes()
  97. -(dt+dh*0.0001)
  98. comparators:
  99. date:
  100. desc: (model) ->
  101. 0 - model.get('date')
  102. asc: (model) ->
  103. model.get('date') - 0
  104. size:
  105. desc: (model) ->
  106. -model.get('size')
  107. asc: (model) ->
  108. model.get('size')
  109. filename:
  110. desc: (model) ->
  111. str = model.get("filename")
  112. str = str.toLowerCase().split("")
  113. _.map str, (letter) ->
  114. return String.fromCharCode(-(letter.charCodeAt(0)));
  115. asc: (model) ->
  116. model.get("filename")
  117. mime:
  118. desc: (model) ->
  119. str = model.get("mimetype")
  120. str = str.toLowerCase().split("")
  121. _.map str, (letter) ->
  122. return String.fromCharCode(-(letter.charCodeAt(0)));
  123. asc: (model) ->
  124. model.get('mimetype')
  125. model: File
  126. models_in_page: BFMOptions.files_in_page
  127. get_page: (page)->
  128. page -= 1
  129. start = @models_in_page * page
  130. end = start + @models_in_page
  131. @models[start..end]
  132. page_count: ->
  133. ~~(@length/@models_in_page+1)
  134. added: () ->
  135. page = Route.page
  136. _.forEach(@get_page(page), (model) ->
  137. new FileView('model': model).render())
  138. Paginator.render()
  139. Directories = Backbone.Collection.extend
  140. url: 'list_directories/'
  141. initialize: (attrs) ->
  142. @bind('reset', @added)
  143. added: () ->
  144. _.forEach(@models, (model) ->
  145. new DirectoryView({'model': model.attributes}).render()
  146. )
  147. FileTableView = Backbone.View.extend
  148. el: $ '#result_list'
  149. current_row: 1
  150. ord: ['date', true]
  151. events: {'click th': 'resort_data'}
  152. resort_data: (e) ->
  153. name = e.currentTarget.getAttribute('data-name')
  154. if not Files.comparators[name]
  155. return false
  156. if @ord[0] == name
  157. @ord[1] = not @ord[1]
  158. else
  159. @ord = [name, true]
  160. @clear()
  161. if @ord[1]
  162. Files.comparator = Files.comparators[name].desc
  163. else
  164. Files.comparator = Files.comparators[name].asc
  165. Files.sort()
  166. clear: () ->
  167. @current_row = 1
  168. @el.html ''
  169. @append($('<thead/>').append($('<tr/>')))
  170. @draw_head()
  171. append: (element) ->
  172. @el.append element
  173. prepend: (element) ->
  174. @el.prepend element
  175. draw_head: () ->
  176. c = {filename: '', size: '', date: '', mime: ''}
  177. c[@ord[0]]="#{if @ord[1] then 'descending' else 'ascending'} sorted"
  178. tpl = _.template($('#browse_head_tpl').html(), c)
  179. @el.find('tr:first').append(tpl)
  180. get_row_class: () ->
  181. @current_row = ((@current_row+1)%2)
  182. return "row#{@current_row+1}"
  183. DirectoriesView = Backbone.View.extend
  184. el: $ '.directory-list'
  185. append: (elm) ->
  186. @el.append(elm)
  187. DirectoryView = Backbone.View.extend
  188. tagName: 'li'
  189. events:
  190. "click .directory": "load_directory"
  191. load_directory: (e) ->
  192. e.stopImmediatePropagation()
  193. Route.goto(@model.rel_dir)
  194. @el.children('a').addClass('selected')
  195. initialize: (attrs) ->
  196. @model = attrs.model
  197. @el = $ @el
  198. render: () ->
  199. Dirs.append @srender()
  200. srender: () ->
  201. @el.html "<a class='directory#{if Route.path == @model.rel_dir then " selected" else ""}'>#{@model.name}</a>"
  202. if @model.childs?
  203. child = new ChildDirectoriesView({'childs': @model.childs, 'parent': @})
  204. child.render()
  205. @el
  206. append: (element) ->
  207. @el.append element
  208. ChildDirectoriesView = Backbone.View.extend
  209. tagName: 'ul'
  210. initialize: (attrs) ->
  211. @el = $ @el
  212. @childs = attrs.childs
  213. @parent = attrs.parent
  214. render: () ->
  215. callback = (child) ->
  216. directory = new DirectoryView({'model': child})
  217. @parent.append(@el.append(directory.srender()))
  218. _.forEach(@childs, callback, @)
  219. Dialog = Backbone.View.extend
  220. tagName: 'form'
  221. className: 'dialog'
  222. events:
  223. "click .submit": 'call_callback'
  224. "click .cancel": 'cancel'
  225. tear_down: () ->
  226. $(@el).fadeOut(200, => @remove())
  227. $('.block').fadeOut(200)
  228. cancel: (e) ->
  229. @tear_down()
  230. e.preventDefault()
  231. call_callback: (e) ->
  232. @tear_down()
  233. e.preventDefault()
  234. @callback($(@el).serialize())
  235. initialize: (attrs) ->
  236. @url = attrs.url
  237. @model = attrs.model
  238. @template = attrs.template
  239. @callback = attrs.callback
  240. @hook = attrs.hook
  241. render: () ->
  242. tpl = _.template($(@template).html(), @model.attributes)
  243. element = $(@el).html(tpl)
  244. $('body').append(element.fadeIn(200))
  245. $('.block').fadeIn(300)
  246. if @hook?
  247. @hook @
  248. FileView = Backbone.View.extend
  249. tagName: 'tr'
  250. events:
  251. "click .delete": 'delete'
  252. "click .touch": 'touch'
  253. "click .rename": 'rename'
  254. "click .resize": 'resize'
  255. delete: (e)->
  256. @model.delete_file()
  257. @remove()
  258. touch: (e) ->
  259. @model.touch_file()
  260. rename: (e) ->
  261. @model.rename_file()
  262. resize: (e) ->
  263. @model.resize_image()
  264. className: ->
  265. Table.get_row_class()
  266. initialize: (attrs) ->
  267. @table = Table
  268. @attrs = attrs.model.attributes
  269. @model = attrs.model
  270. render: () ->
  271. tpl = _.template($('#browse_file_tpl').html(), @attrs)
  272. elm = $(@el).html(tpl)
  273. resizable_mimetypes = ['image/png', 'image/jpeg',
  274. 'image/bmp', 'image/gif']
  275. if @attrs.mimetype in resizable_mimetypes and BFMOptions.pil
  276. elm.find('.icons .resize').css('display', 'inline-block')
  277. @table.append elm
  278. FileUploadView = Backbone.View.extend
  279. initialize: (file, parent) ->
  280. @file = file
  281. @parent = parent
  282. @directory = Route.path
  283. events:
  284. 'click a': 'abort'
  285. renders: () ->
  286. filename = if @file.name? then @file.name else @file.fileName
  287. @el = $(_.template($('#file_upload_tpl').html(), {filename: filename}))
  288. @delegateEvents @events
  289. @el
  290. do_upload: () ->
  291. csrf_token = $('input[name=csrfmiddlewaretoken]').val()
  292. @xhr = $.ajax_upload @file, {
  293. url: "upfile/?directory=#{@directory}"
  294. headers:
  295. "X-CSRFToken": csrf_token
  296. progress: ((e, stats) => @report_progress(e, stats))
  297. complete: ((e, data) => @upload_complete(e, data))
  298. error: ((e) => @upload_error(e))
  299. abort: ((e) => @upload_abort(e))
  300. }
  301. abort: (e) ->
  302. @xhr.abort()
  303. report_progress: (e, stats) ->
  304. @parent.report_speed(stats.speed)
  305. @el.find('.progress').stop(true).animate({
  306. width: "#{stats.completion*100}%"
  307. }, stats.last_call)
  308. upload_error: (e) ->
  309. @el.find('.progress').css('background', '#CC0000')
  310. @parent.report_errors()
  311. @upload_next()
  312. upload_abort: (e) ->
  313. @el.find('.progress').css('background', '#FF6600')
  314. @upload_next()
  315. upload_complete: (e, data) ->
  316. @el.find('.fname').html """<a href="#{data.url}" target="_blank">#{data.filename}</a>"""
  317. @el.find('.progress').stop(true).animate({
  318. width: "100%"
  319. }, 300)
  320. @upload_next()
  321. upload_next: () ->
  322. @parent.upload_next()
  323. @el.find('.stop').remove()
  324. UploaderView = Backbone.View.extend
  325. initialize: () ->
  326. @uploadlist = []
  327. @errors = false
  328. el: $ '.uploader'
  329. events:
  330. 'change form input': 'selected'
  331. uploadingevents:
  332. 'click .minimize': 'minimize'
  333. 'click .maximize': 'maximize'
  334. 'click .refresh': 'rebirth'
  335. minimize: (e) ->
  336. @el.addClass('minimized')
  337. $(e.currentTarget).removeClass('minimize').addClass('maximize')
  338. maximize: (e) ->
  339. @el.removeClass('minimized')
  340. $(e.currentTarget).removeClass('maximize').addClass('minimize')
  341. rebirth: (e) ->
  342. Uploader = new UploaderView()
  343. Uploader.render(@el)
  344. render: (elm) ->
  345. @el.html _.template($('#uploader_start_tpl').html())()
  346. if elm?
  347. elm.replaceWith(@el)
  348. selected: (e) ->
  349. tmpl = $(_.template($('#uploader_uploading_tpl').html())())
  350. @el.replaceWith tmpl
  351. @el = tmpl
  352. @delegateEvents @uploadingevents
  353. table = tmpl.find('table')
  354. selected_files = e.currentTarget.files
  355. for file in selected_files
  356. @uploadlist.push(new FileUploadView file, @)
  357. for uploadable in @uploadlist
  358. table.append uploadable.renders()
  359. @uploadlist.reverse()
  360. @uploadlist.pop().do_upload()
  361. window.onbeforeunload = (e) ->
  362. $.trim($('#upload_cancel_tpl').text())
  363. upload_next: () ->
  364. if @uploadlist and @uploadlist.length > 0
  365. @uploadlist.pop().do_upload()
  366. else
  367. template = if not @errors then '#upload_success_tpl' else '#upload_fail_tpl'
  368. text = $.trim($(template).text())
  369. @el.find('.status').html(text)
  370. @el.filter('.uploadinghead').find('.icon').removeClass('minimize maximize').addClass('refresh')
  371. window.onbeforeunload = null
  372. Route.reload()
  373. report_speed: (speed) ->
  374. @el.find('.status .speed').text("#{readable_size(speed)}/s")
  375. report_errors: () ->
  376. @errors = true
  377. PaginatorView = Backbone.View.extend
  378. el: $ 'p.paginator'
  379. events:
  380. 'click a': 'page_click'
  381. 'click .firstpage': 'first_page'
  382. 'click .lastpage': 'last_page'
  383. render: () ->
  384. @el.empty()
  385. pages = []
  386. page_count = Files.page_count()
  387. if page_count > 5
  388. if Route.page > 6
  389. @el.append _.template($('#pgn_first_page_tpl').html())()
  390. for page in [Route.page-5..Route.page+5]
  391. if page < 1 or page > page_count
  392. continue
  393. if parseInt(page) == parseInt(Route.page)
  394. rn = _.template($('#pgn_current_page_tpl').html(), {page: page})
  395. else
  396. rn = _.template($('#pgn_page_tpl').html(), {page: page})
  397. @el.append rn
  398. if page_count > 5
  399. if Route.page < page_count - 5
  400. @el.append _.template($('#pgn_last_page_tpl').html())()
  401. page_click: (e) ->
  402. page = parseInt($(e.currentTarget).text())
  403. if not isNaN page
  404. Route.goto undefined, page
  405. e.preventDefault()
  406. first_page: (e) ->
  407. e.preventDefault()
  408. Route.goto undefined, 1
  409. last_page: (e) ->
  410. e.preventDefault()
  411. Route.goto undefined, Files.page_count()
  412. Urls = Backbone.Router.extend
  413. initialize: ->
  414. @do_reload = false
  415. routes:
  416. '*path/page-:page': 'do_browse'
  417. '*path': 'do_browse'
  418. do_browse: (path, page) ->
  419. @page = if page? then parseInt(page) else 1
  420. if @do_reload or path isnt @path
  421. @path = path
  422. if not @do_reload
  423. Dirs.el.find('.selected').removeClass('selected')
  424. Table.clear()
  425. Files.set_directory(path)
  426. Files.fetch()
  427. else
  428. Table.clear()
  429. Files.added()
  430. @do_reload = false
  431. goto: (path, page) ->
  432. page = if page? then parseInt(page) else 1
  433. path = if path? then path else @path
  434. @navigate "#{path}/page-#{page}", true
  435. reload: () ->
  436. @do_reload = true
  437. @do_browse(@path, @page)
  438. Table = new FileTableView()
  439. Dirs = new DirectoriesView()
  440. Uploader = new UploaderView()
  441. Paginator = new PaginatorView()
  442. Files = new Files()
  443. D = new Directories
  444. Route = new Urls()
  445. D.fetch()
  446. Uploader.render()
  447. Backbone.history.start()