[Notice] Announcing the End of Demo Server [Read me]
doortts doortts 2018-04-07
js: Upgrade jQuery to v3.3.1
Higher jQuery version is a prerequite of some front-end libraries.
It is also related with Play upgrade.

- Current: v1.9.0
- New: v3.3.1
@238481addf30cc721fd91be27ab06e41a0a353bc
minify-js.sh
--- minify-js.sh
+++ minify-js.sh
@@ -1,15 +1,16 @@
+#################
 # yona-layout.js
+#################
 
 CLOSURE_COMPILER="public/compiler.jar"
 OUT_DIR="public/javascripts"
 PUBLIC="public"
 PUBLIC_JAVASCRIPTS="public/javascripts"
 
-java -jar $CLOSURE_COMPILER --js $PUBLIC_JAVASCRIPTS/lib/nprogress/nprogress.js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery-1.9.0.js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery.browser.js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery.pjax.js $PUBLIC_JAVASCRIPTS/common/yobi.Common.js --js_output_file $OUT_DIR/yona-layout.js
+java -jar $CLOSURE_COMPILER --js $PUBLIC_JAVASCRIPTS/lib/nprogress/nprogress.js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery-3.3.1.js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery.browser.js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery.pjax.js $PUBLIC_JAVASCRIPTS/common/yobi.Common.js --js_output_file $OUT_DIR/yona-layout.js
 
 # for dev 
-# cat $PUBLIC_JAVASCRIPTS/lib/nprogress/nprogress.js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery-1.9.0.js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery.browser.js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery.pjax.js $PUBLIC_JAVASCRIPTS/common/yobi.Common.js > $OUT_DIR/yona-layout.js
-
+#cat $PUBLIC_JAVASCRIPTS/lib/nprogress/nprogress.js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery-3.3.1.js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery.browser.js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery.pjax.js $PUBLIC_JAVASCRIPTS/common/yobi.Common.js > $OUT_DIR/yona-layout.js
 
 # yona-common.js
 java -jar $CLOSURE_COMPILER --js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery.tmpl.js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery.form.js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery.validate.js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery.requestAs.js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery.search.js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery.zclip.min.js $PUBLIC_JAVASCRIPTS/lib/jquery/jquery.placeholder.min.js $PUBLIC/bootstrap/js/bootstrap.js $PUBLIC_JAVASCRIPTS/lib/rgbcolor.js $PUBLIC_JAVASCRIPTS/lib/humanize.js $PUBLIC_JAVASCRIPTS/lib/validate.js $PUBLIC_JAVASCRIPTS/lib/xss.js $PUBLIC_JAVASCRIPTS/lib/clipboard.min.js --js_output_file $OUT_DIR/yona-common.js
 
public/javascripts/lib/jquery/jquery-3.3.1.js (added)
+++ public/javascripts/lib/jquery/jquery-3.3.1.js
This file is too big to display.
public/javascripts/lib/jquery/jquery.pjax.js
--- public/javascripts/lib/jquery/jquery.pjax.js
+++ public/javascripts/lib/jquery/jquery.pjax.js
@@ -1,6 +1,8 @@
-// jquery.pjax.js
-// copyright chris wanstrath
-// https://github.com/defunkt/jquery-pjax
+/*!
+ * Copyright 2012, Chris Wanstrath
+ * Released under the MIT License
+ * https://github.com/defunkt/jquery-pjax
+ */
 
 (function($){
 
@@ -17,9 +19,7 @@
 // pjax specific options:
 //
 //
-// container - Where to stick the response body. Usually a String selector.
-//             $(container).html(xhr.responseBody)
-//             (default: current jquery context)
+// container - String selector for the element where to place the response body.
 //      push - Whether to pushState the URL. Defaults to true (of course).
 //   replace - Want to use replaceState instead? That's cool.
 //
@@ -28,11 +28,13 @@
 //
 // Returns the jQuery object
 function fnPjax(selector, container, options) {
-  var context = this
+  options = optionsFor(container, options)
   return this.on('click.pjax', selector, function(event) {
-    var opts = $.extend({}, optionsFor(container, options))
-    if (!opts.container)
-      opts.container = $(this).attr('data-pjax') || context
+    var opts = options
+    if (!opts.container) {
+      opts = $.extend({}, options)
+      opts.container = $(this).attr('data-pjax')
+    }
     handleClick(event, opts)
   })
 }
@@ -50,16 +52,12 @@
 //   // is the same as
 //   $(document).pjax('a')
 //
-//  $(document).on('click', 'a', function(event) {
-//    var container = $(this).closest('[data-pjax-container]')
-//    $.pjax.click(event, container)
-//  })
-//
 // Returns nothing.
 function handleClick(event, container, options) {
   options = optionsFor(container, options)
 
   var link = event.currentTarget
+  var $link = $(link)
 
   if (link.tagName.toUpperCase() !== 'A')
     throw "$.fn.pjax or $.pjax.click requires an anchor element"
@@ -73,28 +71,28 @@
   if ( location.protocol !== link.protocol || location.hostname !== link.hostname )
     return
 
-  // Ignore anchors on the same page
-  if (link.hash && link.href.replace(link.hash, '') ===
-       location.href.replace(location.hash, ''))
+  // Ignore case when a hash is being tacked on the current URL
+  if ( link.href.indexOf('#') > -1 && stripHash(link) == stripHash(location) )
     return
 
-  // Ignore empty anchor "foo.html#"
-  if (link.href === location.href + '#')
+  // Ignore event with default prevented
+  if (event.isDefaultPrevented())
     return
 
   var defaults = {
     url: link.href,
-    container: $(link).attr('data-pjax'),
+    container: $link.attr('data-pjax'),
     target: link
   }
 
   var opts = $.extend({}, defaults, options)
   var clickEvent = $.Event('pjax:click')
-  $(link).trigger(clickEvent, [opts])
+  $link.trigger(clickEvent, [opts])
 
   if (!clickEvent.isDefaultPrevented()) {
     pjax(opts)
     event.preventDefault()
+    $link.trigger('pjax:clicked', [opts])
   }
 }
 
@@ -108,8 +106,7 @@
 // Examples
 //
 //  $(document).on('submit', 'form', function(event) {
-//    var container = $(this).closest('[data-pjax-container]')
-//    $.pjax.submit(event, container)
+//    $.pjax.submit(event, '[data-pjax-container]')
 //  })
 //
 // Returns nothing.
@@ -117,16 +114,30 @@
   options = optionsFor(container, options)
 
   var form = event.currentTarget
+  var $form = $(form)
 
   if (form.tagName.toUpperCase() !== 'FORM')
     throw "$.pjax.submit requires a form element"
 
   var defaults = {
-    type: form.method.toUpperCase(),
-    url: form.action,
-    data: $(form).serializeArray(),
-    container: $(form).attr('data-pjax'),
+    type: ($form.attr('method') || 'GET').toUpperCase(),
+    url: $form.attr('action'),
+    container: $form.attr('data-pjax'),
     target: form
+  }
+
+  if (defaults.type !== 'GET' && window.FormData !== undefined) {
+    defaults.data = new FormData(form)
+    defaults.processData = false
+    defaults.contentType = false
+  } else {
+    // Can't handle file uploads, exit
+    if ($form.find(':file').length) {
+      return
+    }
+
+    // Fallback to manually serializing the fields
+    defaults.data = $form.serializeArray()
   }
 
   pjax($.extend({}, defaults, options))
@@ -142,8 +153,7 @@
 //
 // Accepts these extra keys:
 //
-// container - Where to stick the response body.
-//             $(container).html(xhr.responseBody)
+// container - String selector for where to stick the response body.
 //      push - Whether to pushState the URL. Defaults to true (of course).
 //   replace - Want to use replaceState instead? That's cool.
 //
@@ -160,21 +170,32 @@
     options.url = options.url()
   }
 
-  var target = options.target
-
   var hash = parseURL(options.url).hash
 
-  var context = options.context = findContainerFor(options.container)
+  var containerType = $.type(options.container)
+  if (containerType !== 'string') {
+    throw "expected string value for 'container' option; got " + containerType
+  }
+  var context = options.context = $(options.container)
+  if (!context.length) {
+    throw "the container selector '" + options.container + "' did not match anything"
+  }
 
   // We want the browser to maintain two separate internal caches: one
   // for pjax'd partial page loads and one for normal page loads.
   // Without adding this secret parameter, some browsers will often
   // confuse the two.
   if (!options.data) options.data = {}
-  options.data._pjax = context.selector
+  if ($.isArray(options.data)) {
+    options.data.push({name: '_pjax', value: options.container})
+  } else {
+    options.data._pjax = options.container
+  }
 
-  function fire(type, args) {
-    var event = $.Event(type, { relatedTarget: target })
+  function fire(type, args, props) {
+    if (!props) props = {}
+    props.relatedTarget = options.target
+    var event = $.Event(type, props)
     context.trigger(event, args)
     return !event.isDefaultPrevented()
   }
@@ -189,7 +210,7 @@
     }
 
     xhr.setRequestHeader('X-PJAX', 'true')
-    xhr.setRequestHeader('X-PJAX-Container', context.selector)
+    xhr.setRequestHeader('X-PJAX-Container', options.container)
 
     if (!fire('pjax:beforeSend', [xhr, settings]))
       return false
@@ -204,7 +225,9 @@
       settings.timeout = 0
     }
 
-    options.requestUrl = parseURL(settings.url).href
+    var url = parseURL(settings.url)
+    if (hash) url.hash = hash
+    options.requestUrl = stripInternalParams(url)
   }
 
   options.complete = function(xhr, textStatus) {
@@ -226,15 +249,23 @@
   }
 
   options.success = function(data, status, xhr) {
+    var previousState = pjax.state
+
     // If $.pjax.defaults.version is a function, invoke it first.
     // Otherwise it can be a static string.
-    var currentVersion = (typeof $.pjax.defaults.version === 'function') ?
+    var currentVersion = typeof $.pjax.defaults.version === 'function' ?
       $.pjax.defaults.version() :
       $.pjax.defaults.version
 
     var latestVersion = xhr.getResponseHeader('X-PJAX-Version')
 
     var container = extractContainer(data, xhr, options)
+
+    var url = parseURL(container.url)
+    if (hash) {
+      url.hash = hash
+      container.url = url.href
+    }
 
     // If there is a layout version mismatch, hard load the new url
     if (currentVersion && latestVersion && currentVersion !== latestVersion) {
@@ -252,7 +283,7 @@
       id: options.id || uniqueId(),
       url: container.url,
       title: container.title,
-      container: context.selector,
+      container: options.container,
       fragment: options.fragment,
       timeout: options.timeout
     }
@@ -261,10 +292,22 @@
       window.history.replaceState(pjax.state, container.title, container.url)
     }
 
+    // Only blur the focus if the focused element is within the container.
+    var blurFocus = $.contains(context, document.activeElement)
+
     // Clear out any focused controls before inserting new page contents.
-    document.activeElement.blur()
+    if (blurFocus) {
+      try {
+        document.activeElement.blur()
+      } catch (e) { /* ignore */ }
+    }
 
     if (container.title) document.title = container.title
+
+    fire('pjax:beforeReplace', [container.contents, options], {
+      state: pjax.state,
+      previousState: previousState
+    })
     context.html(container.contents)
 
     // FF bug: Won't autofocus fields that are inserted via JS.
@@ -274,32 +317,21 @@
     // http://www.w3.org/html/wg/drafts/html/master/forms.html
     var autofocusEl = context.find('input[autofocus], textarea[autofocus]').last()[0]
     if (autofocusEl && document.activeElement !== autofocusEl) {
-      autofocusEl.focus();
+      autofocusEl.focus()
     }
 
     executeScriptTags(container.scripts)
 
-    // Scroll to top by default
-    if (typeof options.scrollTo === 'number')
-      $(window).scrollTop(options.scrollTo)
+    var scrollTo = options.scrollTo
 
-    // If the URL has a hash in it, make sure the browser
-    // knows to navigate to the hash.
-    if ( hash !== '' ) {
-      // Avoid using simple hash set here. Will add another history
-      // entry. Replace the url with replaceState and scroll to target
-      // by hand.
-      //
-      //   window.location.hash = hash
-      var url = parseURL(container.url)
-      url.hash = hash
-
-      pjax.state.url = url.href
-      window.history.replaceState(pjax.state, container.title, url.href)
-
-      var target = $(url.hash)
-      if (target.length) $(window).scrollTop(target.offset().top)
+    // Ensure browser scrolls to the element referenced by the URL anchor
+    if (hash) {
+      var name = decodeURIComponent(hash.slice(1))
+      var target = document.getElementById(name) || document.getElementsByName(name)[0]
+      if (target) scrollTo = $(target).offset().top
     }
+
+    if (typeof scrollTo == 'number') $(window).scrollTop(scrollTo)
 
     fire('pjax:success', [data, status, xhr, options])
   }
@@ -314,7 +346,7 @@
       id: uniqueId(),
       url: window.location.href,
       title: document.title,
-      container: context.selector,
+      container: options.container,
       fragment: options.fragment,
       timeout: options.timeout
     }
@@ -322,11 +354,7 @@
   }
 
   // Cancel the current request if we're already pjaxing
-  var xhr = pjax.xhr
-  if ( xhr && xhr.readyState < 4) {
-    xhr.onreadystatechange = $.noop
-    xhr.abort()
-  }
+  abortXHR(pjax.xhr)
 
   pjax.options = options
   var xhr = pjax.xhr = $.ajax(options)
@@ -334,9 +362,9 @@
   if (xhr.readyState > 0) {
     if (options.push && !options.replace) {
       // Cache current container element before replacing it
-      cachePush(pjax.state.id, context.clone().contents())
+      cachePush(pjax.state.id, [options.container, cloneContents(context)])
 
-      window.history.pushState(null, "", stripPjaxParam(options.requestUrl))
+      window.history.pushState(null, "", options.requestUrl)
     }
 
     fire('pjax:start', [xhr, options])
@@ -367,7 +395,7 @@
 //
 // Returns nothing.
 function locationReplace(url) {
-  window.history.replaceState(null, "", "#")
+  window.history.replaceState(null, "", pjax.state.url)
   window.location.replace(url)
 }
 
@@ -393,7 +421,15 @@
 // You probably shouldn't use pjax on pages with other pushState
 // stuff yet.
 function onPjaxPopstate(event) {
+
+  // Hitting back or forward should override any pending PJAX request.
+  if (!initialPop) {
+    abortXHR(pjax.xhr)
+  }
+
+  var previousState = pjax.state
   var state = event.state
+  var direction
 
   if (state && state.container) {
     // When coming forward from a separate history session, will get an
@@ -401,22 +437,24 @@
     // page.
     if (initialPop && initialURL == state.url) return
 
-    // If popping back to the same state, just skip.
-    // Could be clicking back from hashchange rather than a pushState.
-    if (pjax.state.id === state.id) return
+    if (previousState) {
+      // If popping back to the same state, just skip.
+      // Could be clicking back from hashchange rather than a pushState.
+      if (previousState.id === state.id) return
 
-    var container = $(state.container)
+      // Since state IDs always increase, we can deduce the navigation direction
+      direction = previousState.id < state.id ? 'forward' : 'back'
+    }
+
+    var cache = cacheMapping[state.id] || []
+    var containerSelector = cache[0] || state.container
+    var container = $(containerSelector), contents = cache[1]
+
     if (container.length) {
-      var direction, contents = cacheMapping[state.id]
-
-      if (pjax.state) {
-        // Since state ids always increase, we can deduce the history
-        // direction from the previous state.
-        direction = pjax.state.id < state.id ? 'forward' : 'back'
-
+      if (previousState) {
         // Cache current container before replacement and inform the
         // cache which direction the history shifted.
-        cachePop(direction, pjax.state.id, container.clone().contents())
+        cachePop(direction, previousState.id, [containerSelector, cloneContents(container)])
       }
 
       var popstateEvent = $.Event('pjax:popstate', {
@@ -428,7 +466,7 @@
       var options = {
         id: state.id,
         url: state.url,
-        container: container,
+        container: containerSelector,
         push: false,
         fragment: state.fragment,
         timeout: state.timeout,
@@ -438,9 +476,14 @@
       if (contents) {
         container.trigger('pjax:start', [null, options])
 
-        if (state.title) document.title = state.title
-        container.html(contents)
         pjax.state = state
+        if (state.title) document.title = state.title
+        var beforeReplaceEvent = $.Event('pjax:beforeReplace', {
+          state: state,
+          previousState: previousState
+        })
+        container.trigger(beforeReplaceEvent, [contents, options])
+        container.html(contents)
 
         container.trigger('pjax:end', [null, options])
       } else {
@@ -449,7 +492,7 @@
 
       // Force reflow/relayout before the browser tries to restore the
       // scroll position.
-      container[0].offsetHeight
+      container[0].offsetHeight // eslint-disable-line no-unused-expressions
     } else {
       locationReplace(location.href)
     }
@@ -485,13 +528,27 @@
       var pair = value.split('=')
       form.append($('<input>', {type: 'hidden', name: pair[0], value: pair[1]}))
     })
+  } else if ($.isArray(data)) {
+    $.each(data, function(index, value) {
+      form.append($('<input>', {type: 'hidden', name: value.name, value: value.value}))
+    })
   } else if (typeof data === 'object') {
+    var key
     for (key in data)
       form.append($('<input>', {type: 'hidden', name: key, value: data[key]}))
   }
 
   $(document.body).append(form)
   form.submit()
+}
+
+// Internal: Abort an XmlHttpRequest if it hasn't been completed,
+// also removing its event handlers.
+function abortXHR(xhr) {
+  if ( xhr && xhr.readyState < 4) {
+    xhr.onreadystatechange = $.noop
+    xhr.abort()
+  }
 }
 
 // Internal: Generate unique id for state object.
@@ -504,16 +561,22 @@
   return (new Date).getTime()
 }
 
-// Internal: Strips _pjax param from url
+function cloneContents(container) {
+  var cloned = container.clone()
+  // Unmark script tags as already being eval'd so they can get executed again
+  // when restored from cache. HAXX: Uses jQuery internal method.
+  cloned.find('script').each(function(){
+    if (!this.src) $._data(this, 'globalEval', false)
+  })
+  return cloned.contents()
+}
+
+// Internal: Strip internal query params from parsed URL.
 //
-// url - String
-//
-// Returns String.
-function stripPjaxParam(url) {
-  return url
-    .replace(/\?_pjax=[^&]+&?/, '?')
-    .replace(/_pjax=[^&]+&?/, '')
-    .replace(/[\?&]$/, '')
+// Returns sanitized url.href String.
+function stripInternalParams(url) {
+  url.search = url.search.replace(/([?&])(_pjax|_)=[^&]*/g, '').replace(/^&/, '')
+  return url.href.replace(/\?($|#)/, '$1')
 }
 
 // Internal: Parse URL components and returns a Locationish object.
@@ -525,6 +588,16 @@
   var a = document.createElement('a')
   a.href = url
   return a
+}
+
+// Internal: Return the `href` component of given URL object with the hash
+// portion removed.
+//
+// location - Location or HTMLAnchorElement
+//
+// Returns String
+function stripHash(location) {
+  return location.href.replace(/#.*/, '')
 }
 
 // Internal: Build options Object for arguments.
@@ -545,44 +618,14 @@
 //
 // Returns options Object.
 function optionsFor(container, options) {
-  // Both container and options
-  if ( container && options )
+  if (container && options) {
+    options = $.extend({}, options)
     options.container = container
-
-  // First argument is options Object
-  else if ( $.isPlainObject(container) )
-    options = container
-
-  // Only container
-  else
-    options = {container: container}
-
-  // Find and validate container
-  if (options.container)
-    options.container = findContainerFor(options.container)
-
-  return options
-}
-
-// Internal: Find container element for a variety of inputs.
-//
-// Because we can't persist elements using the history API, we must be
-// able to find a String selector that will consistently find the Element.
-//
-// container - A selector String, jQuery object, or DOM Element.
-//
-// Returns a jQuery object whose context is `document` and has a selector.
-function findContainerFor(container) {
-  container = $(container)
-
-  if ( !container.length ) {
-    throw "no pjax container for " + container.selector
-  } else if ( container.selector !== '' && container.context === document ) {
+    return options
+  } else if ($.isPlainObject(container)) {
     return container
-  } else if ( container.attr('id') ) {
-    return $('#' + container.attr('id'))
   } else {
-    throw "cant get selector for pjax container!"
+    return {container: container}
   }
 }
 
@@ -596,7 +639,7 @@
 //
 // Returns a jQuery object.
 function findAll(elems, selector) {
-  return elems.filter(selector).add(elems.find(selector));
+  return elems.filter(selector).add(elems.find(selector))
 }
 
 function parseHTML(html) {
@@ -615,18 +658,21 @@
 //
 // Returns an Object with url, title, and contents keys.
 function extractContainer(data, xhr, options) {
-  var obj = {}
+  var obj = {}, fullDocument = /<html/i.test(data)
 
   // Prefer X-PJAX-URL header if it was set, otherwise fallback to
   // using the original requested url.
-  obj.url = stripPjaxParam(xhr.getResponseHeader('X-PJAX-URL') || options.requestUrl)
+  var serverUrl = xhr.getResponseHeader('X-PJAX-URL')
+  obj.url = serverUrl ? stripInternalParams(parseURL(serverUrl)) : options.requestUrl
 
+  var $head, $body
   // Attempt to parse response html into elements
-  if (/<html/i.test(data)) {
-    var $head = $(parseHTML(data.match(/<head[^>]*>([\s\S.]*)<\/head>/i)[0]))
-    var $body = $(parseHTML(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0]))
+  if (fullDocument) {
+    $body = $(parseHTML(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0]))
+    var head = data.match(/<head[^>]*>([\s\S.]*)<\/head>/i)
+    $head = head != null ? $(parseHTML(head[0])) : $body
   } else {
-    var $head = $body = $(parseHTML(data))
+    $head = $body = $(parseHTML(data))
   }
 
   // If response data is empty, return fast
@@ -638,16 +684,15 @@
   obj.title = findAll($head, 'title').last().text()
 
   if (options.fragment) {
+    var $fragment = $body
     // If they specified a fragment, look for it in the response
     // and pull it out.
-    if (options.fragment === 'body') {
-      var $fragment = $body
-    } else {
-      var $fragment = findAll($body, options.fragment).first()
+    if (options.fragment !== 'body') {
+      $fragment = findAll($fragment, options.fragment).first()
     }
 
     if ($fragment.length) {
-      obj.contents = $fragment.contents()
+      obj.contents = options.fragment === 'body' ? $fragment : $fragment.contents()
 
       // If there's no title, look for data-title and title attributes
       // on the fragment
@@ -655,7 +700,7 @@
         obj.title = $fragment.attr('title') || $fragment.data('title')
     }
 
-  } else if (!/<html/i.test(data)) {
+  } else if (!fullDocument) {
     obj.contents = $body
   }
 
@@ -699,7 +744,8 @@
     if (matchedScripts.length) return
 
     var script = document.createElement('script')
-    script.type = $(this).attr('type')
+    var type = $(this).attr('type')
+    if (type) script.type = type
     script.src = $(this).attr('src')
     document.head.appendChild(script)
   })
@@ -722,14 +768,11 @@
   cacheMapping[id] = value
   cacheBackStack.push(id)
 
-  // Remove all entires in forward history stack after pushing
-  // a new page.
-  while (cacheForwardStack.length)
-    delete cacheMapping[cacheForwardStack.shift()]
+  // Remove all entries in forward history stack after pushing a new page.
+  trimCacheStack(cacheForwardStack, 0)
 
   // Trim back history stack to max cache length.
-  while (cacheBackStack.length > pjax.defaults.maxCacheLength)
-    delete cacheMapping[cacheBackStack.shift()]
+  trimCacheStack(cacheBackStack, pjax.defaults.maxCacheLength)
 }
 
 // Shifts cache from directional history cache. Should be
@@ -754,8 +797,23 @@
   }
 
   pushStack.push(id)
-  if (id = popStack.pop())
-    delete cacheMapping[id]
+  id = popStack.pop()
+  if (id) delete cacheMapping[id]
+
+  // Trim whichever stack we just pushed to to max cache length.
+  trimCacheStack(pushStack, pjax.defaults.maxCacheLength)
+}
+
+// Trim a cache stack (either cacheBackStack or cacheForwardStack) to be no
+// longer than the specified length, deleting cached DOM elements as necessary.
+//
+// stack  - Array of state IDs
+// length - Maximum length to trim to
+//
+// Returns nothing.
+function trimCacheStack(stack, length) {
+  while (stack.length > length)
+    delete cacheMapping[stack.shift()]
 }
 
 // Public: Find version identifier for the initial page load.
@@ -824,15 +882,22 @@
 
 // Add the state property to jQuery's event object so we can use it in
 // $(window).bind('popstate')
-if ( $.inArray('state', $.event.props) < 0 )
+if ($.event.props && $.inArray('state', $.event.props) < 0) {
   $.event.props.push('state')
+} else if (!('state' in $.Event.prototype)) {
+  $.event.addProp('state')
+}
 
 // Is pjax supported by this browser?
 $.support.pjax =
   window.history && window.history.pushState && window.history.replaceState &&
   // pushState isn't reliable on iOS until 5.
-  !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/)
+  !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/)
 
-$.support.pjax ? enable() : disable()
+if ($.support.pjax) {
+  enable()
+} else {
+  disable()
+}
 
-})(jQuery);
(No newline at end of file)
+})(jQuery)
public/javascripts/yona-layout.js
--- public/javascripts/yona-layout.js
+++ public/javascripts/yona-layout.js
This diff is too big to display.
Add a comment
List