Sidebar.coffee 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. class Sidebar extends Class
  2. constructor: ->
  3. @tag = null
  4. @container = null
  5. @opened = false
  6. @width = 410
  7. @fixbutton = $(".fixbutton")
  8. @fixbutton_addx = 0
  9. @fixbutton_initx = 0
  10. @fixbutton_targetx = 0
  11. @frame = $("#inner-iframe")
  12. @initFixbutton()
  13. @dragStarted = 0
  14. @globe = null
  15. @original_set_site_info = wrapper.setSiteInfo # We going to override this, save the original
  16. # Start in opened state for debugging
  17. if false
  18. @startDrag()
  19. @moved()
  20. @fixbutton_targetx = @fixbutton_initx - @width
  21. @stopDrag()
  22. initFixbutton: ->
  23. # Detect dragging
  24. @fixbutton.on "mousedown", (e) =>
  25. e.preventDefault()
  26. # Disable previous listeners
  27. @fixbutton.off "click"
  28. @fixbutton.off "mousemove"
  29. # Make sure its not a click
  30. @dragStarted = (+ new Date)
  31. @fixbutton.one "mousemove", (e) =>
  32. @fixbutton_addx = @fixbutton.offset().left-e.pageX
  33. @startDrag()
  34. @fixbutton.parent().on "click", (e) =>
  35. @stopDrag()
  36. @fixbutton_initx = @fixbutton.offset().left # Initial x position
  37. # Start dragging the fixbutton
  38. startDrag: ->
  39. @log "startDrag"
  40. @fixbutton_targetx = @fixbutton_initx # Fallback x position
  41. @fixbutton.addClass("dragging")
  42. # Fullscreen drag bg to capture mouse events over iframe
  43. $("<div class='drag-bg'></div>").appendTo(document.body)
  44. # IE position wrap fix
  45. if navigator.userAgent.indexOf('MSIE') != -1 or navigator.appVersion.indexOf('Trident/') > 0
  46. @fixbutton.css("pointer-events", "none")
  47. # Don't go to homepage
  48. @fixbutton.one "click", (e) =>
  49. @stopDrag()
  50. @fixbutton.removeClass("dragging")
  51. if Math.abs(@fixbutton.offset().left - @fixbutton_initx) > 5
  52. # If moved more than some pixel the button then don't go to homepage
  53. e.preventDefault()
  54. # Animate drag
  55. @fixbutton.parents().on "mousemove", @animDrag
  56. @fixbutton.parents().on "mousemove" ,@waitMove
  57. # Stop dragging listener
  58. @fixbutton.parents().on "mouseup", (e) =>
  59. e.preventDefault()
  60. @stopDrag()
  61. # Wait for moving the fixbutton
  62. waitMove: (e) =>
  63. if Math.abs(@fixbutton.offset().left - @fixbutton_targetx) > 10 and (+ new Date)-@dragStarted > 100
  64. @moved()
  65. @fixbutton.parents().off "mousemove" ,@waitMove
  66. moved: ->
  67. @log "Moved"
  68. @createHtmltag()
  69. $(document.body).css("perspective", "1000px").addClass("body-sidebar")
  70. $(window).off "resize"
  71. $(window).on "resize", =>
  72. $(document.body).css "height", $(window).height()
  73. @scrollable()
  74. $(window).trigger "resize"
  75. # Override setsiteinfo to catch changes
  76. wrapper.setSiteInfo = (site_info) =>
  77. @setSiteInfo(site_info)
  78. @original_set_site_info.apply(wrapper, arguments)
  79. setSiteInfo: (site_info) ->
  80. @updateHtmlTag()
  81. @displayGlobe()
  82. # Create the sidebar html tag
  83. createHtmltag: ->
  84. if not @container
  85. @container = $("""
  86. <div class="sidebar-container"><div class="sidebar scrollable"><div class="content-wrapper"><div class="content">
  87. </div></div></div></div>
  88. """)
  89. @container.appendTo(document.body)
  90. @tag = @container.find(".sidebar")
  91. @updateHtmlTag()
  92. @scrollable = window.initScrollable()
  93. updateHtmlTag: ->
  94. wrapper.ws.cmd "sidebarGetHtmlTag", {}, (res) =>
  95. if @tag.find(".content").children().length == 0 # First update
  96. @log "Creating content"
  97. morphdom(@tag.find(".content")[0], '<div class="content">'+res+'</div>')
  98. @scrollable()
  99. else # Not first update, patch the html to keep unchanged dom elements
  100. @log "Patching content"
  101. morphdom @tag.find(".content")[0], '<div class="content">'+res+'</div>', {
  102. onBeforeMorphEl: (from_el, to_el) -> # Ignore globe loaded state
  103. if from_el.className == "globe"
  104. return false
  105. else
  106. return true
  107. }
  108. animDrag: (e) =>
  109. mousex = e.pageX
  110. overdrag = @fixbutton_initx-@width-mousex
  111. if overdrag > 0 # Overdragged
  112. overdrag_percent = 1+overdrag/300
  113. mousex = (e.pageX + (@fixbutton_initx-@width)*overdrag_percent)/(1+overdrag_percent)
  114. targetx = @fixbutton_initx-mousex-@fixbutton_addx
  115. @fixbutton.offset
  116. left: mousex+@fixbutton_addx
  117. if @tag
  118. @tag.css("transform", "translateX(#{0-targetx}px)")
  119. # Check if opened
  120. if (not @opened and targetx > @width/3) or (@opened and targetx > @width*0.9)
  121. @fixbutton_targetx = @fixbutton_initx - @width # Make it opened
  122. else
  123. @fixbutton_targetx = @fixbutton_initx
  124. # Stop dragging the fixbutton
  125. stopDrag: ->
  126. @fixbutton.parents().off "mousemove"
  127. @fixbutton.off "mousemove"
  128. @fixbutton.css("pointer-events", "")
  129. $(".drag-bg").remove()
  130. if not @fixbutton.hasClass("dragging")
  131. return
  132. @fixbutton.removeClass("dragging")
  133. # Move back to initial position
  134. if @fixbutton_targetx != @fixbutton.offset().left
  135. # Animate fixbutton
  136. @fixbutton.stop().animate {"left": @fixbutton_targetx}, 500, "easeOutBack", =>
  137. # Switch back to auto align
  138. if @fixbutton_targetx == @fixbutton_initx # Closed
  139. @fixbutton.css("left", "auto")
  140. else # Opened
  141. @fixbutton.css("left", @fixbutton_targetx)
  142. $(".fixbutton-bg").trigger "mouseout" # Switch fixbutton back to normal status
  143. # Animate sidebar and iframe
  144. if @fixbutton_targetx == @fixbutton_initx
  145. # Closed
  146. targetx = 0
  147. @opened = false
  148. else
  149. # Opened
  150. targetx = @width
  151. if not @opened
  152. @onOpened()
  153. @opened = true
  154. # Revent sidebar transitions
  155. @tag.css("transition", "0.4s ease-out")
  156. @tag.css("transform", "translateX(-#{targetx}px)").one transitionEnd, =>
  157. @tag.css("transition", "")
  158. if not @opened
  159. @container.remove()
  160. @container = null
  161. @tag.remove()
  162. @tag = null
  163. # Revert body transformations
  164. @log "stopdrag", "opened:", @opened
  165. if not @opened
  166. @onClosed()
  167. onOpened: ->
  168. @log "Opened"
  169. @scrollable()
  170. # Re-calculate height when site admin opened or closed
  171. @tag.find("#checkbox-owned").off("click").on "click", =>
  172. setTimeout (=>
  173. @scrollable()
  174. ), 300
  175. # Site limit button
  176. @tag.find("#button-sitelimit").on "click", =>
  177. wrapper.ws.cmd "siteSetLimit", $("#input-sitelimit").val(), =>
  178. wrapper.notifications.add "done-sitelimit", "done", "Site storage limit modified!", 5000
  179. @updateHtmlTag()
  180. return false
  181. # Change identity button
  182. @tag.find("#button-identity").on "click", =>
  183. wrapper.ws.cmd "certSelect"
  184. return false
  185. # Owned checkbox
  186. @tag.find("#checkbox-owned").on "click", =>
  187. wrapper.ws.cmd "siteSetOwned", [@tag.find("#checkbox-owned").is(":checked")]
  188. # Save settings
  189. @tag.find("#button-settings").on "click", =>
  190. wrapper.ws.cmd "fileGet", "content.json", (res) =>
  191. data = JSON.parse(res)
  192. data["title"] = $("#settings-title").val()
  193. data["description"] = $("#settings-description").val()
  194. json_raw = unescape(encodeURIComponent(JSON.stringify(data, undefined, '\t')))
  195. wrapper.ws.cmd "fileWrite", ["content.json", btoa(json_raw)], (res) =>
  196. if res != "ok" # fileWrite failed
  197. wrapper.notifications.add "file-write", "error", "File write error: #{res}"
  198. else
  199. wrapper.notifications.add "file-write", "done", "Site settings saved!", 5000
  200. @updateHtmlTag()
  201. return false
  202. # Sign content.json
  203. @tag.find("#button-sign").on "click", =>
  204. inner_path = @tag.find("#select-contents").val()
  205. if wrapper.site_info.privatekey
  206. # Privatekey stored in users.json
  207. wrapper.ws.cmd "siteSign", ["stored", inner_path], (res) =>
  208. wrapper.notifications.add "sign", "done", "#{inner_path} Signed!", 5000
  209. else
  210. # Ask the user for privatekey
  211. wrapper.displayPrompt "Enter your private key:", "password", "Sign", (privatekey) => # Prompt the private key
  212. wrapper.ws.cmd "siteSign", [privatekey, inner_path], (res) =>
  213. if res == "ok"
  214. wrapper.notifications.add "sign", "done", "#{inner_path} Signed!", 5000
  215. return false
  216. # Publish content.json
  217. @tag.find("#button-publish").on "click", =>
  218. inner_path = @tag.find("#select-contents").val()
  219. @tag.find("#button-publish").addClass "loading"
  220. wrapper.ws.cmd "sitePublish", {"inner_path": inner_path, "sign": false}, =>
  221. @tag.find("#button-publish").removeClass "loading"
  222. @loadGlobe()
  223. onClosed: ->
  224. $(window).off "resize"
  225. $(document.body).css("transition", "0.6s ease-in-out").removeClass("body-sidebar").on transitionEnd, (e) =>
  226. if e.target == document.body
  227. $(document.body).css("height", "auto").css("perspective", "").css("transition", "").off transitionEnd
  228. @unloadGlobe()
  229. # We dont need site info anymore
  230. wrapper.setSiteInfo = @original_set_site_info
  231. loadGlobe: =>
  232. if @tag.find(".globe").hasClass("loading")
  233. setTimeout (=>
  234. if typeof(DAT) == "undefined" # Globe script not loaded, do it first
  235. $.getScript("/uimedia/globe/all.js", @displayGlobe)
  236. else
  237. @displayGlobe()
  238. ), 600
  239. displayGlobe: =>
  240. wrapper.ws.cmd "sidebarGetPeers", [], (globe_data) =>
  241. if @globe
  242. @globe.scene.remove(@globe.points)
  243. @globe.addData( globe_data, {format: 'magnitude', name: "hello", animated: false} )
  244. @globe.createPoints()
  245. else
  246. @globe = new DAT.Globe( @tag.find(".globe")[0], {"imgDir": "/uimedia/globe/"} )
  247. @globe.addData( globe_data, {format: 'magnitude', name: "hello"} )
  248. @globe.createPoints()
  249. @globe.animate()
  250. @tag.find(".globe").removeClass("loading")
  251. unloadGlobe: =>
  252. if not @globe
  253. return false
  254. @globe.unload()
  255. @globe = null
  256. window.sidebar = new Sidebar()
  257. window.transitionEnd = 'transitionend webkitTransitionEnd oTransitionEnd otransitionend'