angular.module('ngTurbolinks', []).run(($location, $rootScope, $http, $q, $compile)-> loadedAssets = null createDocument = null xhr_req = null referer = null triggerEvent = (name, data) -> event = document.createEvent 'Events' event.data = data if data event.initEvent name, true, true document.dispatchEvent event popCookie = (name) -> value = document.cookie.match(new RegExp(name+"=(\\w+)"))?[1].toUpperCase() or '' document.cookie = name + '=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/' value rememberReferer = -> referer = document.location.href processResponse = (responseText, status, headers)-> clientOrServerError = -> 400 <= status < 600 validContent = -> headers()["content-type"].match /^(?:text\/html|application\/xhtml\+xml|application\/xml)(?:;|$)/ extractTrackAssets = (doc) -> for node in doc.head.childNodes when node.getAttribute?('data-turbolinks-track')? node.getAttribute('src') or node.getAttribute('href') assetsChanged = (doc) -> loadedAssets ||= extractTrackAssets document fetchedAssets = extractTrackAssets doc fetchedAssets.length isnt loadedAssets.length or intersection(fetchedAssets, loadedAssets).length isnt loadedAssets.length intersection = (a, b) -> [a, b] = [b, a] if a.length > b.length value for value in a when value in b if not clientOrServerError() and validContent() doc = createDocument responseText if doc and !assetsChanged doc return doc browserCompatibleDocumentParser = -> createDocumentUsingParser = (html) -> (new DOMParser).parseFromString html, 'text/html' createDocumentUsingDOM = (html) -> doc = document.implementation.createHTMLDocument '' doc.documentElement.innerHTML = html doc createDocumentUsingWrite = (html) -> doc = document.implementation.createHTMLDocument '' doc.open 'replace' doc.write html doc.close() doc # Use createDocumentUsingParser if DOMParser is defined and natively # supports 'text/html' parsing (Firefox 12+, IE 10) # # Use createDocumentUsingDOM if createDocumentUsingParser throws an exception # due to unsupported type 'text/html' (Firefox < 12, Opera) # # Use createDocumentUsingWrite if: # - DOMParser isn't defined # - createDocumentUsingParser returns null due to unsupported type 'text/html' (Chrome, Safari) # - createDocumentUsingDOM doesn't create a valid HTML document (safeguarding against potential edge cases) try if window.DOMParser testDoc = createDocumentUsingParser '
test' createDocumentUsingParser catch e testDoc = createDocumentUsingDOM '
test' createDocumentUsingDOM finally unless testDoc?.body?.childNodes.length is 1 return createDocumentUsingWrite extractTitleAndBody = (doc) -> title = doc.querySelector 'title' [ title?.textContent, removeNoscriptTags(doc.body), CSRFToken.get(doc).token, 'runScripts' ] CSRFToken = get: (doc = document) -> node: tag = doc.querySelector 'meta[name="csrf-token"]' token: tag?.getAttribute? 'content' update: (latest) -> current = @get() if current.token? and latest? and current.token isnt latest current.node.setAttribute 'content', latest changePage = (title, body, csrfToken, runScripts) -> document.title = title angular.element("body").replaceWith(body) $compile(body)($rootScope) CSRFToken.update csrfToken if csrfToken? executeScriptTags() if runScripts currentState = window.history.state triggerEvent 'page:change' triggerEvent 'page:update' executeScriptTags = -> scripts = Array::slice.call document.body.querySelectorAll 'script:not([data-turbolinks-eval="false"])' for script in scripts when script.type in ['', 'text/javascript'] copy = document.createElement 'script' copy.setAttribute attr.name, attr.value for attr in script.attributes copy.appendChild document.createTextNode script.innerHTML { parentNode, nextSibling } = script parentNode.removeChild script parentNode.insertBefore copy, nextSibling return removeNoscriptTags = (node) -> node.innerHTML = node.innerHTML.replace /