rasputin 0.9.1 → 0.10.0
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.
- data/README.md +19 -0
 - data/lib/rasputin/handlebars/handlebars.js +5 -0
 - data/lib/rasputin/version.rb +1 -1
 - data/vendor/assets/javascripts/TransformJS.js +432 -0
 - data/vendor/assets/javascripts/metamorph.js +298 -0
 - data/vendor/assets/javascripts/sproutcore-datastore.js +0 -1
 - data/vendor/assets/javascripts/sproutcore-i18n.js +0 -1
 - data/vendor/assets/javascripts/sproutcore-routing.js +549 -0
 - data/vendor/assets/javascripts/sproutcore-statechart.js +1 -0
 - data/vendor/assets/javascripts/sproutcore-touch.js +63 -387
 - data/vendor/assets/javascripts/sproutcore-utils.js +73 -0
 - data/vendor/assets/javascripts/sproutcore.js +243 -110
 - data/vendor/assets/stylesheets/normalize.css +10 -18
 - metadata +12 -8
 
| 
         @@ -0,0 +1,298 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            // ==========================================================================
         
     | 
| 
      
 2 
     | 
    
         
            +
            // Project:   metamorph
         
     | 
| 
      
 3 
     | 
    
         
            +
            // Copyright: ©2011 My Company Inc. All rights reserved.
         
     | 
| 
      
 4 
     | 
    
         
            +
            // ==========================================================================
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            (function(window) {
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              var K = function(){},
         
     | 
| 
      
 9 
     | 
    
         
            +
                  guid = 0,
         
     | 
| 
      
 10 
     | 
    
         
            +
                  document = window.document,
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  // Feature-detect the W3C range API
         
     | 
| 
      
 13 
     | 
    
         
            +
                  supportsRange = ('createRange' in document);
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              // Constructor that supports either Metamorph('foo') or new
         
     | 
| 
      
 16 
     | 
    
         
            +
              // Metamorph('foo');
         
     | 
| 
      
 17 
     | 
    
         
            +
              // 
         
     | 
| 
      
 18 
     | 
    
         
            +
              // Takes a string of HTML as the argument.
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              var Metamorph = function(html) {
         
     | 
| 
      
 21 
     | 
    
         
            +
                var self;
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                if (this instanceof Metamorph) {
         
     | 
| 
      
 24 
     | 
    
         
            +
                  self = this;
         
     | 
| 
      
 25 
     | 
    
         
            +
                } else {
         
     | 
| 
      
 26 
     | 
    
         
            +
                  self = new K();
         
     | 
| 
      
 27 
     | 
    
         
            +
                }
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                self.innerHTML = html;
         
     | 
| 
      
 30 
     | 
    
         
            +
                var myGuid = 'metamorph-'+(guid++);
         
     | 
| 
      
 31 
     | 
    
         
            +
                self.start = myGuid + '-start';
         
     | 
| 
      
 32 
     | 
    
         
            +
                self.end = myGuid + '-end';
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                return self;
         
     | 
| 
      
 35 
     | 
    
         
            +
              };
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
              K.prototype = Metamorph.prototype;
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              var rangeFor, htmlFunc, removeFunc, outerHTMLFunc, appendToFunc, startTagFunc, endTagFunc;
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              // create the outer HTML for the current metamorph. this function will be
         
     | 
| 
      
 42 
     | 
    
         
            +
              // extended by the Internet Explorer version to work around a bug.
         
     | 
| 
      
 43 
     | 
    
         
            +
              outerHTMLFunc = function() {
         
     | 
| 
      
 44 
     | 
    
         
            +
                return this.startTag() + this.innerHTML + this.endTag();
         
     | 
| 
      
 45 
     | 
    
         
            +
              };
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
              startTagFunc = function() {
         
     | 
| 
      
 48 
     | 
    
         
            +
                return "<script id='" + this.start + "' type='text/x-placeholder'></script>";
         
     | 
| 
      
 49 
     | 
    
         
            +
              };
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              endTagFunc = function() {
         
     | 
| 
      
 52 
     | 
    
         
            +
                return "<script id='" + this.end + "' type='text/x-placeholder'></script>";
         
     | 
| 
      
 53 
     | 
    
         
            +
              };
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
              // If we have the W3C range API, this process is relatively straight forward.
         
     | 
| 
      
 56 
     | 
    
         
            +
              if (supportsRange) {
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                // Get a range for the current morph. Optionally include the starting and
         
     | 
| 
      
 59 
     | 
    
         
            +
                // ending placeholders.
         
     | 
| 
      
 60 
     | 
    
         
            +
                rangeFor = function(morph, outerToo) {
         
     | 
| 
      
 61 
     | 
    
         
            +
                  var range = document.createRange();
         
     | 
| 
      
 62 
     | 
    
         
            +
                  var before = document.getElementById(morph.start);
         
     | 
| 
      
 63 
     | 
    
         
            +
                  var after = document.getElementById(morph.end);
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  if (outerToo) {
         
     | 
| 
      
 66 
     | 
    
         
            +
                    range.setStartBefore(before);
         
     | 
| 
      
 67 
     | 
    
         
            +
                    range.setEndAfter(after);
         
     | 
| 
      
 68 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 69 
     | 
    
         
            +
                    range.setStartAfter(before);
         
     | 
| 
      
 70 
     | 
    
         
            +
                    range.setEndBefore(after);
         
     | 
| 
      
 71 
     | 
    
         
            +
                  }
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  return range;
         
     | 
| 
      
 74 
     | 
    
         
            +
                };
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                htmlFunc = function(html) {
         
     | 
| 
      
 77 
     | 
    
         
            +
                  // get a range for the current metamorph object
         
     | 
| 
      
 78 
     | 
    
         
            +
                  var range = rangeFor(this);
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                  // delete the contents of the range, which will be the
         
     | 
| 
      
 81 
     | 
    
         
            +
                  // nodes between the starting and ending placeholder.
         
     | 
| 
      
 82 
     | 
    
         
            +
                  range.deleteContents();
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                  // create a new document fragment for the HTML
         
     | 
| 
      
 85 
     | 
    
         
            +
                  var fragment = range.createContextualFragment(html);
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                  // inser the fragment into the range
         
     | 
| 
      
 88 
     | 
    
         
            +
                  range.insertNode(fragment);
         
     | 
| 
      
 89 
     | 
    
         
            +
                };
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                removeFunc = function() {
         
     | 
| 
      
 92 
     | 
    
         
            +
                  // get a range for the current metamorph object including
         
     | 
| 
      
 93 
     | 
    
         
            +
                  // the starting and ending placeholders.
         
     | 
| 
      
 94 
     | 
    
         
            +
                  var range = rangeFor(this, true);
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  // delete the entire range.
         
     | 
| 
      
 97 
     | 
    
         
            +
                  range.deleteContents();
         
     | 
| 
      
 98 
     | 
    
         
            +
                };
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                appendToFunc = function(node) {
         
     | 
| 
      
 101 
     | 
    
         
            +
                  var range = document.createRange();
         
     | 
| 
      
 102 
     | 
    
         
            +
                  range.setStart(node);
         
     | 
| 
      
 103 
     | 
    
         
            +
                  range.collapse(false);
         
     | 
| 
      
 104 
     | 
    
         
            +
                  var frag = range.createContextualFragment(this.outerHTML());
         
     | 
| 
      
 105 
     | 
    
         
            +
                  node.appendChild(frag);
         
     | 
| 
      
 106 
     | 
    
         
            +
                };
         
     | 
| 
      
 107 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 108 
     | 
    
         
            +
                /**
         
     | 
| 
      
 109 
     | 
    
         
            +
                 * This code is mostly taken from jQuery, with one exception. In jQuery's case, we
         
     | 
| 
      
 110 
     | 
    
         
            +
                 * have some HTML and we need to figure out how to convert it into some nodes.
         
     | 
| 
      
 111 
     | 
    
         
            +
                 *
         
     | 
| 
      
 112 
     | 
    
         
            +
                 * In this case, jQuery needs to scan the HTML looking for an opening tag and use
         
     | 
| 
      
 113 
     | 
    
         
            +
                 * that as the key for the wrap map. In our case, we know the parent node, and
         
     | 
| 
      
 114 
     | 
    
         
            +
                 * can use its type as the key for the wrap map.
         
     | 
| 
      
 115 
     | 
    
         
            +
                 **/
         
     | 
| 
      
 116 
     | 
    
         
            +
                var wrapMap = {
         
     | 
| 
      
 117 
     | 
    
         
            +
                  select: [ 1, "<select multiple='multiple'>", "</select>" ],
         
     | 
| 
      
 118 
     | 
    
         
            +
                  fieldset: [ 1, "<fieldset>", "</fieldset>" ],
         
     | 
| 
      
 119 
     | 
    
         
            +
                  table: [ 1, "<table>", "</table>" ],
         
     | 
| 
      
 120 
     | 
    
         
            +
                  tbody: [ 2, "<table><tbody>", "</tbody></table>" ],
         
     | 
| 
      
 121 
     | 
    
         
            +
                  tr: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
         
     | 
| 
      
 122 
     | 
    
         
            +
                  colgroup: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
         
     | 
| 
      
 123 
     | 
    
         
            +
                  map: [ 1, "<map>", "</map>" ],
         
     | 
| 
      
 124 
     | 
    
         
            +
                  _default: [ 0, "", "" ]
         
     | 
| 
      
 125 
     | 
    
         
            +
                };
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                /**
         
     | 
| 
      
 128 
     | 
    
         
            +
                 * Given a parent node and some HTML, generate a set of nodes. Return the first
         
     | 
| 
      
 129 
     | 
    
         
            +
                 * node, which will allow us to traverse the rest using nextSibling.
         
     | 
| 
      
 130 
     | 
    
         
            +
                 *
         
     | 
| 
      
 131 
     | 
    
         
            +
                 * We need to do this because innerHTML in IE does not really parse the nodes.
         
     | 
| 
      
 132 
     | 
    
         
            +
                 **/
         
     | 
| 
      
 133 
     | 
    
         
            +
                 var firstNodeFor = function(parentNode, html) {
         
     | 
| 
      
 134 
     | 
    
         
            +
                  var arr = wrapMap[parentNode.tagName.toLowerCase()] || wrapMap._default;
         
     | 
| 
      
 135 
     | 
    
         
            +
                    var depth = arr[0], start = arr[1], end = arr[2];
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                    var element = document.createElement('div');
         
     | 
| 
      
 138 
     | 
    
         
            +
                  element.innerHTML = start + html + end;
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                  for (var i=0; i<=depth; i++) {
         
     | 
| 
      
 141 
     | 
    
         
            +
                    element = element.firstChild;
         
     | 
| 
      
 142 
     | 
    
         
            +
                  }
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                  return element;
         
     | 
| 
      
 145 
     | 
    
         
            +
                };
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                /**
         
     | 
| 
      
 148 
     | 
    
         
            +
                 * Internet Explorer does not allow setting innerHTML if the first element
         
     | 
| 
      
 149 
     | 
    
         
            +
                 * is a "zero-scope" element. This problem can be worked around by making
         
     | 
| 
      
 150 
     | 
    
         
            +
                 * the first node an invisible text node. We, like Modernizr, use ­
         
     | 
| 
      
 151 
     | 
    
         
            +
                 **/
         
     | 
| 
      
 152 
     | 
    
         
            +
                var startTagFuncWithoutShy = startTagFunc;
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
                startTagFunc = function() {
         
     | 
| 
      
 155 
     | 
    
         
            +
                  return "­" + startTagFuncWithoutShy.call(this);
         
     | 
| 
      
 156 
     | 
    
         
            +
                }
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
                /**
         
     | 
| 
      
 159 
     | 
    
         
            +
                 * In some cases, Internet Explorer can create an anonymous node in
         
     | 
| 
      
 160 
     | 
    
         
            +
                 * the hierarchy with no tagName. You can create this scenario via:
         
     | 
| 
      
 161 
     | 
    
         
            +
                 *
         
     | 
| 
      
 162 
     | 
    
         
            +
                 *     div = document.createElement("div");
         
     | 
| 
      
 163 
     | 
    
         
            +
                 *     div.innerHTML = "<table>­<script></script><tr><td>hi</td></tr></table>";
         
     | 
| 
      
 164 
     | 
    
         
            +
                 *     div.firstChild.firstChild.tagName //=> ""
         
     | 
| 
      
 165 
     | 
    
         
            +
                 *
         
     | 
| 
      
 166 
     | 
    
         
            +
                 * If our script markers are inside such a node, we need to find that
         
     | 
| 
      
 167 
     | 
    
         
            +
                 * node and use *it* as the marker.
         
     | 
| 
      
 168 
     | 
    
         
            +
                 **/
         
     | 
| 
      
 169 
     | 
    
         
            +
                var realNode = function(start) {
         
     | 
| 
      
 170 
     | 
    
         
            +
                  while (start.parentNode.tagName === "") {
         
     | 
| 
      
 171 
     | 
    
         
            +
                    start = start.parentNode;
         
     | 
| 
      
 172 
     | 
    
         
            +
                  }
         
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
      
 174 
     | 
    
         
            +
                  return start;
         
     | 
| 
      
 175 
     | 
    
         
            +
                };
         
     | 
| 
      
 176 
     | 
    
         
            +
             
     | 
| 
      
 177 
     | 
    
         
            +
                /**
         
     | 
| 
      
 178 
     | 
    
         
            +
                 * When automatically adding a tbody, Internet Explorer inserts the
         
     | 
| 
      
 179 
     | 
    
         
            +
                 * tbody immediately before the first <tr>. Other browsers create it
         
     | 
| 
      
 180 
     | 
    
         
            +
                 * before the first node, no matter what.
         
     | 
| 
      
 181 
     | 
    
         
            +
                 *
         
     | 
| 
      
 182 
     | 
    
         
            +
                 * This means the the following code:
         
     | 
| 
      
 183 
     | 
    
         
            +
                 *
         
     | 
| 
      
 184 
     | 
    
         
            +
                 *     div = document.createElement("div");
         
     | 
| 
      
 185 
     | 
    
         
            +
                 *     div.innerHTML = "<table><script id='first'></script><tr><td>hi</td></tr><script id='last'></script></table>
         
     | 
| 
      
 186 
     | 
    
         
            +
                 *
         
     | 
| 
      
 187 
     | 
    
         
            +
                 * Generates the following DOM in IE:
         
     | 
| 
      
 188 
     | 
    
         
            +
                 *
         
     | 
| 
      
 189 
     | 
    
         
            +
                 *     + div
         
     | 
| 
      
 190 
     | 
    
         
            +
                 *       + table
         
     | 
| 
      
 191 
     | 
    
         
            +
                 *         - script id='first'
         
     | 
| 
      
 192 
     | 
    
         
            +
                 *         + tbody
         
     | 
| 
      
 193 
     | 
    
         
            +
                 *           + tr
         
     | 
| 
      
 194 
     | 
    
         
            +
                 *             + td
         
     | 
| 
      
 195 
     | 
    
         
            +
                 *               - "hi"
         
     | 
| 
      
 196 
     | 
    
         
            +
                 *           - script id='last'
         
     | 
| 
      
 197 
     | 
    
         
            +
                 *
         
     | 
| 
      
 198 
     | 
    
         
            +
                 * Which means that the two script tags, even though they were
         
     | 
| 
      
 199 
     | 
    
         
            +
                 * inserted at the same point in the hierarchy in the original
         
     | 
| 
      
 200 
     | 
    
         
            +
                 * HTML, now have different parents.
         
     | 
| 
      
 201 
     | 
    
         
            +
                 *
         
     | 
| 
      
 202 
     | 
    
         
            +
                 * This code reparents the first script tag by making it the tbody's
         
     | 
| 
      
 203 
     | 
    
         
            +
                 * first child.
         
     | 
| 
      
 204 
     | 
    
         
            +
                 **/
         
     | 
| 
      
 205 
     | 
    
         
            +
                var fixParentage = function(start, end) {
         
     | 
| 
      
 206 
     | 
    
         
            +
                  if (start.parentNode !== end.parentNode) {
         
     | 
| 
      
 207 
     | 
    
         
            +
                    end.parentNode.insertBefore(start, end.parentNode.firstChild);
         
     | 
| 
      
 208 
     | 
    
         
            +
                  }
         
     | 
| 
      
 209 
     | 
    
         
            +
                };
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
      
 211 
     | 
    
         
            +
                htmlFunc = function(html) {
         
     | 
| 
      
 212 
     | 
    
         
            +
                  // get the real starting node. see realNode for details.
         
     | 
| 
      
 213 
     | 
    
         
            +
                  var start = realNode(document.getElementById(this.start));
         
     | 
| 
      
 214 
     | 
    
         
            +
                  var end = document.getElementById(this.end);
         
     | 
| 
      
 215 
     | 
    
         
            +
                  var nextSibling;
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
                  // make sure that the start and end nodes share the same
         
     | 
| 
      
 218 
     | 
    
         
            +
                  // parent. If not, fix it.
         
     | 
| 
      
 219 
     | 
    
         
            +
                  fixParentage(start, end);
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
                  var node;
         
     | 
| 
      
 222 
     | 
    
         
            +
             
     | 
| 
      
 223 
     | 
    
         
            +
                  // remove all of the nodes after the starting placeholder and
         
     | 
| 
      
 224 
     | 
    
         
            +
                  // before the ending placeholder.
         
     | 
| 
      
 225 
     | 
    
         
            +
                  node = start.nextSibling;
         
     | 
| 
      
 226 
     | 
    
         
            +
                  while (node) {
         
     | 
| 
      
 227 
     | 
    
         
            +
                    if (node === end) { break; }
         
     | 
| 
      
 228 
     | 
    
         
            +
                    node.parentNode.removeChild(node);
         
     | 
| 
      
 229 
     | 
    
         
            +
                    node = start.nextSibling;
         
     | 
| 
      
 230 
     | 
    
         
            +
                  }
         
     | 
| 
      
 231 
     | 
    
         
            +
             
     | 
| 
      
 232 
     | 
    
         
            +
                  // get the first node for the HTML string, even in cases like
         
     | 
| 
      
 233 
     | 
    
         
            +
                  // tables and lists where a simple innerHTML on a div would
         
     | 
| 
      
 234 
     | 
    
         
            +
                  // swallow some of the content.
         
     | 
| 
      
 235 
     | 
    
         
            +
                  node = firstNodeFor(start.parentNode, html);
         
     | 
| 
      
 236 
     | 
    
         
            +
             
     | 
| 
      
 237 
     | 
    
         
            +
                  // copy the nodes for the HTML between the starting and ending
         
     | 
| 
      
 238 
     | 
    
         
            +
                  // placeholder.
         
     | 
| 
      
 239 
     | 
    
         
            +
                  while (node) {
         
     | 
| 
      
 240 
     | 
    
         
            +
                    nextSibling = node.nextSibling;
         
     | 
| 
      
 241 
     | 
    
         
            +
                    end.parentNode.insertBefore(node, end);
         
     | 
| 
      
 242 
     | 
    
         
            +
                    node = nextSibling;
         
     | 
| 
      
 243 
     | 
    
         
            +
                  }
         
     | 
| 
      
 244 
     | 
    
         
            +
                };
         
     | 
| 
      
 245 
     | 
    
         
            +
             
     | 
| 
      
 246 
     | 
    
         
            +
                // remove the nodes in the DOM representing this metamorph.
         
     | 
| 
      
 247 
     | 
    
         
            +
                //
         
     | 
| 
      
 248 
     | 
    
         
            +
                // this includes the starting and ending placeholders.
         
     | 
| 
      
 249 
     | 
    
         
            +
                removeFunc = function() {
         
     | 
| 
      
 250 
     | 
    
         
            +
                  var start = realNode(document.getElementById(this.start));
         
     | 
| 
      
 251 
     | 
    
         
            +
                  var end = document.getElementById(this.end);
         
     | 
| 
      
 252 
     | 
    
         
            +
             
     | 
| 
      
 253 
     | 
    
         
            +
                  this.html('');
         
     | 
| 
      
 254 
     | 
    
         
            +
                  start.parentNode.removeChild(start);
         
     | 
| 
      
 255 
     | 
    
         
            +
                  end.parentNode.removeChild(end);
         
     | 
| 
      
 256 
     | 
    
         
            +
                };
         
     | 
| 
      
 257 
     | 
    
         
            +
             
     | 
| 
      
 258 
     | 
    
         
            +
                appendToFunc = function(parentNode) {
         
     | 
| 
      
 259 
     | 
    
         
            +
                  var node = firstNodeFor(parentNode, this.outerHTML());
         
     | 
| 
      
 260 
     | 
    
         
            +
             
     | 
| 
      
 261 
     | 
    
         
            +
                  while (node) {
         
     | 
| 
      
 262 
     | 
    
         
            +
                    nextSibling = node.nextSibling;
         
     | 
| 
      
 263 
     | 
    
         
            +
                    parentNode.appendChild(node);
         
     | 
| 
      
 264 
     | 
    
         
            +
                    node = nextSibling;
         
     | 
| 
      
 265 
     | 
    
         
            +
                  }
         
     | 
| 
      
 266 
     | 
    
         
            +
                };
         
     | 
| 
      
 267 
     | 
    
         
            +
              }
         
     | 
| 
      
 268 
     | 
    
         
            +
             
     | 
| 
      
 269 
     | 
    
         
            +
              Metamorph.prototype.html = function(html) {
         
     | 
| 
      
 270 
     | 
    
         
            +
                this.checkRemoved();
         
     | 
| 
      
 271 
     | 
    
         
            +
                if (html === undefined) { return this.innerHTML; }
         
     | 
| 
      
 272 
     | 
    
         
            +
             
     | 
| 
      
 273 
     | 
    
         
            +
                htmlFunc.call(this, html);
         
     | 
| 
      
 274 
     | 
    
         
            +
             
     | 
| 
      
 275 
     | 
    
         
            +
                this.innerHTML = html;
         
     | 
| 
      
 276 
     | 
    
         
            +
              };
         
     | 
| 
      
 277 
     | 
    
         
            +
             
     | 
| 
      
 278 
     | 
    
         
            +
              Metamorph.prototype.remove = removeFunc;
         
     | 
| 
      
 279 
     | 
    
         
            +
              Metamorph.prototype.outerHTML = outerHTMLFunc;
         
     | 
| 
      
 280 
     | 
    
         
            +
              Metamorph.prototype.appendTo = appendToFunc;
         
     | 
| 
      
 281 
     | 
    
         
            +
              Metamorph.prototype.startTag = startTagFunc;
         
     | 
| 
      
 282 
     | 
    
         
            +
              Metamorph.prototype.endTag = endTagFunc;
         
     | 
| 
      
 283 
     | 
    
         
            +
             
     | 
| 
      
 284 
     | 
    
         
            +
              Metamorph.prototype.isRemoved = function() {
         
     | 
| 
      
 285 
     | 
    
         
            +
                var before = document.getElementById(this.start);
         
     | 
| 
      
 286 
     | 
    
         
            +
                var after = document.getElementById(this.end);
         
     | 
| 
      
 287 
     | 
    
         
            +
             
     | 
| 
      
 288 
     | 
    
         
            +
                return !before || !after;
         
     | 
| 
      
 289 
     | 
    
         
            +
              };
         
     | 
| 
      
 290 
     | 
    
         
            +
             
     | 
| 
      
 291 
     | 
    
         
            +
              Metamorph.prototype.checkRemoved = function() {
         
     | 
| 
      
 292 
     | 
    
         
            +
                if (this.isRemoved()) {
         
     | 
| 
      
 293 
     | 
    
         
            +
                  throw new Error("Cannot perform operations on a Metamorph that is not in the DOM.");
         
     | 
| 
      
 294 
     | 
    
         
            +
                }
         
     | 
| 
      
 295 
     | 
    
         
            +
              };
         
     | 
| 
      
 296 
     | 
    
         
            +
             
     | 
| 
      
 297 
     | 
    
         
            +
              window.Metamorph = Metamorph;
         
     | 
| 
      
 298 
     | 
    
         
            +
            })(this);
         
     | 
| 
         @@ -0,0 +1,549 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            // ==========================================================================
         
     | 
| 
      
 2 
     | 
    
         
            +
            // Project:   SproutCore - JavaScript Application Framework
         
     | 
| 
      
 3 
     | 
    
         
            +
            // Copyright: ©2006-2011 Strobe Inc. and contributors.
         
     | 
| 
      
 4 
     | 
    
         
            +
            //            Portions ©2008-2011 Apple Inc. All rights reserved.
         
     | 
| 
      
 5 
     | 
    
         
            +
            // License:   Licensed under MIT license (see license.js)
         
     | 
| 
      
 6 
     | 
    
         
            +
            // ==========================================================================
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            (function() {
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            var get = SC.get, set = SC.set;
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            /**
         
     | 
| 
      
 13 
     | 
    
         
            +
              Wether the browser supports HTML5 history.
         
     | 
| 
      
 14 
     | 
    
         
            +
            */
         
     | 
| 
      
 15 
     | 
    
         
            +
            var supportsHistory = !!(window.history && window.history.pushState);
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            /**
         
     | 
| 
      
 18 
     | 
    
         
            +
              Wether the browser supports the hashchange event.
         
     | 
| 
      
 19 
     | 
    
         
            +
            */
         
     | 
| 
      
 20 
     | 
    
         
            +
            var supportsHashChange = ('onhashchange' in window) && (document.documentMode === undefined || document.documentMode > 7);
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            /**
         
     | 
| 
      
 23 
     | 
    
         
            +
              @class
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              Route is a class used internally by SC.routes. The routes defined by your
         
     | 
| 
      
 26 
     | 
    
         
            +
              application are stored in a tree structure, and this is the class for the
         
     | 
| 
      
 27 
     | 
    
         
            +
              nodes.
         
     | 
| 
      
 28 
     | 
    
         
            +
            */
         
     | 
| 
      
 29 
     | 
    
         
            +
            var Route = SC.Object.extend(
         
     | 
| 
      
 30 
     | 
    
         
            +
            /** @scope Route.prototype */ {
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              target: null,
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              method: null,
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              staticRoutes: null,
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              dynamicRoutes: null,
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              wildcardRoutes: null,
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
              add: function(parts, target, method) {
         
     | 
| 
      
 43 
     | 
    
         
            +
                var part, nextRoute;
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                // clone the parts array because we are going to alter it
         
     | 
| 
      
 46 
     | 
    
         
            +
                parts = SC.copy(parts);
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                if (!parts || parts.length === 0) {
         
     | 
| 
      
 49 
     | 
    
         
            +
                  this.target = target;
         
     | 
| 
      
 50 
     | 
    
         
            +
                  this.method = method;
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                } else {
         
     | 
| 
      
 53 
     | 
    
         
            +
                  part = parts.shift();
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                  // there are 3 types of routes
         
     | 
| 
      
 56 
     | 
    
         
            +
                  switch (part.slice(0, 1)) {
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                  // 1. dynamic routes
         
     | 
| 
      
 59 
     | 
    
         
            +
                  case ':':
         
     | 
| 
      
 60 
     | 
    
         
            +
                    part = part.slice(1, part.length);
         
     | 
| 
      
 61 
     | 
    
         
            +
                    if (!this.dynamicRoutes) this.dynamicRoutes = {};
         
     | 
| 
      
 62 
     | 
    
         
            +
                    if (!this.dynamicRoutes[part]) this.dynamicRoutes[part] = this.constructor.create();
         
     | 
| 
      
 63 
     | 
    
         
            +
                    nextRoute = this.dynamicRoutes[part];
         
     | 
| 
      
 64 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                  // 2. wildcard routes
         
     | 
| 
      
 67 
     | 
    
         
            +
                  case '*':
         
     | 
| 
      
 68 
     | 
    
         
            +
                    part = part.slice(1, part.length);
         
     | 
| 
      
 69 
     | 
    
         
            +
                    if (!this.wildcardRoutes) this.wildcardRoutes = {};
         
     | 
| 
      
 70 
     | 
    
         
            +
                    nextRoute = this.wildcardRoutes[part] = this.constructor.create();
         
     | 
| 
      
 71 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  // 3. static routes
         
     | 
| 
      
 74 
     | 
    
         
            +
                  default:
         
     | 
| 
      
 75 
     | 
    
         
            +
                    if (!this.staticRoutes) this.staticRoutes = {};
         
     | 
| 
      
 76 
     | 
    
         
            +
                    if (!this.staticRoutes[part]) this.staticRoutes[part] = this.constructor.create();
         
     | 
| 
      
 77 
     | 
    
         
            +
                    nextRoute = this.staticRoutes[part];
         
     | 
| 
      
 78 
     | 
    
         
            +
                  }
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                  // recursively add the rest of the route
         
     | 
| 
      
 81 
     | 
    
         
            +
                  if (nextRoute) nextRoute.add(parts, target, method);
         
     | 
| 
      
 82 
     | 
    
         
            +
                }
         
     | 
| 
      
 83 
     | 
    
         
            +
              },
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
              routeForParts: function(parts, params) {
         
     | 
| 
      
 86 
     | 
    
         
            +
                var part, key, route;
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                // clone the parts array because we are going to alter it
         
     | 
| 
      
 89 
     | 
    
         
            +
                parts = SC.copy(parts);
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                // if parts is empty, we are done
         
     | 
| 
      
 92 
     | 
    
         
            +
                if (!parts || parts.length === 0) {
         
     | 
| 
      
 93 
     | 
    
         
            +
                  return this.method ? this : null;
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                } else {
         
     | 
| 
      
 96 
     | 
    
         
            +
                  part = parts.shift();
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                  // try to match a static route
         
     | 
| 
      
 99 
     | 
    
         
            +
                  if (this.staticRoutes && this.staticRoutes[part]) {
         
     | 
| 
      
 100 
     | 
    
         
            +
                    return this.staticRoutes[part].routeForParts(parts, params);
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                    // else, try to match a dynamic route
         
     | 
| 
      
 105 
     | 
    
         
            +
                    for (key in this.dynamicRoutes) {
         
     | 
| 
      
 106 
     | 
    
         
            +
                      route = this.dynamicRoutes[key].routeForParts(parts, params);
         
     | 
| 
      
 107 
     | 
    
         
            +
                      if (route) {
         
     | 
| 
      
 108 
     | 
    
         
            +
                        params[key] = part;
         
     | 
| 
      
 109 
     | 
    
         
            +
                        return route;
         
     | 
| 
      
 110 
     | 
    
         
            +
                      }
         
     | 
| 
      
 111 
     | 
    
         
            +
                    }
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                    // else, try to match a wilcard route
         
     | 
| 
      
 114 
     | 
    
         
            +
                    for (key in this.wildcardRoutes) {
         
     | 
| 
      
 115 
     | 
    
         
            +
                      parts.unshift(part);
         
     | 
| 
      
 116 
     | 
    
         
            +
                      params[key] = parts.join('/');
         
     | 
| 
      
 117 
     | 
    
         
            +
                      return this.wildcardRoutes[key].routeForParts(null, params);
         
     | 
| 
      
 118 
     | 
    
         
            +
                    }
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                    // if nothing was found, it means that there is no match
         
     | 
| 
      
 121 
     | 
    
         
            +
                    return null;
         
     | 
| 
      
 122 
     | 
    
         
            +
                  }
         
     | 
| 
      
 123 
     | 
    
         
            +
                }
         
     | 
| 
      
 124 
     | 
    
         
            +
              }
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
            });
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
            /**
         
     | 
| 
      
 129 
     | 
    
         
            +
              @class
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
              SC.routes manages the browser location. You can change the hash part of the
         
     | 
| 
      
 132 
     | 
    
         
            +
              current location. The following code
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                  SC.routes.set('location', 'notes/edit/4');
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
              will change the location to http://domain.tld/my_app#notes/edit/4. Adding
         
     | 
| 
      
 137 
     | 
    
         
            +
              routes will register a handler that will be called whenever the location
         
     | 
| 
      
 138 
     | 
    
         
            +
              changes and matches the route:
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                  SC.routes.add(':controller/:action/:id', MyApp, MyApp.route);
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
              You can pass additional parameters in the location hash that will be relayed
         
     | 
| 
      
 143 
     | 
    
         
            +
              to the route handler:
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                  SC.routes.set('location', 'notes/show/4?format=xml&language=fr');
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
              The syntax for the location hash is described in the location property
         
     | 
| 
      
 148 
     | 
    
         
            +
              documentation, and the syntax for adding handlers is described in the
         
     | 
| 
      
 149 
     | 
    
         
            +
              add method documentation.
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
      
 151 
     | 
    
         
            +
              Browsers keep track of the locations in their history, so when the user
         
     | 
| 
      
 152 
     | 
    
         
            +
              presses the 'back' or 'forward' button, the location is changed, SC.route
         
     | 
| 
      
 153 
     | 
    
         
            +
              catches it and calls your handler. Except for Internet Explorer versions 7
         
     | 
| 
      
 154 
     | 
    
         
            +
              and earlier, which do not modify the history stack when the location hash
         
     | 
| 
      
 155 
     | 
    
         
            +
              changes.
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
              SC.routes also supports HTML5 history, which uses a '/' instead of a '#'
         
     | 
| 
      
 158 
     | 
    
         
            +
              in the URLs, so that all your website's URLs are consistent.
         
     | 
| 
      
 159 
     | 
    
         
            +
            */
         
     | 
| 
      
 160 
     | 
    
         
            +
            var routes = SC.routes = SC.Object.create(
         
     | 
| 
      
 161 
     | 
    
         
            +
              /** @scope SC.routes.prototype */{
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
              /**
         
     | 
| 
      
 164 
     | 
    
         
            +
                Set this property to true if you want to use HTML5 history, if available on
         
     | 
| 
      
 165 
     | 
    
         
            +
                the browser, instead of the location hash.
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                HTML 5 history uses the history.pushState method and the window's popstate
         
     | 
| 
      
 168 
     | 
    
         
            +
                event.
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                By default it is false, so your URLs will look like:
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
                    http://domain.tld/my_app#notes/edit/4
         
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
      
 174 
     | 
    
         
            +
                If set to true and the browser supports pushState(), your URLs will look
         
     | 
| 
      
 175 
     | 
    
         
            +
                like:
         
     | 
| 
      
 176 
     | 
    
         
            +
             
     | 
| 
      
 177 
     | 
    
         
            +
                    http://domain.tld/my_app/notes/edit/4
         
     | 
| 
      
 178 
     | 
    
         
            +
             
     | 
| 
      
 179 
     | 
    
         
            +
                You will also need to make sure that baseURI is properly configured, as
         
     | 
| 
      
 180 
     | 
    
         
            +
                well as your server so that your routes are properly pointing to your
         
     | 
| 
      
 181 
     | 
    
         
            +
                SproutCore application.
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
                @see http://dev.w3.org/html5/spec/history.html#the-history-interface
         
     | 
| 
      
 184 
     | 
    
         
            +
                @property
         
     | 
| 
      
 185 
     | 
    
         
            +
                @type {Boolean}
         
     | 
| 
      
 186 
     | 
    
         
            +
              */
         
     | 
| 
      
 187 
     | 
    
         
            +
              wantsHistory: false,
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
              /**
         
     | 
| 
      
 190 
     | 
    
         
            +
                A read-only boolean indicating whether or not HTML5 history is used. Based
         
     | 
| 
      
 191 
     | 
    
         
            +
                on the value of wantsHistory and the browser's support for pushState.
         
     | 
| 
      
 192 
     | 
    
         
            +
             
     | 
| 
      
 193 
     | 
    
         
            +
                @see wantsHistory
         
     | 
| 
      
 194 
     | 
    
         
            +
                @property
         
     | 
| 
      
 195 
     | 
    
         
            +
                @type {Boolean}
         
     | 
| 
      
 196 
     | 
    
         
            +
              */
         
     | 
| 
      
 197 
     | 
    
         
            +
              usesHistory: null,
         
     | 
| 
      
 198 
     | 
    
         
            +
             
     | 
| 
      
 199 
     | 
    
         
            +
              /**
         
     | 
| 
      
 200 
     | 
    
         
            +
                The base URI used to resolve routes (which are relative URLs). Only used
         
     | 
| 
      
 201 
     | 
    
         
            +
                when usesHistory is equal to true.
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
                The build tools automatically configure this value if you have the
         
     | 
| 
      
 204 
     | 
    
         
            +
                html5_history option activated in the Buildfile:
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
                    config :my_app, :html5_history => true
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
                Alternatively, it uses by default the value of the href attribute of the
         
     | 
| 
      
 209 
     | 
    
         
            +
                <base> tag of the HTML document. For example:
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
      
 211 
     | 
    
         
            +
                    <base href="http://domain.tld/my_app">
         
     | 
| 
      
 212 
     | 
    
         
            +
             
     | 
| 
      
 213 
     | 
    
         
            +
                The value can also be customized before or during the exectution of the
         
     | 
| 
      
 214 
     | 
    
         
            +
                main() method.
         
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
      
 216 
     | 
    
         
            +
                @see http://www.w3.org/TR/html5/semantics.html#the-base-element
         
     | 
| 
      
 217 
     | 
    
         
            +
                @property
         
     | 
| 
      
 218 
     | 
    
         
            +
                @type {String}
         
     | 
| 
      
 219 
     | 
    
         
            +
              */
         
     | 
| 
      
 220 
     | 
    
         
            +
              baseURI: document.baseURI,
         
     | 
| 
      
 221 
     | 
    
         
            +
             
     | 
| 
      
 222 
     | 
    
         
            +
              /** @private
         
     | 
| 
      
 223 
     | 
    
         
            +
                A boolean value indicating whether or not the ping method has been called
         
     | 
| 
      
 224 
     | 
    
         
            +
                to setup the SC.routes.
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
                @property
         
     | 
| 
      
 227 
     | 
    
         
            +
                @type {Boolean}
         
     | 
| 
      
 228 
     | 
    
         
            +
              */
         
     | 
| 
      
 229 
     | 
    
         
            +
              _didSetup: false,
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
      
 231 
     | 
    
         
            +
              /** @private
         
     | 
| 
      
 232 
     | 
    
         
            +
                Internal representation of the current location hash.
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
                @property
         
     | 
| 
      
 235 
     | 
    
         
            +
                @type {String}
         
     | 
| 
      
 236 
     | 
    
         
            +
              */
         
     | 
| 
      
 237 
     | 
    
         
            +
              _location: null,
         
     | 
| 
      
 238 
     | 
    
         
            +
             
     | 
| 
      
 239 
     | 
    
         
            +
              /** @private
         
     | 
| 
      
 240 
     | 
    
         
            +
                Routes are stored in a tree structure, this is the root node.
         
     | 
| 
      
 241 
     | 
    
         
            +
             
     | 
| 
      
 242 
     | 
    
         
            +
                @property
         
     | 
| 
      
 243 
     | 
    
         
            +
                @type {Route}
         
     | 
| 
      
 244 
     | 
    
         
            +
              */
         
     | 
| 
      
 245 
     | 
    
         
            +
              _firstRoute: null,
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
      
 247 
     | 
    
         
            +
              /** @private
         
     | 
| 
      
 248 
     | 
    
         
            +
                An internal reference to the Route class.
         
     | 
| 
      
 249 
     | 
    
         
            +
             
     | 
| 
      
 250 
     | 
    
         
            +
                @property
         
     | 
| 
      
 251 
     | 
    
         
            +
              */
         
     | 
| 
      
 252 
     | 
    
         
            +
              _Route: Route,
         
     | 
| 
      
 253 
     | 
    
         
            +
             
     | 
| 
      
 254 
     | 
    
         
            +
              /** @private
         
     | 
| 
      
 255 
     | 
    
         
            +
                Internal method used to extract and merge the parameters of a URL.
         
     | 
| 
      
 256 
     | 
    
         
            +
             
     | 
| 
      
 257 
     | 
    
         
            +
                @returns {Hash}
         
     | 
| 
      
 258 
     | 
    
         
            +
              */
         
     | 
| 
      
 259 
     | 
    
         
            +
              _extractParametersAndRoute: function(obj) {
         
     | 
| 
      
 260 
     | 
    
         
            +
                var params = {},
         
     | 
| 
      
 261 
     | 
    
         
            +
                    route = obj.route || '',
         
     | 
| 
      
 262 
     | 
    
         
            +
                    separator, parts, i, len, crumbs, key;
         
     | 
| 
      
 263 
     | 
    
         
            +
             
     | 
| 
      
 264 
     | 
    
         
            +
                separator = (route.indexOf('?') < 0 && route.indexOf('&') >= 0) ? '&' : '?';
         
     | 
| 
      
 265 
     | 
    
         
            +
                parts = route.split(separator);
         
     | 
| 
      
 266 
     | 
    
         
            +
                route = parts[0];
         
     | 
| 
      
 267 
     | 
    
         
            +
                if (parts.length === 1) {
         
     | 
| 
      
 268 
     | 
    
         
            +
                  parts = [];
         
     | 
| 
      
 269 
     | 
    
         
            +
                } else if (parts.length === 2) {
         
     | 
| 
      
 270 
     | 
    
         
            +
                  parts = parts[1].split('&');
         
     | 
| 
      
 271 
     | 
    
         
            +
                } else if (parts.length > 2) {
         
     | 
| 
      
 272 
     | 
    
         
            +
                  parts.shift();
         
     | 
| 
      
 273 
     | 
    
         
            +
                }
         
     | 
| 
      
 274 
     | 
    
         
            +
             
     | 
| 
      
 275 
     | 
    
         
            +
                // extract the parameters from the route string
         
     | 
| 
      
 276 
     | 
    
         
            +
                len = parts.length;
         
     | 
| 
      
 277 
     | 
    
         
            +
                for (i = 0; i < len; ++i) {
         
     | 
| 
      
 278 
     | 
    
         
            +
                  crumbs = parts[i].split('=');
         
     | 
| 
      
 279 
     | 
    
         
            +
                  params[crumbs[0]] = crumbs[1];
         
     | 
| 
      
 280 
     | 
    
         
            +
                }
         
     | 
| 
      
 281 
     | 
    
         
            +
             
     | 
| 
      
 282 
     | 
    
         
            +
                // overlay any parameter passed in obj
         
     | 
| 
      
 283 
     | 
    
         
            +
                for (key in obj) {
         
     | 
| 
      
 284 
     | 
    
         
            +
                  if (obj.hasOwnProperty(key) && key !== 'route') {
         
     | 
| 
      
 285 
     | 
    
         
            +
                    params[key] = '' + obj[key];
         
     | 
| 
      
 286 
     | 
    
         
            +
                  }
         
     | 
| 
      
 287 
     | 
    
         
            +
                }
         
     | 
| 
      
 288 
     | 
    
         
            +
             
     | 
| 
      
 289 
     | 
    
         
            +
                // build the route
         
     | 
| 
      
 290 
     | 
    
         
            +
                parts = [];
         
     | 
| 
      
 291 
     | 
    
         
            +
                for (key in params) {
         
     | 
| 
      
 292 
     | 
    
         
            +
                  parts.push([key, params[key]].join('='));
         
     | 
| 
      
 293 
     | 
    
         
            +
                }
         
     | 
| 
      
 294 
     | 
    
         
            +
                params.params = separator + parts.join('&');
         
     | 
| 
      
 295 
     | 
    
         
            +
                params.route = route;
         
     | 
| 
      
 296 
     | 
    
         
            +
             
     | 
| 
      
 297 
     | 
    
         
            +
                return params;
         
     | 
| 
      
 298 
     | 
    
         
            +
              },
         
     | 
| 
      
 299 
     | 
    
         
            +
             
     | 
| 
      
 300 
     | 
    
         
            +
              /**
         
     | 
| 
      
 301 
     | 
    
         
            +
                The current location hash. It is the part in the browser's location after
         
     | 
| 
      
 302 
     | 
    
         
            +
                the '#' mark.
         
     | 
| 
      
 303 
     | 
    
         
            +
             
     | 
| 
      
 304 
     | 
    
         
            +
                The following code
         
     | 
| 
      
 305 
     | 
    
         
            +
             
     | 
| 
      
 306 
     | 
    
         
            +
                    SC.routes.set('location', 'notes/edit/4');
         
     | 
| 
      
 307 
     | 
    
         
            +
             
     | 
| 
      
 308 
     | 
    
         
            +
                will change the location to http://domain.tld/my_app#notes/edit/4 and call
         
     | 
| 
      
 309 
     | 
    
         
            +
                the correct route handler if it has been registered with the add method.
         
     | 
| 
      
 310 
     | 
    
         
            +
             
     | 
| 
      
 311 
     | 
    
         
            +
                You can also pass additional parameters. They will be relayed to the route
         
     | 
| 
      
 312 
     | 
    
         
            +
                handler. For example, the following code
         
     | 
| 
      
 313 
     | 
    
         
            +
             
     | 
| 
      
 314 
     | 
    
         
            +
                    SC.routes.add(':controller/:action/:id', MyApp, MyApp.route);
         
     | 
| 
      
 315 
     | 
    
         
            +
                    SC.routes.set('location', 'notes/show/4?format=xml&language=fr');
         
     | 
| 
      
 316 
     | 
    
         
            +
             
     | 
| 
      
 317 
     | 
    
         
            +
                will change the location to
         
     | 
| 
      
 318 
     | 
    
         
            +
                http://domain.tld/my_app#notes/show/4?format=xml&language=fr and call the
         
     | 
| 
      
 319 
     | 
    
         
            +
                MyApp.route method with the following argument:
         
     | 
| 
      
 320 
     | 
    
         
            +
             
     | 
| 
      
 321 
     | 
    
         
            +
                    { route: 'notes/show/4',
         
     | 
| 
      
 322 
     | 
    
         
            +
                      params: '?format=xml&language=fr',
         
     | 
| 
      
 323 
     | 
    
         
            +
                      controller: 'notes',
         
     | 
| 
      
 324 
     | 
    
         
            +
                      action: 'show',
         
     | 
| 
      
 325 
     | 
    
         
            +
                      id: '4',
         
     | 
| 
      
 326 
     | 
    
         
            +
                      format: 'xml',
         
     | 
| 
      
 327 
     | 
    
         
            +
                      language: 'fr' }
         
     | 
| 
      
 328 
     | 
    
         
            +
             
     | 
| 
      
 329 
     | 
    
         
            +
                The location can also be set with a hash, the following code
         
     | 
| 
      
 330 
     | 
    
         
            +
             
     | 
| 
      
 331 
     | 
    
         
            +
                    SC.routes.set('location',
         
     | 
| 
      
 332 
     | 
    
         
            +
                      { route: 'notes/edit/4', format: 'xml', language: 'fr' });
         
     | 
| 
      
 333 
     | 
    
         
            +
             
     | 
| 
      
 334 
     | 
    
         
            +
                will change the location to
         
     | 
| 
      
 335 
     | 
    
         
            +
                http://domain.tld/my_app#notes/show/4?format=xml&language=fr.
         
     | 
| 
      
 336 
     | 
    
         
            +
             
     | 
| 
      
 337 
     | 
    
         
            +
                The 'notes/show/4&format=xml&language=fr' syntax for passing parameters,
         
     | 
| 
      
 338 
     | 
    
         
            +
                using a '&' instead of a '?', as used in SproutCore 1.0 is still supported.
         
     | 
| 
      
 339 
     | 
    
         
            +
             
     | 
| 
      
 340 
     | 
    
         
            +
                @property
         
     | 
| 
      
 341 
     | 
    
         
            +
                @type {String}
         
     | 
| 
      
 342 
     | 
    
         
            +
              */
         
     | 
| 
      
 343 
     | 
    
         
            +
              location: function(key, value) {
         
     | 
| 
      
 344 
     | 
    
         
            +
                this._skipRoute = false;
         
     | 
| 
      
 345 
     | 
    
         
            +
                return this._extractLocation(key, value);
         
     | 
| 
      
 346 
     | 
    
         
            +
              }.property(),
         
     | 
| 
      
 347 
     | 
    
         
            +
             
     | 
| 
      
 348 
     | 
    
         
            +
              _extractLocation: function(key, value) {
         
     | 
| 
      
 349 
     | 
    
         
            +
                var crumbs, encodedValue;
         
     | 
| 
      
 350 
     | 
    
         
            +
             
     | 
| 
      
 351 
     | 
    
         
            +
                if (value !== undefined) {
         
     | 
| 
      
 352 
     | 
    
         
            +
                  if (value === null) {
         
     | 
| 
      
 353 
     | 
    
         
            +
                    value = '';
         
     | 
| 
      
 354 
     | 
    
         
            +
                  }
         
     | 
| 
      
 355 
     | 
    
         
            +
             
     | 
| 
      
 356 
     | 
    
         
            +
                  if (typeof(value) === 'object') {
         
     | 
| 
      
 357 
     | 
    
         
            +
                    crumbs = this._extractParametersAndRoute(value);
         
     | 
| 
      
 358 
     | 
    
         
            +
                    value = crumbs.route + crumbs.params;
         
     | 
| 
      
 359 
     | 
    
         
            +
                  }
         
     | 
| 
      
 360 
     | 
    
         
            +
             
     | 
| 
      
 361 
     | 
    
         
            +
                  if (!SC.empty(value) || (this._location && this._location !== value)) {
         
     | 
| 
      
 362 
     | 
    
         
            +
                    encodedValue = encodeURI(value);
         
     | 
| 
      
 363 
     | 
    
         
            +
             
     | 
| 
      
 364 
     | 
    
         
            +
                    if (this.usesHistory) {
         
     | 
| 
      
 365 
     | 
    
         
            +
                      if (encodedValue.length > 0) {
         
     | 
| 
      
 366 
     | 
    
         
            +
                        encodedValue = '/' + encodedValue;
         
     | 
| 
      
 367 
     | 
    
         
            +
                      }
         
     | 
| 
      
 368 
     | 
    
         
            +
                      window.history.pushState(null, null, get(this, 'baseURI') + encodedValue);
         
     | 
| 
      
 369 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 370 
     | 
    
         
            +
                      window.location.hash = encodedValue;
         
     | 
| 
      
 371 
     | 
    
         
            +
                    }
         
     | 
| 
      
 372 
     | 
    
         
            +
                  }
         
     | 
| 
      
 373 
     | 
    
         
            +
             
     | 
| 
      
 374 
     | 
    
         
            +
                  this._location = value;
         
     | 
| 
      
 375 
     | 
    
         
            +
                }
         
     | 
| 
      
 376 
     | 
    
         
            +
             
     | 
| 
      
 377 
     | 
    
         
            +
                return this._location;
         
     | 
| 
      
 378 
     | 
    
         
            +
              },
         
     | 
| 
      
 379 
     | 
    
         
            +
             
     | 
| 
      
 380 
     | 
    
         
            +
              /**
         
     | 
| 
      
 381 
     | 
    
         
            +
                You usually don't need to call this method. It is done automatically after
         
     | 
| 
      
 382 
     | 
    
         
            +
                the application has been initialized.
         
     | 
| 
      
 383 
     | 
    
         
            +
             
     | 
| 
      
 384 
     | 
    
         
            +
                It registers for the hashchange event if available. If not, it creates a
         
     | 
| 
      
 385 
     | 
    
         
            +
                timer that looks for location changes every 150ms.
         
     | 
| 
      
 386 
     | 
    
         
            +
              */
         
     | 
| 
      
 387 
     | 
    
         
            +
              ping: function() {
         
     | 
| 
      
 388 
     | 
    
         
            +
                var that;
         
     | 
| 
      
 389 
     | 
    
         
            +
             
     | 
| 
      
 390 
     | 
    
         
            +
                if (!this._didSetup) {
         
     | 
| 
      
 391 
     | 
    
         
            +
                  this._didSetup = true;
         
     | 
| 
      
 392 
     | 
    
         
            +
             
     | 
| 
      
 393 
     | 
    
         
            +
                  if (get(this, 'wantsHistory') && supportsHistory) {
         
     | 
| 
      
 394 
     | 
    
         
            +
                    this.usesHistory = true;
         
     | 
| 
      
 395 
     | 
    
         
            +
             
     | 
| 
      
 396 
     | 
    
         
            +
                    popState();
         
     | 
| 
      
 397 
     | 
    
         
            +
                    jQuery(window).bind('popstate', popState);
         
     | 
| 
      
 398 
     | 
    
         
            +
             
     | 
| 
      
 399 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 400 
     | 
    
         
            +
                    this.usesHistory = false;
         
     | 
| 
      
 401 
     | 
    
         
            +
             
     | 
| 
      
 402 
     | 
    
         
            +
                    if (supportsHashChange) {
         
     | 
| 
      
 403 
     | 
    
         
            +
                      hashChange();
         
     | 
| 
      
 404 
     | 
    
         
            +
                      jQuery(window).bind('hashchange', hashChange);
         
     | 
| 
      
 405 
     | 
    
         
            +
             
     | 
| 
      
 406 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 407 
     | 
    
         
            +
                      // we don't use a SC.Timer because we don't want
         
     | 
| 
      
 408 
     | 
    
         
            +
                      // a run loop to be triggered at each ping
         
     | 
| 
      
 409 
     | 
    
         
            +
                      that = this;
         
     | 
| 
      
 410 
     | 
    
         
            +
                      this._invokeHashChange = function() {
         
     | 
| 
      
 411 
     | 
    
         
            +
                        that.hashChange();
         
     | 
| 
      
 412 
     | 
    
         
            +
                        setTimeout(that._invokeHashChange, 100);
         
     | 
| 
      
 413 
     | 
    
         
            +
                      };
         
     | 
| 
      
 414 
     | 
    
         
            +
                      this._invokeHashChange();
         
     | 
| 
      
 415 
     | 
    
         
            +
                    }
         
     | 
| 
      
 416 
     | 
    
         
            +
                  }
         
     | 
| 
      
 417 
     | 
    
         
            +
                }
         
     | 
| 
      
 418 
     | 
    
         
            +
              },
         
     | 
| 
      
 419 
     | 
    
         
            +
             
     | 
| 
      
 420 
     | 
    
         
            +
              /**
         
     | 
| 
      
 421 
     | 
    
         
            +
                Adds a route handler. Routes have the following format:
         
     | 
| 
      
 422 
     | 
    
         
            +
             
     | 
| 
      
 423 
     | 
    
         
            +
                 - 'users/show/5' is a static route and only matches this exact string,
         
     | 
| 
      
 424 
     | 
    
         
            +
                 - ':action/:controller/:id' is a dynamic route and the handler will be
         
     | 
| 
      
 425 
     | 
    
         
            +
                    called with the 'action', 'controller' and 'id' parameters passed in a
         
     | 
| 
      
 426 
     | 
    
         
            +
                    hash,
         
     | 
| 
      
 427 
     | 
    
         
            +
                 - '*url' is a wildcard route, it matches the whole route and the handler
         
     | 
| 
      
 428 
     | 
    
         
            +
                    will be called with the 'url' parameter passed in a hash.
         
     | 
| 
      
 429 
     | 
    
         
            +
             
     | 
| 
      
 430 
     | 
    
         
            +
                Route types can be combined, the following are valid routes:
         
     | 
| 
      
 431 
     | 
    
         
            +
             
     | 
| 
      
 432 
     | 
    
         
            +
                 - 'users/:action/:id'
         
     | 
| 
      
 433 
     | 
    
         
            +
                 - ':controller/show/:id'
         
     | 
| 
      
 434 
     | 
    
         
            +
                 - ':controller/ *url' (ignore the space, because of jslint)
         
     | 
| 
      
 435 
     | 
    
         
            +
             
     | 
| 
      
 436 
     | 
    
         
            +
                @param {String} route the route to be registered
         
     | 
| 
      
 437 
     | 
    
         
            +
                @param {Object} target the object on which the method will be called, or
         
     | 
| 
      
 438 
     | 
    
         
            +
                  directly the function to be called to handle the route
         
     | 
| 
      
 439 
     | 
    
         
            +
                @param {Function} method the method to be called on target to handle the
         
     | 
| 
      
 440 
     | 
    
         
            +
                  route, can be a function or a string
         
     | 
| 
      
 441 
     | 
    
         
            +
              */
         
     | 
| 
      
 442 
     | 
    
         
            +
              add: function(route, target, method) {
         
     | 
| 
      
 443 
     | 
    
         
            +
                if (!this._didSetup) {
         
     | 
| 
      
 444 
     | 
    
         
            +
                  SC.run.once(this, 'ping');
         
     | 
| 
      
 445 
     | 
    
         
            +
                }
         
     | 
| 
      
 446 
     | 
    
         
            +
             
     | 
| 
      
 447 
     | 
    
         
            +
                if (method === undefined && SC.typeOf(target) === 'function') {
         
     | 
| 
      
 448 
     | 
    
         
            +
                  method = target;
         
     | 
| 
      
 449 
     | 
    
         
            +
                  target = null;
         
     | 
| 
      
 450 
     | 
    
         
            +
                } else if (SC.typeOf(method) === 'string') {
         
     | 
| 
      
 451 
     | 
    
         
            +
                  method = target[method];
         
     | 
| 
      
 452 
     | 
    
         
            +
                }
         
     | 
| 
      
 453 
     | 
    
         
            +
             
     | 
| 
      
 454 
     | 
    
         
            +
                if (!this._firstRoute) this._firstRoute = Route.create();
         
     | 
| 
      
 455 
     | 
    
         
            +
                this._firstRoute.add(route.split('/'), target, method);
         
     | 
| 
      
 456 
     | 
    
         
            +
             
     | 
| 
      
 457 
     | 
    
         
            +
                return this;
         
     | 
| 
      
 458 
     | 
    
         
            +
              },
         
     | 
| 
      
 459 
     | 
    
         
            +
             
     | 
| 
      
 460 
     | 
    
         
            +
              /**
         
     | 
| 
      
 461 
     | 
    
         
            +
                Observer of the 'location' property that calls the correct route handler
         
     | 
| 
      
 462 
     | 
    
         
            +
                when the location changes.
         
     | 
| 
      
 463 
     | 
    
         
            +
              */
         
     | 
| 
      
 464 
     | 
    
         
            +
              locationDidChange: function() {
         
     | 
| 
      
 465 
     | 
    
         
            +
                this.trigger();
         
     | 
| 
      
 466 
     | 
    
         
            +
              }.observes('location'),
         
     | 
| 
      
 467 
     | 
    
         
            +
             
     | 
| 
      
 468 
     | 
    
         
            +
              /**
         
     | 
| 
      
 469 
     | 
    
         
            +
                Triggers a route even if already in that route (does change the location, if it
         
     | 
| 
      
 470 
     | 
    
         
            +
                is not already changed, as well).
         
     | 
| 
      
 471 
     | 
    
         
            +
             
     | 
| 
      
 472 
     | 
    
         
            +
                If the location is not the same as the supplied location, this simply lets "location"
         
     | 
| 
      
 473 
     | 
    
         
            +
                handle it (which ends up coming back to here).
         
     | 
| 
      
 474 
     | 
    
         
            +
              */
         
     | 
| 
      
 475 
     | 
    
         
            +
              trigger: function() {
         
     | 
| 
      
 476 
     | 
    
         
            +
                var location = get(this, 'location'),
         
     | 
| 
      
 477 
     | 
    
         
            +
                    params, route;
         
     | 
| 
      
 478 
     | 
    
         
            +
             
     | 
| 
      
 479 
     | 
    
         
            +
                if (this._firstRoute) {
         
     | 
| 
      
 480 
     | 
    
         
            +
                  params = this._extractParametersAndRoute({ route: location });
         
     | 
| 
      
 481 
     | 
    
         
            +
                  location = params.route;
         
     | 
| 
      
 482 
     | 
    
         
            +
                  delete params.route;
         
     | 
| 
      
 483 
     | 
    
         
            +
                  delete params.params;
         
     | 
| 
      
 484 
     | 
    
         
            +
             
     | 
| 
      
 485 
     | 
    
         
            +
                  route = this.getRoute(location, params);
         
     | 
| 
      
 486 
     | 
    
         
            +
                  if (route && route.method) {
         
     | 
| 
      
 487 
     | 
    
         
            +
                    route.method.call(route.target || this, params);
         
     | 
| 
      
 488 
     | 
    
         
            +
                  }
         
     | 
| 
      
 489 
     | 
    
         
            +
                }
         
     | 
| 
      
 490 
     | 
    
         
            +
              },
         
     | 
| 
      
 491 
     | 
    
         
            +
             
     | 
| 
      
 492 
     | 
    
         
            +
              getRoute: function(route, params) {
         
     | 
| 
      
 493 
     | 
    
         
            +
                var firstRoute = this._firstRoute;
         
     | 
| 
      
 494 
     | 
    
         
            +
                if (params == null) {
         
     | 
| 
      
 495 
     | 
    
         
            +
                  params = {}
         
     | 
| 
      
 496 
     | 
    
         
            +
                }
         
     | 
| 
      
 497 
     | 
    
         
            +
             
     | 
| 
      
 498 
     | 
    
         
            +
                return firstRoute.routeForParts(route.split('/'), params);
         
     | 
| 
      
 499 
     | 
    
         
            +
              },
         
     | 
| 
      
 500 
     | 
    
         
            +
             
     | 
| 
      
 501 
     | 
    
         
            +
              exists: function(route, params) {
         
     | 
| 
      
 502 
     | 
    
         
            +
                route = this.getRoute(route, params);
         
     | 
| 
      
 503 
     | 
    
         
            +
                return route != null && route.method != null;
         
     | 
| 
      
 504 
     | 
    
         
            +
              }
         
     | 
| 
      
 505 
     | 
    
         
            +
             
     | 
| 
      
 506 
     | 
    
         
            +
            });
         
     | 
| 
      
 507 
     | 
    
         
            +
             
     | 
| 
      
 508 
     | 
    
         
            +
            /**
         
     | 
| 
      
 509 
     | 
    
         
            +
              Event handler for the hashchange event. Called automatically by the browser
         
     | 
| 
      
 510 
     | 
    
         
            +
              if it supports the hashchange event, or by our timer if not.
         
     | 
| 
      
 511 
     | 
    
         
            +
            */
         
     | 
| 
      
 512 
     | 
    
         
            +
            function hashChange(event) {
         
     | 
| 
      
 513 
     | 
    
         
            +
              var loc = window.location.hash;
         
     | 
| 
      
 514 
     | 
    
         
            +
             
     | 
| 
      
 515 
     | 
    
         
            +
              // Remove the '#' prefix
         
     | 
| 
      
 516 
     | 
    
         
            +
              loc = (loc && loc.length > 0) ? loc.slice(1, loc.length) : '';
         
     | 
| 
      
 517 
     | 
    
         
            +
             
     | 
| 
      
 518 
     | 
    
         
            +
              if (!jQuery.browser.mozilla) {
         
     | 
| 
      
 519 
     | 
    
         
            +
                // because of bug https://bugzilla.mozilla.org/show_bug.cgi?id=483304
         
     | 
| 
      
 520 
     | 
    
         
            +
                loc = decodeURI(loc);
         
     | 
| 
      
 521 
     | 
    
         
            +
              }
         
     | 
| 
      
 522 
     | 
    
         
            +
             
     | 
| 
      
 523 
     | 
    
         
            +
              if (get(routes, 'location') !== loc && !routes._skipRoute) {
         
     | 
| 
      
 524 
     | 
    
         
            +
                SC.run.once(function() {
         
     | 
| 
      
 525 
     | 
    
         
            +
                  set(routes, 'location', loc);
         
     | 
| 
      
 526 
     | 
    
         
            +
                });
         
     | 
| 
      
 527 
     | 
    
         
            +
              }
         
     | 
| 
      
 528 
     | 
    
         
            +
              routes._skipRoute = false;
         
     | 
| 
      
 529 
     | 
    
         
            +
            }
         
     | 
| 
      
 530 
     | 
    
         
            +
             
     | 
| 
      
 531 
     | 
    
         
            +
            function popState(event) {
         
     | 
| 
      
 532 
     | 
    
         
            +
              var base = get(routes, 'baseURI'),
         
     | 
| 
      
 533 
     | 
    
         
            +
                  loc = document.location.href;
         
     | 
| 
      
 534 
     | 
    
         
            +
             
     | 
| 
      
 535 
     | 
    
         
            +
              if (loc.slice(0, base.length) === base) {
         
     | 
| 
      
 536 
     | 
    
         
            +
             
     | 
| 
      
 537 
     | 
    
         
            +
                // Remove the base prefix and the extra '/'
         
     | 
| 
      
 538 
     | 
    
         
            +
                loc = loc.slice(base.length + 1, loc.length);
         
     | 
| 
      
 539 
     | 
    
         
            +
             
     | 
| 
      
 540 
     | 
    
         
            +
                if (get(routes, 'location') !== loc && !routes._skipRoute) {
         
     | 
| 
      
 541 
     | 
    
         
            +
                  SC.run.once(function() {
         
     | 
| 
      
 542 
     | 
    
         
            +
                    set(routes, 'location', loc);
         
     | 
| 
      
 543 
     | 
    
         
            +
                  });
         
     | 
| 
      
 544 
     | 
    
         
            +
                }
         
     | 
| 
      
 545 
     | 
    
         
            +
              }
         
     | 
| 
      
 546 
     | 
    
         
            +
              routes._skipRoute = false;
         
     | 
| 
      
 547 
     | 
    
         
            +
            }
         
     | 
| 
      
 548 
     | 
    
         
            +
             
     | 
| 
      
 549 
     | 
    
         
            +
            })();
         
     |