SiteFiles.coffee 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. class SiteFiles extends Class
  2. constructor: (@site) ->
  3. @limit = 10
  4. @selected = {}
  5. @items = []
  6. @loaded = false
  7. @orderby = "time_downloaded"
  8. @mode = "site"
  9. @mode = "single_site"
  10. @orderby_desc = true
  11. @has_more = false
  12. getSites: =>
  13. back = []
  14. # Create separate fake site objects for bigfiles
  15. sites = {}
  16. for file in @items
  17. sites[file.site.row.address] ?= {row: file.site.row, files: {mode: @mode, items: [], selected: @selected, update: @update}}
  18. sites[file.site.row.address].files.items.push(file)
  19. for address, site of sites
  20. back.push(site)
  21. return back
  22. handleSelectClick: (e) =>
  23. return false
  24. handleSelectEnd: (e) =>
  25. document.body.removeEventListener('mouseup', @handleSelectEnd)
  26. @select_action = null
  27. handleSelectMousedown: (e) =>
  28. inner_path = e.currentTarget.attributes.inner_path.value
  29. if @selected[inner_path]
  30. delete @selected[inner_path]
  31. @select_action = "deselect"
  32. else
  33. @selected[inner_path] = true
  34. @select_action = "select"
  35. Page.page_files.checkSelectedFiles()
  36. document.body.addEventListener('mouseup', @handleSelectEnd)
  37. e.stopPropagation()
  38. Page.projector.scheduleRender()
  39. return false
  40. handleRowMouseenter: (e) =>
  41. if e.buttons and @select_action
  42. inner_path = e.target.attributes.inner_path.value
  43. if @select_action == "select"
  44. @selected[inner_path] = true
  45. else
  46. delete @selected[inner_path]
  47. Page.page_files.checkSelectedFiles()
  48. Page.projector.scheduleRender()
  49. return false
  50. handleOrderbyClick: (e) =>
  51. orderby = e.currentTarget.attributes.orderby.value
  52. if @orderby == orderby
  53. @orderby_desc = not @orderby_desc
  54. @orderby = orderby
  55. @update()
  56. return false
  57. handleMoreClick: =>
  58. @limit += 15
  59. @update()
  60. return false
  61. selectAll: =>
  62. is_selected_all = @isSelectedAll()
  63. for item in @items
  64. if is_selected_all
  65. delete @selected[item.inner_path]
  66. else
  67. @selected[item.inner_path] = true
  68. Page.projector.scheduleRender()
  69. Page.page_files.checkSelectedFiles()
  70. handleSelectAllClick: =>
  71. if @has_more
  72. @limit = 1000
  73. @update =>
  74. @selectAll()
  75. else
  76. @selectAll()
  77. return false
  78. renderOrder: (title, orderby) =>
  79. h("a.title.orderby", {
  80. href: "##{orderby}",
  81. orderby: orderby,
  82. onclick: @handleOrderbyClick,
  83. classes: {selected: @orderby == orderby, desc: @orderby_desc}
  84. }, [
  85. title,
  86. h("div.icon.icon-arrow-down")
  87. ])
  88. renderOrderRight: (title, orderby) =>
  89. h("a.title.orderby", {
  90. href: "##{orderby}",
  91. orderby: orderby,
  92. onclick: @handleOrderbyClick,
  93. classes: {selected: @orderby == orderby, desc: @orderby_desc}
  94. }, [
  95. h("div.icon.icon-arrow-down"),
  96. title
  97. ])
  98. isSelectedAll: =>
  99. return not @has_more and Object.keys(@selected).length == @items.length
  100. render: =>
  101. if not @items?.length
  102. return []
  103. [
  104. h("div.files.files-#{@mode}", exitAnimation: Animation.slideUpInout, [
  105. h("div.tr.thead", [
  106. h("div.td.pre",
  107. h("a.checkbox-outer", {
  108. href: "#Select+all", onclick: @handleSelectAllClick, classes: {selected: @isSelectedAll()}
  109. }, h("span.checkbox"))
  110. ),
  111. if @mode == "bigfiles" or @mode == "result"
  112. h("div.td.site", @renderOrder("Site", "address"))
  113. h("div.td.inner_path", @renderOrder("Optional file", "is_pinned DESC, inner_path")),
  114. if @mode == "bigfiles"
  115. h("div.td.status", "Status")
  116. h("div.td.size", @renderOrderRight("Size", "size")),
  117. h("div.td.peer", @renderOrder("Peers", "peer")),
  118. h("div.td.uploaded", @renderOrder("Uploaded", "uploaded")),
  119. h("div.td.added", @renderOrder("Finished", "time_downloaded"))
  120. #h("th.access", "Access")
  121. ]),
  122. h("div.tbody", @items.map (file) =>
  123. site = file.site or @site
  124. if file.peer >= 10
  125. profile_color = "#47d094"
  126. else if file.peer > 0
  127. profile_color = "#f5b800"
  128. else
  129. profile_color = "#d1d1d1"
  130. if @mode == "bigfiles"
  131. file.pieces ?= 0
  132. file.pieces_downloaded ?= 0
  133. if file.pieces == 0 or file.pieces_downloaded == 0
  134. percent = 0
  135. else
  136. percent = parseInt((file.pieces_downloaded / file.pieces) * 100)
  137. if file.is_downloading or percent == 100
  138. status = ""
  139. percent_bg = "#9ef5cf"
  140. else
  141. status = "paused"
  142. percent_bg = "#f5f49e"
  143. percent_title = "#{percent}% #{status}"
  144. classes = {selected: @selected[file.inner_path], pinned: file.is_pinned}
  145. h("div.tr", {key: file.inner_path, inner_path: file.inner_path, exitAnimation: Animation.slideUpInout, enterAnimation: Animation.slideDown, classes: classes, onmouseenter: @handleRowMouseenter}, [
  146. h("div.td.pre",
  147. h("a.checkbox-outer", {
  148. href: "#Select",
  149. onmousedown: @handleSelectMousedown,
  150. onclick: @handleSelectClick,
  151. inner_path: file.inner_path
  152. }, h("span.checkbox"))
  153. ),
  154. if @mode == "bigfiles" or @mode == "result"
  155. h("div.td.site", h("a.link", {href: site.getHref()}, site.row.content.title))
  156. h("div.td.inner_path",
  157. h("a.title.link", {href: site.getHref(file), target: "_blank", title: file.inner_path.replace(/.*\//, "")}, file.inner_path.replace(/.*\//, ""))
  158. if file.is_pinned
  159. h("span.pinned", {exitAnimation: Animation.slideUpInout, enterAnimation: Animation.slideDown}, "Pinned")
  160. ),
  161. if @mode == "bigfiles"
  162. h("div.td.status", {classes: {"downloading": file.is_downloading}}
  163. h("span.percent", {title: "#{file.pieces_downloaded} of #{file.pieces} pieces downloaded", style: "box-shadow: inset #{percent * 0.8}px 0px 0px #{percent_bg};"}, percent_title)
  164. )
  165. h("div.td.size", Text.formatSize(file.size)),
  166. h("div.td.peer", [
  167. h("div.icon.icon-profile", {style: "color: #{profile_color}"}),
  168. h("span.num", file.peer)
  169. ]),
  170. h("div.td.uploaded",
  171. h("div.uploaded-text", Text.formatSize(file.uploaded)),
  172. h("div.dots-container", [
  173. h("span.dots.dots-bg", {title: "Ratio: #{(file.uploaded/file.size).toFixed(1)}"}, "\u2022\u2022\u2022\u2022\u2022"),
  174. h("span.dots.dots-fg", {title: "Ratio: #{(file.uploaded/file.size).toFixed(1)}", style: "width: #{Math.min(5, file.uploaded/file.size) * 9}px"}, "\u2022\u2022\u2022\u2022\u2022")
  175. ])
  176. ),
  177. h("div.td.added", if file.time_downloaded then Time.since(file.time_downloaded) else "n/a"),
  178. #h("td.access", if file.time_accessed then Time.since(file.time_accessed) else "n/a")
  179. ])
  180. )
  181. ]),
  182. if @has_more
  183. h("div.more-container", h("a.more", {href: "#More", onclick: @handleMoreClick}, "More files..."))
  184. ]
  185. update: (cb) =>
  186. orderby = @orderby + (if @orderby_desc then " DESC" else "")
  187. Page.cmd "optionalFileList", {address: @site.row.address, limit: @limit+1, orderby: orderby}, (res) =>
  188. @items = res[0..@limit-1]
  189. @loaded = true
  190. @has_more = res.length > @limit
  191. Page.projector.scheduleRender()
  192. cb?()
  193. window.SiteFiles = SiteFiles