epuber 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
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}"