David Chambers avatar David Chambers committed 53b4507

obviate the need to publish both "hashchange" and "render" in several places

Comments (0)

Files changed (7)

src/document.coffee

   div.innerHTML = marked text.match(/^.*$/m)[0]
   div.textContent
 
-subscribe 'pre:render', (text, setEditorValue) ->
-  position = text.length - 1
-  if 0xD800 <= text.charCodeAt(position) < 0xDC00
-    # In Chrome, if one attempts to delete a surrogate pair character,
-    # only half of the pair is deleted. We strip the orphan to avoid
-    # `encodeURIComponent` throwing a `URIError`.
-    text = text.substr 0, position
-    # Normalize textarea's value.
-    setEditorValue = yes
-  [text, setEditorValue]
-
 stylesheets = []
 
-subscribe 'render', (text, setEditorValue) ->
+subscribe 'textchange', (text) ->
   while stylesheet = stylesheets.pop()
     document.head.removeChild stylesheet
 
     document.head.appendChild stylesheets[stylesheets.length] = link
 
   document.title = extractTitle(text) or 'Hashify'
-  Hashify.editor.value text if setEditorValue
+  markup.innerHTML = marked text

src/editor.coffee

 counter = $('counter')
 danger = 2083 - "#{root}#!/#{longestQueryString}".length
 
+subscribe 'pre:textchange', (text) ->
+  # In Chrome, if one attempts to delete a surrogate pair character,
+  # only half of the pair is deleted. We strip the orphan to avoid
+  # `encodeURIComponent` throwing a `URIError`.
+  pos = text.length - 1
+  text = text.substr(0, pos) if 0xD800 <= text.charCodeAt(pos) < 0xDC00
+  [text]
+
+subscribe 'textchange', (text) ->
+  publish 'hashchange', Hashify.encode text
+  Hashify.editor.value text
+
 subscribe 'hashchange', (hash) ->
   counter.innerHTML = length = hash.length
   counter.className =
   if start?
     editor.focus()
     editor.setSelectionRange start, end
-    publish 'hashchange', Hashify.encode text
-    publish 'render', text
+    publish 'textchange', text
 
 # Prevent typing from inadvertently triggering keyboard shortcuts.
 addEvent editor, 'keydown', (event) ->
   # If `editor.value` has changed since last we checked, we go ahead
   # and update the view. If it has _not_ changed, as will be the case
   # when one hits "enter" in the location bar, we needn't do anything.
-  unless lastEditorValue is lastEditorValue = @value
-    publish 'hashchange', Hashify.encode @value
-    publish 'render', @value
+  publish 'textchange', @value unless lastEditorValue is @value
+  lastEditorValue = @value
 
 addEvent editor, 'dragenter', -> false
 

src/highlight.coffee

 # This is a live collection:
 nodeList = document.getElementsByTagName 'code'
 
-subscribe 'post:render', ->
+subscribe 'post:textchange', ->
   for node in nodeList when /^lang-/.test node.className
     node.className = node.className.replace 'lang', 'language'
     hljs.highlightBlock node

src/initialize.coffee

 
 markup = $('markup')
 
-subscribe 'render', (text) ->
-  markup.innerHTML = marked text
-
 subscribe 'editor:resized', (width) ->
   markup.style.marginLeft = width + 'px'
 
 {hash, query} = Hashify.location.components()
 
-# Initialize `#counter`.
-publish 'hashchange', hash, "#{query}"
-
 ready = ->
   value = Hashify.editor.value()
   if query.contains 'raw:yes'
     # we fall back to hashbangs. If `location.hash` is to be
     # the source of truth, `location.pathname` should be "/".
     location.replace '/#!/' + hash + query
-  publish 'render', decode(hash), yes
+  publish 'hashchange', hash
   do ready
 else if /^unpack:/.test hash
   list = hash.substr(7).split(',')
   # The maximum number of `hash` parameters is 15.
   if list.length <= bitlyLimit
     sendRequest 'expand', "hash=#{ list.join '&hash=' }", (data) ->
-      list = data.expand
-      for {long_url}, idx in list
-        list[idx] = decode long_url.substr root.length
+      stripRoot = (url) -> url.substr root.length
       # Canonicalize: btoa('x') + btoa('y') != btoa('xy')
-      publish 'render', list.join(''), yes
-      publish 'hashchange', Hashify.encode(Hashify.editor.value()), "#{query}"
+      text = (decode stripRoot long_url for {long_url} in data.expand).join ''
+      publish 'hashchange', Hashify.encode text
       do ready
 else
   do ready

src/location.coffee

     params = (name for [name] in directives when @contains name).join(';')
     params and '?' + params
 
-subscribe 'hashchange', (hash, query, options = {}) ->
-  (options = query; query = undefined) if typeof query is 'object'
+subscribe 'pre:hashchange', (args...) ->
+  args unless /^unpack:/.test args[0]
 
-  path = '/' + hash + (query or '')
+subscribe 'hashchange', (hash, options = {}) ->
+  publish 'textchange', decode hash
+  path = '/' + hash + (Hashify.location.components().query or '')
   if window.history?.pushState
     method = if options.save then 'pushState' else 'replaceState'
     history[method] null, null, path
     hash: pathname.substr(1), query: search
 
 addEvent window, 'popstate', ->
-  publish 'render', decode(components().hash), yes
+  publish 'hashchange', components().hash
 
 longest = new Query (name for [name, include] in directives when include)
 
     '?count=none&related=hashify&url=foo&text=' +
     encodeURIComponent tweetText
   wrapper.insertBefore tweet, shorturl
-
-  url = data.long_url.substr root.length
-  unless /^unpack:/.test url
-    lastSavedDocument = url
-    publish 'hashchange', url, save: yes
   wrapper.className = ''
+  publish 'hashchange', lastSavedDocument = components().hash, save: yes
 
 addEvent shorten, 'click', (event) ->
   (event or window.event).preventDefault()
   else do new Function "return #{data}"
 
 corsNotSupported = ->
-  text = '''
+  publish 'textchange', '''
     # I'm sorry, Dave
 
     Your browser appears not to support
 
     [1]: http://en.wikipedia.org/wiki/Cross-Origin_Resource_Sharing
   '''
-  publish 'hashchange', Hashify.encode text
-  publish 'render', text, yes
 
 sendRequest = (action, params, success) ->
   request = new XMLHttpRequest()
     throw error unless error.message is 'Security violation' # Opera
     do corsNotSupported
 
-window.subscriptions = {}
+subscriptions = {}
 
 subscribe = (event, action) ->
   (subscriptions[event] or= []).push action
 
+stack = []
 publish = (event, args...) ->
-  args = s args... for s in subscriptions["pre:#{event}"] or []
-  s args... for s in subscriptions[event] or []
-  s args... for s in subscriptions["post:#{event}"] or []
-  return
+  return if event in stack # prevent recursion
+  stack.push event
+  # A "pre:" hook may modify the published arguments before they're
+  # passed to the remaining event listeners (by returning an array),
+  # or it may cancel the event (by returning a falsy value).
+  cancelled = no
+  for s in subscriptions["pre:#{event}"] or []
+    unless args = s args...
+      cancelled = yes
+      break
+  unless cancelled
+    s args... for s in subscriptions[event] or []
+    s args... for s in subscriptions["post:#{event}"] or []
+  stack.pop()
 
 Hashify.utils = {$, addEvent, decode, publish, sendRequest, subscribe}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.