epuber 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +6 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +46 -0
  5. data/bin/epuber +10 -0
  6. data/epuber.gemspec +51 -0
  7. data/lib/epuber.rb +14 -0
  8. data/lib/epuber/book.rb +267 -0
  9. data/lib/epuber/book/contributor.rb +90 -0
  10. data/lib/epuber/book/file_request.rb +68 -0
  11. data/lib/epuber/book/target.rb +284 -0
  12. data/lib/epuber/book/toc_item.rb +130 -0
  13. data/lib/epuber/checker.rb +19 -0
  14. data/lib/epuber/checker/text_checker.rb +129 -0
  15. data/lib/epuber/checker_transformer_base.rb +71 -0
  16. data/lib/epuber/command.rb +65 -0
  17. data/lib/epuber/command/compile.rb +142 -0
  18. data/lib/epuber/command/init.rb +145 -0
  19. data/lib/epuber/command/server.rb +59 -0
  20. data/lib/epuber/compiler.rb +255 -0
  21. data/lib/epuber/compiler/compilation_context.rb +86 -0
  22. data/lib/epuber/compiler/file_finders/abstract.rb +270 -0
  23. data/lib/epuber/compiler/file_finders/imaginary.rb +167 -0
  24. data/lib/epuber/compiler/file_finders/normal.rb +22 -0
  25. data/lib/epuber/compiler/file_resolver.rb +316 -0
  26. data/lib/epuber/compiler/file_types/abstract_file.rb +119 -0
  27. data/lib/epuber/compiler/file_types/bade_file.rb +39 -0
  28. data/lib/epuber/compiler/file_types/container_xml_file.rb +26 -0
  29. data/lib/epuber/compiler/file_types/generated_file.rb +29 -0
  30. data/lib/epuber/compiler/file_types/ibooks_display_options_file.rb +31 -0
  31. data/lib/epuber/compiler/file_types/image_file.rb +42 -0
  32. data/lib/epuber/compiler/file_types/mime_type_file.rb +20 -0
  33. data/lib/epuber/compiler/file_types/nav_file.rb +42 -0
  34. data/lib/epuber/compiler/file_types/opf_file.rb +27 -0
  35. data/lib/epuber/compiler/file_types/source_file.rb +52 -0
  36. data/lib/epuber/compiler/file_types/static_file.rb +18 -0
  37. data/lib/epuber/compiler/file_types/stylus_file.rb +20 -0
  38. data/lib/epuber/compiler/file_types/xhtml_file.rb +102 -0
  39. data/lib/epuber/compiler/generator.rb +67 -0
  40. data/lib/epuber/compiler/meta_inf_generator.rb +41 -0
  41. data/lib/epuber/compiler/nav_generator.rb +201 -0
  42. data/lib/epuber/compiler/opf_generator.rb +284 -0
  43. data/lib/epuber/compiler/xhtml_processor.rb +254 -0
  44. data/lib/epuber/config.rb +133 -0
  45. data/lib/epuber/dsl/attribute.rb +248 -0
  46. data/lib/epuber/dsl/attribute_support.rb +130 -0
  47. data/lib/epuber/dsl/object.rb +145 -0
  48. data/lib/epuber/dsl/tree_object.rb +101 -0
  49. data/lib/epuber/helper.rb +19 -0
  50. data/lib/epuber/lockfile.rb +55 -0
  51. data/lib/epuber/plugin.rb +108 -0
  52. data/lib/epuber/ruby_extensions/match_data.rb +40 -0
  53. data/lib/epuber/ruby_extensions/thread.rb +13 -0
  54. data/lib/epuber/server.rb +614 -0
  55. data/lib/epuber/server/auto_refresh/auto_refresh.coffee +97 -0
  56. data/lib/epuber/server/auto_refresh/connector.coffee +125 -0
  57. data/lib/epuber/server/auto_refresh/protocol.coffee +41 -0
  58. data/lib/epuber/server/auto_refresh/reloader.coffee +261 -0
  59. data/lib/epuber/server/base.styl +3 -0
  60. data/lib/epuber/server/basic.styl +211 -0
  61. data/lib/epuber/server/book_content.styl +39 -0
  62. data/lib/epuber/server/default_cover.png +0 -0
  63. data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Bold.ttf +0 -0
  64. data/lib/epuber/server/fonts/AvenirNext/AvenirNext-BoldItalic.ttf +0 -0
  65. data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Italic.ttf +0 -0
  66. data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Regular.ttf +0 -0
  67. data/lib/epuber/server/handlers.rb +67 -0
  68. data/lib/epuber/server/keyboard_control.coffee +6 -0
  69. data/lib/epuber/server/pages/book.bade +75 -0
  70. data/lib/epuber/server/pages/common.bade +59 -0
  71. data/lib/epuber/server/pages/files.bade +17 -0
  72. data/lib/epuber/server/pages/toc.bade +29 -0
  73. data/lib/epuber/server/support.coffee +10 -0
  74. data/lib/epuber/templates/template.bookspec +143 -0
  75. data/lib/epuber/third_party/bower.rb +22 -0
  76. data/lib/epuber/third_party/bower/bower.json +10 -0
  77. data/lib/epuber/third_party/bower/bower_components/cookies-js/bower.json +10 -0
  78. data/lib/epuber/third_party/bower/bower_components/cookies-js/dist/cookies.d.ts +33 -0
  79. data/lib/epuber/third_party/bower/bower_components/cookies-js/dist/cookies.js +173 -0
  80. data/lib/epuber/third_party/bower/bower_components/cookies-js/dist/cookies.min.js +6 -0
  81. data/lib/epuber/third_party/bower/bower_components/jquery/MIT-LICENSE.txt +21 -0
  82. data/lib/epuber/third_party/bower/bower_components/jquery/bower.json +28 -0
  83. data/lib/epuber/third_party/bower/bower_components/jquery/dist/jquery.js +9210 -0
  84. data/lib/epuber/third_party/bower/bower_components/jquery/dist/jquery.min.js +5 -0
  85. data/lib/epuber/third_party/bower/bower_components/jquery/dist/jquery.min.map +1 -0
  86. data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax.js +786 -0
  87. data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/jsonp.js +89 -0
  88. data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/load.js +75 -0
  89. data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/parseJSON.js +13 -0
  90. data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/parseXML.js +28 -0
  91. data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/script.js +64 -0
  92. data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/var/nonce.js +5 -0
  93. data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/var/rquery.js +3 -0
  94. data/lib/epuber/third_party/bower/bower_components/jquery/src/ajax/xhr.js +136 -0
  95. data/lib/epuber/third_party/bower/bower_components/jquery/src/attributes.js +11 -0
  96. data/lib/epuber/third_party/bower/bower_components/jquery/src/attributes/attr.js +141 -0
  97. data/lib/epuber/third_party/bower/bower_components/jquery/src/attributes/classes.js +158 -0
  98. data/lib/epuber/third_party/bower/bower_components/jquery/src/attributes/prop.js +94 -0
  99. data/lib/epuber/third_party/bower/bower_components/jquery/src/attributes/support.js +35 -0
  100. data/lib/epuber/third_party/bower/bower_components/jquery/src/attributes/val.js +161 -0
  101. data/lib/epuber/third_party/bower/bower_components/jquery/src/callbacks.js +205 -0
  102. data/lib/epuber/third_party/bower/bower_components/jquery/src/core.js +502 -0
  103. data/lib/epuber/third_party/bower/bower_components/jquery/src/core/access.js +60 -0
  104. data/lib/epuber/third_party/bower/bower_components/jquery/src/core/init.js +123 -0
  105. data/lib/epuber/third_party/bower/bower_components/jquery/src/core/parseHTML.js +39 -0
  106. data/lib/epuber/third_party/bower/bower_components/jquery/src/core/ready.js +97 -0
  107. data/lib/epuber/third_party/bower/bower_components/jquery/src/core/var/rsingleTag.js +4 -0
  108. data/lib/epuber/third_party/bower/bower_components/jquery/src/css.js +450 -0
  109. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/addGetHookIf.js +22 -0
  110. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/curCSS.js +57 -0
  111. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/defaultDisplay.js +70 -0
  112. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/hiddenVisibleSelectors.js +15 -0
  113. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/support.js +96 -0
  114. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/swap.js +28 -0
  115. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/var/cssExpand.js +3 -0
  116. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/var/getStyles.js +12 -0
  117. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/var/isHidden.js +13 -0
  118. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/var/rmargin.js +3 -0
  119. data/lib/epuber/third_party/bower/bower_components/jquery/src/css/var/rnumnonpx.js +5 -0
  120. data/lib/epuber/third_party/bower/bower_components/jquery/src/data.js +178 -0
  121. data/lib/epuber/third_party/bower/bower_components/jquery/src/data/Data.js +181 -0
  122. data/lib/epuber/third_party/bower/bower_components/jquery/src/data/accepts.js +20 -0
  123. data/lib/epuber/third_party/bower/bower_components/jquery/src/data/var/data_priv.js +5 -0
  124. data/lib/epuber/third_party/bower/bower_components/jquery/src/data/var/data_user.js +5 -0
  125. data/lib/epuber/third_party/bower/bower_components/jquery/src/deferred.js +149 -0
  126. data/lib/epuber/third_party/bower/bower_components/jquery/src/deprecated.js +13 -0
  127. data/lib/epuber/third_party/bower/bower_components/jquery/src/dimensions.js +50 -0
  128. data/lib/epuber/third_party/bower/bower_components/jquery/src/effects.js +648 -0
  129. data/lib/epuber/third_party/bower/bower_components/jquery/src/effects/Tween.js +114 -0
  130. data/lib/epuber/third_party/bower/bower_components/jquery/src/effects/animatedSelector.js +13 -0
  131. data/lib/epuber/third_party/bower/bower_components/jquery/src/event.js +868 -0
  132. data/lib/epuber/third_party/bower/bower_components/jquery/src/event/ajax.js +13 -0
  133. data/lib/epuber/third_party/bower/bower_components/jquery/src/event/alias.js +39 -0
  134. data/lib/epuber/third_party/bower/bower_components/jquery/src/event/support.js +9 -0
  135. data/lib/epuber/third_party/bower/bower_components/jquery/src/exports/amd.js +24 -0
  136. data/lib/epuber/third_party/bower/bower_components/jquery/src/exports/global.js +32 -0
  137. data/lib/epuber/third_party/bower/bower_components/jquery/src/intro.js +44 -0
  138. data/lib/epuber/third_party/bower/bower_components/jquery/src/jquery.js +37 -0
  139. data/lib/epuber/third_party/bower/bower_components/jquery/src/manipulation.js +580 -0
  140. data/lib/epuber/third_party/bower/bower_components/jquery/src/manipulation/_evalUrl.js +18 -0
  141. data/lib/epuber/third_party/bower/bower_components/jquery/src/manipulation/support.js +32 -0
  142. data/lib/epuber/third_party/bower/bower_components/jquery/src/manipulation/var/rcheckableType.js +3 -0
  143. data/lib/epuber/third_party/bower/bower_components/jquery/src/offset.js +207 -0
  144. data/lib/epuber/third_party/bower/bower_components/jquery/src/outro.js +1 -0
  145. data/lib/epuber/third_party/bower/bower_components/jquery/src/queue.js +142 -0
  146. data/lib/epuber/third_party/bower/bower_components/jquery/src/queue/delay.js +22 -0
  147. data/lib/epuber/third_party/bower/bower_components/jquery/src/selector-native.js +172 -0
  148. data/lib/epuber/third_party/bower/bower_components/jquery/src/selector-sizzle.js +14 -0
  149. data/lib/epuber/third_party/bower/bower_components/jquery/src/selector.js +1 -0
  150. data/lib/epuber/third_party/bower/bower_components/jquery/src/serialize.js +111 -0
  151. data/lib/epuber/third_party/bower/bower_components/jquery/src/sizzle/dist/sizzle.js +2067 -0
  152. data/lib/epuber/third_party/bower/bower_components/jquery/src/sizzle/dist/sizzle.min.js +3 -0
  153. data/lib/epuber/third_party/bower/bower_components/jquery/src/sizzle/dist/sizzle.min.map +1 -0
  154. data/lib/epuber/third_party/bower/bower_components/jquery/src/traversing.js +199 -0
  155. data/lib/epuber/third_party/bower/bower_components/jquery/src/traversing/findFilter.js +100 -0
  156. data/lib/epuber/third_party/bower/bower_components/jquery/src/traversing/var/rneedsContext.js +6 -0
  157. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/arr.js +3 -0
  158. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/class2type.js +4 -0
  159. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/concat.js +5 -0
  160. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/hasOwn.js +5 -0
  161. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/indexOf.js +5 -0
  162. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/pnum.js +3 -0
  163. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/push.js +5 -0
  164. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/rnotwhite.js +3 -0
  165. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/slice.js +5 -0
  166. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/strundefined.js +3 -0
  167. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/support.js +4 -0
  168. data/lib/epuber/third_party/bower/bower_components/jquery/src/var/toString.js +5 -0
  169. data/lib/epuber/third_party/bower/bower_components/jquery/src/wrap.js +79 -0
  170. data/lib/epuber/third_party/bower/bower_components/keymaster/MIT-LICENSE +20 -0
  171. data/lib/epuber/third_party/bower/bower_components/keymaster/Makefile +4 -0
  172. data/lib/epuber/third_party/bower/bower_components/keymaster/README.markdown +212 -0
  173. data/lib/epuber/third_party/bower/bower_components/keymaster/bower.json +27 -0
  174. data/lib/epuber/third_party/bower/bower_components/keymaster/keymaster.js +296 -0
  175. data/lib/epuber/third_party/bower/bower_components/keymaster/package.json +11 -0
  176. data/lib/epuber/third_party/bower/bower_components/keymaster/test.html +93 -0
  177. data/lib/epuber/third_party/bower/bower_components/spin.js/LICENSE.txt +21 -0
  178. data/lib/epuber/third_party/bower/bower_components/spin.js/README.md +21 -0
  179. data/lib/epuber/third_party/bower/bower_components/spin.js/bower.json +18 -0
  180. data/lib/epuber/third_party/bower/bower_components/spin.js/jquery.spin.js +80 -0
  181. data/lib/epuber/third_party/bower/bower_components/spin.js/spin.js +337 -0
  182. data/lib/epuber/third_party/bower/bower_components/uri.js/LICENSE.txt +21 -0
  183. data/lib/epuber/third_party/bower/bower_components/uri.js/README.md +534 -0
  184. data/lib/epuber/third_party/bower/bower_components/uri.js/bower.json +16 -0
  185. data/lib/epuber/third_party/bower/bower_components/uri.js/contributing.md +19 -0
  186. data/lib/epuber/third_party/bower/bower_components/uri.js/src/IPv6.js +188 -0
  187. data/lib/epuber/third_party/bower/bower_components/uri.js/src/SecondLevelDomains.js +241 -0
  188. data/lib/epuber/third_party/bower/bower_components/uri.js/src/URI.fragmentQuery.js +104 -0
  189. data/lib/epuber/third_party/bower/bower_components/uri.js/src/URI.fragmentURI.js +97 -0
  190. data/lib/epuber/third_party/bower/bower_components/uri.js/src/URI.js +2115 -0
  191. data/lib/epuber/third_party/bower/bower_components/uri.js/src/URI.min.js +86 -0
  192. data/lib/epuber/third_party/bower/bower_components/uri.js/src/URITemplate.js +499 -0
  193. data/lib/epuber/third_party/bower/bower_components/uri.js/src/jquery.URI.js +235 -0
  194. data/lib/epuber/third_party/bower/bower_components/uri.js/src/jquery.URI.min.js +7 -0
  195. data/lib/epuber/third_party/bower/bower_components/uri.js/src/punycode.js +508 -0
  196. data/lib/epuber/transformer.rb +19 -0
  197. data/lib/epuber/transformer/text_transformer.rb +60 -0
  198. data/lib/epuber/user_interface.rb +186 -0
  199. data/lib/epuber/vendor/globals_context.rb +26 -0
  200. data/lib/epuber/vendor/hash_binding.rb +26 -0
  201. data/lib/epuber/vendor/nokogiri_extensions.rb +30 -0
  202. data/lib/epuber/vendor/ruby_templater.rb +71 -0
  203. data/lib/epuber/vendor/size.rb +20 -0
  204. data/lib/epuber/vendor/version.rb +83 -0
  205. data/lib/epuber/version.rb +4 -0
  206. metadata +556 -0
@@ -0,0 +1,97 @@
1
+
2
+ # most of this code is based on https://github.com/livereload/livereload-js/blob/master/src/livereload.coffee
3
+ #
4
+
5
+ class @AutoRefresh
6
+ MESSAGE_MAP =
7
+ styles: ReloaderContext.ReloadType.style
8
+ reload: ReloaderContext.ReloadType.reload
9
+ compile_start: ReloaderContext.ReloadType.compilation_begin
10
+ compile_end: ReloaderContext.ReloadType.compilation_end
11
+
12
+ CONNECTION_STATUS_ID = 'epuber_connection_container'
13
+
14
+ constructor: (@window, @console) ->
15
+ unless @WebSocket = @window.WebSocket || @window.MozWebSocket
16
+ @console.error("AutoRefresh disabled because the browser does not seem to support web sockets")
17
+ return
18
+
19
+ @shouldDisplayConnectionStatus = no
20
+ @document = @window.document
21
+
22
+ @reloader = new ReloaderContext(@window, @console)
23
+
24
+ url_without_fragment = new URI(window.location).fragment(null).toString()
25
+
26
+ @connector = new Connector url_without_fragment, @WebSocket, @console, Timer,
27
+ connecting: =>
28
+ @console.info("AutoRefresh: started connecting")
29
+ @_displayConnectionStatus('Connecting')
30
+
31
+ socketConnected: =>
32
+
33
+ connected: =>
34
+ @console.info("AutoRefresh: connection to server established")
35
+ @_hideConnectionStatus()
36
+
37
+ disconnected: (reason) =>
38
+ msg = "AutoRefresh: disconnected (reason: #{reason})"
39
+ @console.log(msg)
40
+ @_displayConnectionStatus(msg)
41
+
42
+ error: (e) =>
43
+ msg = "AutoRefresh: connector error #{JSON.stringify(e)}"
44
+ @console.error(msg)
45
+ @_displayConnectionStatus(msg)
46
+
47
+ message: (message) =>
48
+ @console.log("AutoRefresh: received message #{JSON.stringify(message)}")
49
+
50
+ name = message.name;
51
+ action = MESSAGE_MAP[name];
52
+ @reloader.perform(action, message.data)
53
+
54
+
55
+ $(@window).unload =>
56
+ @connector.disconnect('unload')
57
+
58
+ @initialized = yes
59
+
60
+ _displayConnectionStatus: (statusMessage) ->
61
+ @shouldDisplayConnectionStatus = yes
62
+
63
+ unless @document.body?
64
+ $(@window).load =>
65
+ if @shouldDisplayConnectionStatus
66
+ @_displayConnectionStatus(statusMessage)
67
+ return
68
+
69
+ container = @document.getElementById(CONNECTION_STATUS_ID)
70
+
71
+ # remove if it is already there
72
+ $(container).remove() if container?
73
+
74
+ # create new container element
75
+ container = @document.createElement('div')
76
+ container.id = CONNECTION_STATUS_ID
77
+
78
+ # remove item after user clicks on the overlay
79
+ container.onclick = ->
80
+ $(container).remove()
81
+
82
+ title = @document.createElement("p")
83
+ title.innerHTML = statusMessage
84
+ container.appendChild(title)
85
+
86
+ $(container).prependTo(@document.body)
87
+
88
+ _hideConnectionStatus: ->
89
+ @shouldDisplayConnectionStatus = no
90
+
91
+ unless @document.body?
92
+ $(@window).load =>
93
+ unless @shouldDisplayConnectionStatus
94
+ @_hideConnectionStatus()
95
+ return
96
+
97
+ $("\##{CONNECTION_STATUS_ID}").remove()
@@ -0,0 +1,125 @@
1
+
2
+ # most of this code is based on https://github.com/livereload/livereload-js/blob/master/src/connector.coffee
3
+ #
4
+ class @Connector
5
+ MIN_DELAY = 1000
6
+ MAX_DELAY = 60 * 1000
7
+ HANDSHAKE_TIMEOUT = 5000
8
+
9
+ constructor: (url, @WebSocket, @console, @Timer, @_handler) ->
10
+ uri = URI(url)
11
+ newScheme =
12
+ switch uri.protocol()
13
+ when 'http'
14
+ 'ws'
15
+ when 'https'
16
+ 'wss'
17
+ uri.protocol(newScheme)
18
+ @_uri = uri.toString()
19
+
20
+ @_nextDelay = MIN_DELAY
21
+ @_connectionDesired = no
22
+
23
+ @protocolParser = new ProtocolParser
24
+ connected: (hello_message) =>
25
+ @_handshakeTimeout.stop()
26
+ @_nextDelay = MIN_DELAY
27
+ @_disconnectionReason = 'broken'
28
+ @_callHandler('connected', hello_message)
29
+
30
+ error: (e) =>
31
+ @_callHandler('error', e)
32
+ @_closeOnError()
33
+
34
+ message: (message) =>
35
+ if message.name == 'heartbeat'
36
+ # TODO: reset timeout timer
37
+ else
38
+ @_callHandler('message', message)
39
+
40
+ @_handshakeTimeout = new Timer =>
41
+ return unless @_isSocketConnected()
42
+ @console.error('Connector: Handshake timed out')
43
+ @_disconnectionReason = 'handshake-timeout'
44
+ @socket.close()
45
+
46
+ @_reconnectTimer = new Timer =>
47
+ return unless @_connectionDesired # shouldn't hit this, but just in case
48
+ @connect()
49
+
50
+ @connect()
51
+
52
+
53
+ _isSocketConnected: ->
54
+ @socket and @socket.readyState is @WebSocket.OPEN
55
+
56
+ connect: ->
57
+ @_connectionDesired = yes
58
+ return if @_isSocketConnected()
59
+
60
+ @protocolParser.reset()
61
+
62
+ # prepare for a new connection
63
+ @_reconnectTimer.stop()
64
+ @_disconnectionReason = 'cannot-connect'
65
+
66
+ @_callHandler('connecting')
67
+
68
+ @socket = new @WebSocket(@_uri)
69
+ @socket.onopen = (e) => @_onopen(e)
70
+ @socket.onclose = (e) => @_onclose(e)
71
+ @socket.onmessage = (e) => @_onmessage(e)
72
+ @socket.onerror = (e) => @_onerror(e)
73
+
74
+ disconnect: (reason = 'manual')->
75
+ @_connectionDesired = no
76
+ @_reconnectTimer.stop() # in case it was running
77
+ return unless @_isSocketConnected()
78
+ @_disconnectionReason = reason
79
+ @socket.close()
80
+
81
+
82
+ _scheduleReconnection: ->
83
+ return unless @_connectionDesired # don't reconnect after manual disconnection
84
+ unless @_reconnectTimer.running
85
+ @_reconnectTimer.start(@_nextDelay)
86
+ @_nextDelay = Math.min(MAX_DELAY, @_nextDelay * 2)
87
+
88
+ _callHandler: (message, arg...) ->
89
+ func = @_handler[message]
90
+ if func?
91
+ func(arg...)
92
+ else
93
+ @console.error("Connector: error: handler doesn't know #{message}")
94
+
95
+ sendMessage: (name, data) ->
96
+ message =
97
+ name: name
98
+
99
+ message.data = data if data?
100
+
101
+ @socket.send(JSON.stringify(message))
102
+
103
+ _closeOnError: ->
104
+ @_handshakeTimeout.stop()
105
+ @_disconnectionReason = 'error'
106
+ @socket.close()
107
+
108
+ _onopen: (e) ->
109
+ @_callHandler('socketConnected')
110
+ @_disconnectionReason = 'handshake-failed'
111
+
112
+ # start handshake
113
+ @sendMessage('hello')
114
+ @_handshakeTimeout.start(HANDSHAKE_TIMEOUT)
115
+
116
+ _onclose: (e) ->
117
+ @_callHandler('disconnected', @_disconnectionReason, @_nextDelay)
118
+ @_scheduleReconnection()
119
+
120
+ _onerror: (e) ->
121
+ @_callHandler('error', e)
122
+ @console.error("Connector: #{e}")
123
+
124
+ _onmessage: (e) ->
125
+ @protocolParser.process(e.data)
@@ -0,0 +1,41 @@
1
+
2
+ # most of this code is based on https://github.com/livereload/livereload-js/blob/master/src/protocol.coffee
3
+ #
4
+
5
+ class @ProtocolError
6
+ constructor: (reason, data) ->
7
+ @message = "LiveReload protocol error (#{reason}) after receiving data: \"#{data}\"."
8
+
9
+ class @ProtocolParser
10
+ constructor: (@handler) ->
11
+ @reset()
12
+
13
+ reset: ->
14
+ @send_hello = false
15
+
16
+ process: (data) ->
17
+ try
18
+ if not @send_hello
19
+ message = @_parseMessage(data, ['hello'])
20
+ @send_hello = true
21
+ @handler.connected(message)
22
+ else
23
+ message = @_parseMessage(data, ['heartbeat', 'styles', 'reload', 'compile_start', 'compile_end'])
24
+ @handler.message(message)
25
+ catch e
26
+ if e instanceof ProtocolError
27
+ @handler.error e
28
+ else
29
+ throw e
30
+
31
+ _parseMessage: (data, validNames) ->
32
+ try
33
+ message = JSON.parse(data)
34
+ catch e
35
+ throw new ProtocolError('unparsable JSON', data)
36
+ unless message.name
37
+ throw new ProtocolError('missing "name" key', data)
38
+ unless message.name in validNames
39
+ throw new ProtocolError("invalid command '#{message.name}', only valid commands are: #{validNames.join(', ')})", data)
40
+
41
+ return message
@@ -0,0 +1,261 @@
1
+
2
+ class @Timer
3
+ constructor: (@func) ->
4
+ @running = no; @id = null
5
+ @_handler = =>
6
+ @running = no
7
+ @id = null
8
+ @func()
9
+
10
+ start: (timeout) ->
11
+ clearTimeout @id if @running
12
+ @id = setTimeout @_handler, timeout
13
+ @running = yes
14
+
15
+ stop: ->
16
+ if @running
17
+ clearTimeout @id
18
+ @running = no; @id = null
19
+
20
+ Timer.start = (timeout, func) ->
21
+ setTimeout func, timeout
22
+
23
+ generateCacheBustUrl = (url) ->
24
+ URI(url).setQuery('now', 1 * new Date).toString()
25
+
26
+
27
+ unless URI.prototype.updateEmptyParts
28
+ URI.prototype.updateEmptyParts = (location) ->
29
+ this.hostname(location.hostname) if this.hostname() == ''
30
+ this.port(location.port) if this.port() == ''
31
+ this.protocol(location.protocol) if this.protocol() == ''
32
+ return this
33
+
34
+
35
+ class @ReloaderContext
36
+ 'use strict';
37
+
38
+ STYLE_ID = "EpuberAutoRefreshTransitionRule"
39
+ TRANSITION =
40
+ className: 'epuber_loading'
41
+ duration: 0.3
42
+
43
+ @ReloadType = ReloadType =
44
+ style: 1
45
+ reload: 2
46
+ compilation_begin: 3
47
+ compilation_end: 4
48
+
49
+
50
+ constructor: (@window, @console) ->
51
+ @document = @window.document
52
+ $(@window).load =>
53
+ @_restoreScrollPosition()
54
+
55
+
56
+ _head: ->
57
+ @__head ||= @document.getElementsByTagName('head')[0]
58
+
59
+
60
+ _startAnimatedStylesheetReload: ->
61
+ return if @document.getElementById(STYLE_ID)?
62
+
63
+ style = @document.createElement("style")
64
+ @_head().appendChild(style)
65
+
66
+ style.setAttribute("type", "text/css")
67
+ style.setAttribute("id", STYLE_ID)
68
+
69
+ style_code = """
70
+ .#{TRANSITION.className} * {
71
+ -webkit-transition: all #{TRANSITION.duration}s ease-out;
72
+ -moz-transition: all #{TRANSITION.duration}s ease-out;
73
+ -o-transition: all #{TRANSITION.duration}s ease-out;
74
+ transition: all #{TRANSITION.duration}s ease-out;
75
+ }
76
+ """
77
+
78
+ if style.styleSheet
79
+ style.styleSheet.cssText = style_code
80
+ else
81
+ style.appendChild(@document.createTextNode(style_code))
82
+
83
+ @_addTransitionClassToHtmlNode()
84
+
85
+ _stopAnimatedStylesheetReload: ->
86
+ element = @document.getElementById(STYLE_ID)
87
+ @_head().removeChild(element) if element?
88
+
89
+ @_removeTransitionClassFromHtmlNode()
90
+
91
+
92
+
93
+ _addTransitionClassToHtmlNode: ->
94
+ htmlNode = document.body.parentNode
95
+ htmlNode.className = htmlNode.className.replace(TRANSITION.className, "") + " #{TRANSITION.className}"
96
+
97
+ _removeTransitionClassFromHtmlNode: ->
98
+ htmlNode = document.body.parentNode
99
+ htmlNode.className = htmlNode.className.replace(TRANSITION.className, "")
100
+
101
+
102
+ _reattachAllStylesheetLinks: (changed_files_hrefs = null) ->
103
+ links = (link for link in @document.getElementsByTagName('link') when link.rel.match(/^stylesheet$/i) and not link.__pendingRemoval)
104
+
105
+ if changed_files_hrefs?
106
+ changed_uris = (URI(href).updateEmptyParts(@window.location) for href in changed_files_hrefs)
107
+
108
+ filtered_list = []
109
+ for link in links
110
+ uri = URI(link.href).removeQuery('now')
111
+
112
+ for changed_uri in changed_uris
113
+ if uri.equals(changed_uri)
114
+ filtered_list.push(link)
115
+ break
116
+
117
+ links = filtered_list
118
+
119
+ for link in links
120
+ @_reattachStylesheetLink(link)
121
+
122
+ _reattachStylesheetLink: (link) ->
123
+ # ignore LINKs that will be removed by LR soon
124
+ return if link.__pendingRemoval
125
+ link.__pendingRemoval = yes
126
+
127
+ clone = link.cloneNode(false)
128
+ clone.href = generateCacheBustUrl(link.href)
129
+
130
+ # insert the new LINK before the old one
131
+ parent = link.parentNode
132
+ if parent.lastChild is link
133
+ parent.appendChild(clone)
134
+ else
135
+ parent.insertBefore clone, link.nextSibling
136
+
137
+ @_waitUntilCssLoads clone, =>
138
+ if /AppleWebKit/.test(navigator.userAgent)
139
+ additionalWaitingTime = 5
140
+ else
141
+ additionalWaitingTime = 200
142
+
143
+ Timer.start additionalWaitingTime, =>
144
+ return if !link.parentNode
145
+ link.parentNode.removeChild(link)
146
+ clone.onreadystatechange = null
147
+
148
+ @window.StyleFix?.link(clone)
149
+
150
+
151
+ _waitUntilCssLoads: (clone, func) ->
152
+ callbackExecuted = no
153
+
154
+ executeCallback = =>
155
+ return if callbackExecuted
156
+ callbackExecuted = yes
157
+ func()
158
+
159
+ # supported by Chrome 19+, Safari 5.2+, Firefox 9+, Opera 9+, IE6+
160
+ # http://www.zachleat.com/web/load-css-dynamically/
161
+ # http://pieisgood.org/test/script-link-events/
162
+ clone.onload = =>
163
+ @console.log "AutoRefresh: the new stylesheet has finished loading... for file #{clone.href}"
164
+ @knownToSupportCssOnLoad = yes
165
+ executeCallback()
166
+
167
+ unless @knownToSupportCssOnLoad
168
+ # polling
169
+ do poll = =>
170
+ if clone.sheet
171
+ @console.log "AutoRefresh: is polling until the new CSS finishes loading... for file #{clone.href}"
172
+ executeCallback()
173
+ else
174
+ Timer.start 50, poll
175
+
176
+ # fail safe
177
+ Timer.start (10 * 1000), executeCallback
178
+
179
+ _createCompilingOverlayIfNeeded: ->
180
+ if @spinner_container?
181
+ return
182
+
183
+ @spinner_container = document.createElement('div');
184
+ @spinner_container.id = 'epuber_spinner_container';
185
+ $(@spinner_container).css('opacity', '0');
186
+
187
+ opts =
188
+ lines: 12 # The number of lines to draw
189
+ length: 7 # The length of each line
190
+ width: 4 # The line thickness
191
+ radius: 9 # The radius of the inner circle
192
+ corners: 1 # Corner roundness (0..1)
193
+ rotate: 0 # The rotation offset
194
+ direction: 1 # 1: clockwise, -1: counterclockwise
195
+ color: '#fff' # #rgb or #rrggbb or array of colors
196
+ speed: 1 # Rounds per second
197
+ trail: 42 # Afterglow percentage
198
+ shadow: false # Whether to render a shadow
199
+ hwaccel: false # Whether to use hardware acceleration
200
+ className: 'epuber_spinner' # The CSS class to assign to the spinner
201
+ zIndex: 2e9 # The z-index (defaults to 2000000000)
202
+ top: '50%' # Top position relative to parent
203
+ left: '50%' # Left position relative to parent
204
+
205
+ @spinner = new Spinner(opts)
206
+
207
+ _displayCompilingOverlay: ->
208
+ @_createCompilingOverlayIfNeeded()
209
+ @spinner.spin(@spinner_container)
210
+ $(@spinner_container).appendTo('body').animate({opacity: '1'}, TRANSITION.duration * 1000)
211
+
212
+ _hideCompilingOverlay: ->
213
+ @spinner.stop()
214
+ $(@spinner_container).remove().animate({opacity: '0'}, TRANSITION.duration * 1000)
215
+
216
+
217
+
218
+ _saveScrollPosition: ->
219
+ expires = new Date;
220
+ expires.setTime(expires.getTime() + 864e5)
221
+
222
+ o = window.pageXOffset + "_" + window.pageYOffset;
223
+ Cookies.set('epuber_scroll_offset', o, expires: expires)
224
+
225
+ _restoreScrollPosition: ->
226
+ offset = Cookies.get('epuber_scroll_offset')
227
+ if offset?
228
+ t = offset.split("_")
229
+
230
+ if t.length == 2
231
+ @window.scrollTo(parseInt(t[0]), parseInt(t[1]))
232
+
233
+ Cookies.expire('epuber_scroll_offset')
234
+
235
+
236
+ perform: (type, changed_files_hrefs) ->
237
+ switch type
238
+ when ReloadType.style
239
+ @console.log('ReloadType.style')
240
+ @_hideCompilingOverlay()
241
+
242
+ @_startAnimatedStylesheetReload()
243
+ @_reattachAllStylesheetLinks(changed_files_hrefs)
244
+ after(TRANSITION.duration * 1000, => @_stopAnimatedStylesheetReload())
245
+
246
+ when ReloadType.reload
247
+ @console.log('AutoRefresh: reloading page')
248
+ @_saveScrollPosition()
249
+
250
+ uri = URI(@window.location)
251
+ uri.setQuery('cache_control', Math.round(+new Date / 1e3))
252
+ @window.location.assign(uri.toString())
253
+
254
+ when ReloadType.compilation_begin
255
+ @_displayCompilingOverlay()
256
+
257
+ when ReloadType.compilation_end
258
+ @_hideCompilingOverlay()
259
+
260
+ else
261
+ @console.error "Unsupported reload type #{type}"