PageFiles.coffee 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. class PageFiles extends Class
  2. constructor: ->
  3. @need_update = true
  4. @updating_files = 0
  5. @optional_stats = {limit: "0", free: "0", used: "0"}
  6. @updateOptionalStats()
  7. @hover_totalbar = false
  8. @menu_totalbar = new Menu()
  9. @editing_limit = false
  10. @limit = ""
  11. @selected_files_num = 0
  12. @selected_files_size = 0
  13. @selected_files_pinned = 0
  14. @bigfiles = new Bigfiles()
  15. @result = new FilesResult()
  16. @display_limit = 0
  17. @filtering = ""
  18. @
  19. getSites: =>
  20. if @result.filter_inner_path
  21. return @result.files.getSites()
  22. if @bigfiles.files.items.length > 0
  23. return @bigfiles.files.getSites().concat(Page.site_list.sites)
  24. else
  25. return Page.site_list.sites
  26. checkSelectedFiles: =>
  27. @selected_files_num = 0
  28. @selected_files_size = 0
  29. @selected_files_pinned = 0
  30. for site in @getSites()
  31. for site_file in site.files.items when site.files.selected[site_file.inner_path]
  32. @selected_files_num += 1
  33. @selected_files_size += site_file.size
  34. @selected_files_pinned += site_file.is_pinned
  35. handleSelectbarCancel: =>
  36. for site in @getSites()
  37. for site_file in site.files.items
  38. for key, val of site.files.selected
  39. delete site.files.selected[key]
  40. @checkSelectedFiles()
  41. Page.projector.scheduleRender()
  42. return false
  43. handleSelectbarPin: =>
  44. for site in @getSites()
  45. inner_paths = (site_file.inner_path for site_file in site.files.items when site.files.selected[site_file.inner_path])
  46. if inner_paths.length > 0
  47. ((site) ->
  48. Page.cmd "optionalFilePin", [inner_paths, site.row.address], ->
  49. site.files.update()
  50. )(site)
  51. @handleSelectbarCancel()
  52. handleSelectbarUnpin: =>
  53. for site in @getSites()
  54. inner_paths = (site_file.inner_path for site_file in site.files.items when site.files.selected[site_file.inner_path])
  55. if inner_paths.length > 0
  56. ((site) ->
  57. Page.cmd "optionalFileUnpin", [inner_paths, site.row.address], ->
  58. site.files.update()
  59. )(site)
  60. @handleSelectbarCancel()
  61. handleSelectbarDelete: =>
  62. bigfiles_modified_sites = []
  63. for site in @getSites()
  64. selected_site_files = (site_file for site_file in site.files.items when site.files.selected[site_file.inner_path])
  65. if selected_site_files.length > 0
  66. for selected_site_file in selected_site_files
  67. Page.cmd "optionalFileDelete", [selected_site_file.inner_path, site.row.address]
  68. if site.files.mode == "bigfiles"
  69. # Try delete piecemap if selected from Bigfile section
  70. Page.cmd "optionalFileDelete", [selected_site_file.inner_path + ".piecemap.msgpack", site.row.address]
  71. bigfiles_modified_sites.push(site.row.address)
  72. site.files.update()
  73. # Also update site section if deleted from Bigfiles section
  74. if bigfiles_modified_sites
  75. for site in Page.site_list.sites
  76. if site.row.address in bigfiles_modified_sites
  77. site.files.update()
  78. Page.site_list.update()
  79. @handleSelectbarCancel()
  80. handleTotalbarOver: =>
  81. @hover_totalbar = true
  82. Page.projector.scheduleRender()
  83. handleTotalbarOut: =>
  84. @hover_totalbar = false
  85. Page.projector.scheduleRender()
  86. handleEditlimitClick: =>
  87. @editing_limit = true
  88. return false
  89. handleLimitCancelClick: =>
  90. @editing_limit = false
  91. return false
  92. handleLimitSetClick: =>
  93. if @limit.indexOf("M") > 0 or @limit.indexOf("m") > 0
  94. limit = (parseFloat(@limit) / 1024).toString()
  95. else if @limit.indexOf("%") > 0
  96. limit = parseFloat(@limit) + "%"
  97. else
  98. limit = parseFloat(@limit).toString()
  99. @optional_stats.limit = limit
  100. Page.cmd("optionalLimitSet", limit)
  101. @editing_limit = false
  102. return false
  103. handleTotalbarMenu: =>
  104. @menu_totalbar.items = []
  105. @menu_totalbar.items.push ["Edit optional files limit", @handleEditlimitClick]
  106. if @menu_totalbar.visible
  107. @menu_totalbar.hide()
  108. else
  109. @menu_totalbar.show()
  110. return false
  111. handleLimitInput: (e) =>
  112. @limit = e.target.value
  113. renderTotalbar: =>
  114. ###
  115. size_optional = 0
  116. optional_downloaded = 0
  117. for site in Page.site_list.sites
  118. size_optional += site.row.settings.size_optional
  119. optional_downloaded += site.row.settings.optional_downloaded
  120. ###
  121. if @editing_limit and parseFloat(@limit) > 0
  122. if @limit.indexOf("M") > 0 or @limit.indexOf("m") > 0
  123. limit = (parseFloat(@limit) / 1024) + "GB"
  124. else
  125. limit = @limit
  126. else
  127. limit = @optional_stats.limit
  128. if limit.endsWith("%")
  129. limit = @optional_stats.free * (parseFloat(limit)/100)
  130. else
  131. limit = parseFloat(limit) * 1024 * 1024 * 1024
  132. if @optional_stats.free > limit * 1.8 and not @hover_totalbar
  133. total_space_limited = limit * 1.8 # Too much free space, keep it visible
  134. else
  135. total_space_limited = @optional_stats.free
  136. percent_optional_downloaded = (@optional_stats.used/limit) * 100
  137. percent_optional_used = percent_optional_downloaded * (limit/total_space_limited)
  138. percent_limit = (limit/total_space_limited) * 100
  139. h("div#PageFilesDashboard", {classes: {editing: @editing_limit}}, [
  140. h("div.totalbar-edit", [
  141. h("span.title", "Optional files limit:"),
  142. h("input", {type: "text", value: @limit, oninput: @handleLimitInput}),
  143. h("a.set", {href: "#", onclick: @handleLimitSetClick}, "Set"),
  144. h("a.cancel", {href: "#", onclick: @handleLimitCancelClick}, "Cancel")
  145. ]),
  146. h("a.totalbar-title", {href: "#", title: "Space current used by optional files", onclick: @handleTotalbarMenu},
  147. "Used: #{Text.formatSize(@optional_stats.used)} / #{Text.formatSize(limit)} (#{Math.round(percent_optional_downloaded)}%)",
  148. h("div.icon-arrow-down")
  149. ),
  150. @menu_totalbar.render(),
  151. h("div.totalbar", { onmouseover: @handleTotalbarOver, onmouseout: @handleTotalbarOut },
  152. h("div.totalbar-used", {style: "width: #{percent_optional_used}%"}),
  153. h("div.totalbar-limitbar", {style: "width: #{percent_limit}%"}),
  154. h("div.totalbar-limit", {style: "margin-left: #{percent_limit}%"},
  155. h("span", {title: "Space allowed to used by optional files"}, Text.formatSize(limit))
  156. )
  157. h("div.totalbar-hddfree",
  158. h("span", {title: "Total free space on your storage"}, [
  159. Text.formatSize(@optional_stats.free),
  160. h("div.arrow", { style: if @optional_stats.free > total_space_limited then "width: 10px" else "width: 0px" }, " \u25B6")
  161. ])
  162. )
  163. )
  164. ])
  165. renderSelectbar: =>
  166. h("div.selectbar", {classes: {visible: @selected_files_num > 0}}, [
  167. "Selected:",
  168. h("span.info", [
  169. h("span.num", "#{@selected_files_num} files"),
  170. h("span.size", "(#{Text.formatSize(@selected_files_size)})"),
  171. ])
  172. h("div.actions", [
  173. if @selected_files_pinned > @selected_files_num / 2
  174. h("a.action.pin.unpin", {href: "#", onclick: @handleSelectbarUnpin}, "UnPin")
  175. else
  176. h("a.action.pin", {href: "#", title: "Don't delete these files automatically", onclick: @handleSelectbarPin}, "Pin")
  177. h("a.action.delete", {href: "#", onclick: @handleSelectbarDelete}, "Delete")
  178. ])
  179. h("a.cancel.link", {href: "#", onclick: @handleSelectbarCancel}, "Cancel")
  180. ])
  181. handleFilterInput: (e) =>
  182. if @input_timer
  183. clearInterval @input_timer
  184. @filtering = e.target.value
  185. @input_timer = setTimeout ( =>
  186. RateLimitCb 600, (cb_done) =>
  187. @result.setFilter @filtering, =>
  188. @checkSelectedFiles()
  189. cb_done()
  190. ), 300
  191. handleFilterKeyup: (e) =>
  192. if e.keyCode == 27 # Esc
  193. e.target.value = ""
  194. @handleFilterInput(e)
  195. return false
  196. renderFilter: =>
  197. h("div.filter", [
  198. # h("span.title", "Filter:"),
  199. h("input.text", {placeholder: "Filter: File name", spellcheck: false, oninput: @handleFilterInput, onkeyup: @handleFilterKeyup, value: @filtering})
  200. ])
  201. updateOptionalStats: =>
  202. Page.cmd "optionalLimitStats", [], (res) =>
  203. @limit = res.limit
  204. if not @limit.endsWith("%")
  205. @limit += " GB"
  206. @optional_stats = res
  207. updateAllFiles: =>
  208. @updating_files = 0
  209. used = 0
  210. Page.site_list.sites.map (site) =>
  211. if not site.row.settings.size_optional
  212. return
  213. @updating_files += 1
  214. used += site.row.settings.optional_downloaded
  215. site.files.update =>
  216. @updating_files -= 1
  217. @updating_files += 1
  218. @bigfiles.files.update =>
  219. @updating_files -= 1
  220. render: =>
  221. if Page.site_list.sites and not @need_update and @updating_files == 0 and document.body.className != "loaded"
  222. document.body.classList.add("loaded")
  223. if @need_update and Page.site_list.sites.length
  224. @updateAllFiles()
  225. @need_update = false
  226. sites = (site for site in Page.site_list.sites when site.row.settings.size_optional)
  227. sites_favorited = (site for site in sites when site.favorite)
  228. sites_connected = (site for site in sites when not site.favorite)
  229. if sites.length > 0 and sites[0].files.loaded == false
  230. # Sites loaded but not site files yet
  231. if sites_favorited.length
  232. sites_favorited = [sites_favorited[0]]
  233. sites_connected = []
  234. else
  235. sites_favorited = []
  236. sites_connected = [sites_connected[0]]
  237. if sites.length == 0
  238. document.body.classList.add("loaded")
  239. return h("div#PageFiles",
  240. @renderSelectbar()
  241. @renderTotalbar()
  242. h("div.empty", [
  243. h("h4", "Hello newcomer!"),
  244. h("small", "You have not downloaded any optional files yet")
  245. ])
  246. )
  247. # Progressive display of sites to large ui blocks
  248. if @display_limit < sites.length
  249. setTimeout ( =>
  250. @display_limit += 1
  251. Page.projector.scheduleRender()
  252. ), 1000
  253. h("div#PageFiles", [
  254. @renderSelectbar()
  255. @renderTotalbar()
  256. @renderFilter()
  257. if @result.filter_inner_path
  258. @result.render()
  259. else
  260. [
  261. @bigfiles.render()
  262. sites_favorited[0..@display_limit].map (site) =>
  263. site.renderOptionalStats()
  264. sites_connected[0..@display_limit].map (site) =>
  265. site.renderOptionalStats()
  266. ]
  267. ])
  268. onSiteInfo: (site_info) =>
  269. if site_info.event?[0] == "peers_added"
  270. return false
  271. if site_info.tasks == 0 and site_info.event?[0] == "file_done"
  272. rate_limit = 1000
  273. else
  274. rate_limit = 10000
  275. RateLimit rate_limit, =>
  276. @need_update = true
  277. window.PageFiles = PageFiles