3 Copyright 2012 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
7 if (typeof _yuitest_coverage == "undefined"){
8 _yuitest_coverage = {};
9 _yuitest_coverline = function(src, line){
10 var coverage = _yuitest_coverage[src];
11 if (!coverage.lines[line]){
12 coverage.calledLines++;
14 coverage.lines[line]++;
16 _yuitest_coverfunc = function(src, name, line){
17 var coverage = _yuitest_coverage[src],
18 funcId = name + ":" + line;
19 if (!coverage.functions[funcId]){
20 coverage.calledFunctions++;
22 coverage.functions[funcId]++;
25 _yuitest_coverage["build/history-hash/history-hash.js"] = {
32 path: "build/history-hash/history-hash.js",
35 _yuitest_coverage["build/history-hash/history-hash.js"].code=["YUI.add('history-hash', function (Y, NAME) {","","/**"," * Provides browser history management backed by"," * <code>window.location.hash</code>, as well as convenience methods for working"," * with the location hash and a synthetic <code>hashchange</code> event that"," * normalizes differences across browsers."," *"," * @module history"," * @submodule history-hash"," * @since 3.2.0"," * @class HistoryHash"," * @extends HistoryBase"," * @constructor"," * @param {Object} config (optional) Configuration object. See the HistoryBase"," * documentation for details."," */","","var HistoryBase = Y.HistoryBase,"," Lang = Y.Lang,"," YArray = Y.Array,"," YObject = Y.Object,"," GlobalEnv = YUI.namespace('Env.HistoryHash'),",""," SRC_HASH = 'hash',",""," hashNotifiers,"," oldHash,"," oldUrl,"," win = Y.config.win,"," useHistoryHTML5 = Y.config.useHistoryHTML5;","","function HistoryHash() {"," HistoryHash.superclass.constructor.apply(this, arguments);","}","","Y.extend(HistoryHash, HistoryBase, {"," // -- Initialization -------------------------------------------------------"," _init: function (config) {"," var bookmarkedState = HistoryHash.parseHash();",""," // If an initialState was provided, merge the bookmarked state into it"," // (the bookmarked state wins)."," config = config || {};",""," this._initialState = config.initialState ?"," Y.merge(config.initialState, bookmarkedState) : bookmarkedState;",""," // Subscribe to the synthetic hashchange event (defined below) to handle"," // changes."," Y.after('hashchange', Y.bind(this._afterHashChange, this), win);",""," HistoryHash.superclass._init.apply(this, arguments);"," },",""," // -- Protected Methods ----------------------------------------------------"," _change: function (src, state, options) {"," // Stringify all values to ensure that comparisons don't fail after"," // they're coerced to strings in the location hash."," YObject.each(state, function (value, key) {"," if (Lang.isValue(value)) {"," state[key] = value.toString();"," }"," });",""," return HistoryHash.superclass._change.call(this, src, state, options);"," },",""," _storeState: function (src, newState) {"," var decode = HistoryHash.decode,"," newHash = HistoryHash.createHash(newState);",""," HistoryHash.superclass._storeState.apply(this, arguments);",""," // Update the location hash with the changes, but only if the new hash"," // actually differs from the current hash (this avoids creating multiple"," // history entries for a single state)."," //"," // We always compare decoded hashes, since it's possible that the hash"," // could be set incorrectly to a non-encoded value outside of"," // HistoryHash."," if (src !== SRC_HASH && decode(HistoryHash.getHash()) !== decode(newHash)) {"," HistoryHash[src === HistoryBase.SRC_REPLACE ? 'replaceHash' : 'setHash'](newHash);"," }"," },",""," // -- Protected Event Handlers ---------------------------------------------",""," /**"," * Handler for hashchange events."," *"," * @method _afterHashChange"," * @param {Event} e"," * @protected"," */"," _afterHashChange: function (e) {"," this._resolveChanges(SRC_HASH, HistoryHash.parseHash(e.newHash), {});"," }","}, {"," // -- Public Static Properties ---------------------------------------------"," NAME: 'historyHash',",""," /**"," * Constant used to identify state changes originating from"," * <code>hashchange</code> events."," *"," * @property SRC_HASH"," * @type String"," * @static"," * @final"," */"," SRC_HASH: SRC_HASH,",""," /**"," * <p>"," * Prefix to prepend when setting the hash fragment. For example, if the"," * prefix is <code>!</code> and the hash fragment is set to"," * <code>#foo=bar&baz=quux</code>, the final hash fragment in the URL will"," * become <code>#!foo=bar&baz=quux</code>. This can be used to help make an"," * Ajax application crawlable in accordance with Google's guidelines at"," * <a href=\"http://code.google.com/web/ajaxcrawling/\">http://code.google.com/web/ajaxcrawling/</a>."," * </p>"," *"," * <p>"," * Note that this prefix applies to all HistoryHash instances. It's not"," * possible for individual instances to use their own prefixes since they"," * all operate on the same URL."," * </p>"," *"," * @property hashPrefix"," * @type String"," * @default ''"," * @static"," */"," hashPrefix: '',",""," // -- Protected Static Properties ------------------------------------------",""," /**"," * Regular expression used to parse location hash/query strings."," *"," * @property _REGEX_HASH"," * @type RegExp"," * @protected"," * @static"," * @final"," */"," _REGEX_HASH: /([^\\?#&]+)=([^&]+)/g,",""," // -- Public Static Methods ------------------------------------------------",""," /**"," * Creates a location hash string from the specified object of key/value"," * pairs."," *"," * @method createHash"," * @param {Object} params object of key/value parameter pairs"," * @return {String} location hash string"," * @static"," */"," createHash: function (params) {"," var encode = HistoryHash.encode,"," hash = [];",""," YObject.each(params, function (value, key) {"," if (Lang.isValue(value)) {"," hash.push(encode(key) + '=' + encode(value));"," }"," });",""," return hash.join('&');"," },",""," /**"," * Wrapper around <code>decodeURIComponent()</code> that also converts +"," * chars into spaces."," *"," * @method decode"," * @param {String} string string to decode"," * @return {String} decoded string"," * @static"," */"," decode: function (string) {"," return decodeURIComponent(string.replace(/\\+/g, ' '));"," },",""," /**"," * Wrapper around <code>encodeURIComponent()</code> that converts spaces to"," * + chars."," *"," * @method encode"," * @param {String} string string to encode"," * @return {String} encoded string"," * @static"," */"," encode: function (string) {"," return encodeURIComponent(string).replace(/%20/g, '+');"," },",""," /**"," * Gets the raw (not decoded) current location hash, minus the preceding '#'"," * character and the hashPrefix (if one is set)."," *"," * @method getHash"," * @return {String} current location hash"," * @static"," */"," getHash: (Y.UA.gecko ? function () {"," // Gecko's window.location.hash returns a decoded string and we want all"," // encoding untouched, so we need to get the hash value from"," // window.location.href instead. We have to use UA sniffing rather than"," // feature detection, since the only way to detect this would be to"," // actually change the hash."," var location = Y.getLocation(),"," matches = /#(.*)$/.exec(location.href),"," hash = matches && matches[1] || '',"," prefix = HistoryHash.hashPrefix;",""," return prefix && hash.indexOf(prefix) === 0 ?"," hash.replace(prefix, '') : hash;"," } : function () {"," var location = Y.getLocation(),"," hash = location.hash.substring(1),"," prefix = HistoryHash.hashPrefix;",""," // Slight code duplication here, but execution speed is of the essence"," // since getHash() is called every 50ms to poll for changes in browsers"," // that don't support native onhashchange. An additional function call"," // would add unnecessary overhead."," return prefix && hash.indexOf(prefix) === 0 ?"," hash.replace(prefix, '') : hash;"," }),",""," /**"," * Gets the current bookmarkable URL."," *"," * @method getUrl"," * @return {String} current bookmarkable URL"," * @static"," */"," getUrl: function () {"," return location.href;"," },",""," /**"," * Parses a location hash string into an object of key/value parameter"," * pairs. If <i>hash</i> is not specified, the current location hash will"," * be used."," *"," * @method parseHash"," * @param {String} hash (optional) location hash string"," * @return {Object} object of parsed key/value parameter pairs"," * @static"," */"," parseHash: function (hash) {"," var decode = HistoryHash.decode,"," i,"," len,"," matches,"," param,"," params = {},"," prefix = HistoryHash.hashPrefix,"," prefixIndex;",""," hash = Lang.isValue(hash) ? hash : HistoryHash.getHash();",""," if (prefix) {"," prefixIndex = hash.indexOf(prefix);",""," if (prefixIndex === 0 || (prefixIndex === 1 && hash.charAt(0) === '#')) {"," hash = hash.replace(prefix, '');"," }"," }",""," matches = hash.match(HistoryHash._REGEX_HASH) || [];",""," for (i = 0, len = matches.length; i < len; ++i) {"," param = matches[i].split('=');"," params[decode(param[0])] = decode(param[1]);"," }",""," return params;"," },",""," /**"," * Replaces the browser's current location hash with the specified hash"," * and removes all forward navigation states, without creating a new browser"," * history entry. Automatically prepends the <code>hashPrefix</code> if one"," * is set."," *"," * @method replaceHash"," * @param {String} hash new location hash"," * @static"," */"," replaceHash: function (hash) {"," var location = Y.getLocation(),"," base = location.href.replace(/#.*$/, '');",""," if (hash.charAt(0) === '#') {"," hash = hash.substring(1);"," }",""," location.replace(base + '#' + (HistoryHash.hashPrefix || '') + hash);"," },",""," /**"," * Sets the browser's location hash to the specified string. Automatically"," * prepends the <code>hashPrefix</code> if one is set."," *"," * @method setHash"," * @param {String} hash new location hash"," * @static"," */"," setHash: function (hash) {"," var location = Y.getLocation();",""," if (hash.charAt(0) === '#') {"," hash = hash.substring(1);"," }",""," location.hash = (HistoryHash.hashPrefix || '') + hash;"," }","});","","// -- Synthetic hashchange Event -----------------------------------------------","","// TODO: YUIDoc currently doesn't provide a good way to document synthetic DOM","// events. For now, we're just documenting the hashchange event on the YUI","// object, which is about the best we can do until enhancements are made to","// YUIDoc.","","/**","Synthetic <code>window.onhashchange</code> event that normalizes differences","across browsers and provides support for browsers that don't natively support","<code>onhashchange</code>.","","This event is provided by the <code>history-hash</code> module.","","@example",""," YUI().use('history-hash', function (Y) {"," Y.on('hashchange', function (e) {"," // Handle hashchange events on the current window."," }, Y.config.win);"," });","","@event hashchange","@param {EventFacade} e Event facade with the following additional"," properties:","","<dl>"," <dt>oldHash</dt>"," <dd>"," Previous hash fragment value before the change."," </dd>",""," <dt>oldUrl</dt>"," <dd>"," Previous URL (including the hash fragment) before the change."," </dd>",""," <dt>newHash</dt>"," <dd>"," New hash fragment value after the change."," </dd>",""," <dt>newUrl</dt>"," <dd>"," New URL (including the hash fragment) after the change."," </dd>","</dl>","@for YUI","@since 3.2.0","**/","","hashNotifiers = GlobalEnv._notifiers;","","if (!hashNotifiers) {"," hashNotifiers = GlobalEnv._notifiers = [];","}","","Y.Event.define('hashchange', {"," on: function (node, subscriber, notifier) {"," // Ignore this subscription if the node is anything other than the"," // window or document body, since those are the only elements that"," // should support the hashchange event. Note that the body could also be"," // a frameset, but that's okay since framesets support hashchange too."," if (node.compareTo(win) || node.compareTo(Y.config.doc.body)) {"," hashNotifiers.push(notifier);"," }"," },",""," detach: function (node, subscriber, notifier) {"," var index = YArray.indexOf(hashNotifiers, notifier);",""," if (index !== -1) {"," hashNotifiers.splice(index, 1);"," }"," }","});","","oldHash = HistoryHash.getHash();","oldUrl = HistoryHash.getUrl();","","if (HistoryBase.nativeHashChange) {"," // Wrap the browser's native hashchange event if there's not already a"," // global listener."," if (!GlobalEnv._hashHandle) {"," GlobalEnv._hashHandle = Y.Event.attach('hashchange', function (e) {"," var newHash = HistoryHash.getHash(),"," newUrl = HistoryHash.getUrl();",""," // Iterate over a copy of the hashNotifiers array since a subscriber"," // could detach during iteration and cause the array to be re-indexed."," YArray.each(hashNotifiers.concat(), function (notifier) {"," notifier.fire({"," _event : e,"," oldHash: oldHash,"," oldUrl : oldUrl,"," newHash: newHash,"," newUrl : newUrl"," });"," });",""," oldHash = newHash;"," oldUrl = newUrl;"," }, win);"," }","} else {"," // Begin polling for location hash changes if there's not already a global"," // poll running."," if (!GlobalEnv._hashPoll) {"," GlobalEnv._hashPoll = Y.later(50, null, function () {"," var newHash = HistoryHash.getHash(),"," facade, newUrl;",""," if (oldHash !== newHash) {"," newUrl = HistoryHash.getUrl();",""," facade = {"," oldHash: oldHash,"," oldUrl : oldUrl,"," newHash: newHash,"," newUrl : newUrl"," };",""," oldHash = newHash;"," oldUrl = newUrl;",""," YArray.each(hashNotifiers.concat(), function (notifier) {"," notifier.fire(facade);"," });"," }"," }, null, true);"," }","}","","Y.HistoryHash = HistoryHash;","","// HistoryHash will never win over HistoryHTML5 unless useHistoryHTML5 is false.","if (useHistoryHTML5 === false || (!Y.History && useHistoryHTML5 !== true &&"," (!HistoryBase.html5 || !Y.HistoryHTML5))) {"," Y.History = HistoryHash;","}","","","}, '3.7.1', {\"requires\": [\"event-synthetic\", \"history-base\", \"yui-later\"]});"];
36 _yuitest_coverage["build/history-hash/history-hash.js"].lines = {"1":0,"19":0,"33":0,"34":0,"37":0,"40":0,"44":0,"46":0,"51":0,"53":0,"60":0,"61":0,"62":0,"66":0,"70":0,"73":0,"82":0,"83":0,"97":0,"162":0,"165":0,"166":0,"167":0,"171":0,"184":0,"197":0,"214":0,"219":0,"222":0,"230":0,"242":0,"256":0,"265":0,"267":0,"268":0,"270":0,"271":0,"275":0,"277":0,"278":0,"279":0,"282":0,"296":0,"299":0,"300":0,"303":0,"315":0,"317":0,"318":0,"321":0,"376":0,"378":0,"379":0,"382":0,"388":0,"389":0,"394":0,"396":0,"397":0,"402":0,"403":0,"405":0,"408":0,"409":0,"410":0,"415":0,"416":0,"425":0,"426":0,"432":0,"433":0,"434":0,"437":0,"438":0,"440":0,"447":0,"448":0,"450":0,"451":0,"458":0,"461":0,"463":0};
37 _yuitest_coverage["build/history-hash/history-hash.js"].functions = {"HistoryHash:33":0,"_init:39":0,"(anonymous 2):60":0,"_change:57":0,"_storeState:69":0,"_afterHashChange:96":0,"(anonymous 3):165":0,"createHash:161":0,"decode:183":0,"encode:196":0,"(anonymous 4):208":0,"}:221":0,"getUrl:241":0,"parseHash:255":0,"replaceHash:295":0,"setHash:314":0,"on:383":0,"detach:393":0,"(anonymous 6):415":0,"(anonymous 5):409":0,"(anonymous 8):450":0,"(anonymous 7):433":0,"(anonymous 1):1":0};
38 _yuitest_coverage["build/history-hash/history-hash.js"].coveredLines = 82;
39 _yuitest_coverage["build/history-hash/history-hash.js"].coveredFunctions = 23;
40 _yuitest_coverline("build/history-hash/history-hash.js", 1);
41 YUI.add('history-hash', function (Y, NAME) {
44 * Provides browser history management backed by
45 * <code>window.location.hash</code>, as well as convenience methods for working
46 * with the location hash and a synthetic <code>hashchange</code> event that
47 * normalizes differences across browsers.
50 * @submodule history-hash
53 * @extends HistoryBase
55 * @param {Object} config (optional) Configuration object. See the HistoryBase
56 * documentation for details.
59 _yuitest_coverfunc("build/history-hash/history-hash.js", "(anonymous 1)", 1);
60 _yuitest_coverline("build/history-hash/history-hash.js", 19);
61 var HistoryBase = Y.HistoryBase,
65 GlobalEnv = YUI.namespace('Env.HistoryHash'),
73 useHistoryHTML5 = Y.config.useHistoryHTML5;
75 _yuitest_coverline("build/history-hash/history-hash.js", 33);
76 function HistoryHash() {
77 _yuitest_coverfunc("build/history-hash/history-hash.js", "HistoryHash", 33);
78 _yuitest_coverline("build/history-hash/history-hash.js", 34);
79 HistoryHash.superclass.constructor.apply(this, arguments);
82 _yuitest_coverline("build/history-hash/history-hash.js", 37);
83 Y.extend(HistoryHash, HistoryBase, {
84 // -- Initialization -------------------------------------------------------
85 _init: function (config) {
86 _yuitest_coverfunc("build/history-hash/history-hash.js", "_init", 39);
87 _yuitest_coverline("build/history-hash/history-hash.js", 40);
88 var bookmarkedState = HistoryHash.parseHash();
90 // If an initialState was provided, merge the bookmarked state into it
91 // (the bookmarked state wins).
92 _yuitest_coverline("build/history-hash/history-hash.js", 44);
93 config = config || {};
95 _yuitest_coverline("build/history-hash/history-hash.js", 46);
96 this._initialState = config.initialState ?
97 Y.merge(config.initialState, bookmarkedState) : bookmarkedState;
99 // Subscribe to the synthetic hashchange event (defined below) to handle
101 _yuitest_coverline("build/history-hash/history-hash.js", 51);
102 Y.after('hashchange', Y.bind(this._afterHashChange, this), win);
104 _yuitest_coverline("build/history-hash/history-hash.js", 53);
105 HistoryHash.superclass._init.apply(this, arguments);
108 // -- Protected Methods ----------------------------------------------------
109 _change: function (src, state, options) {
110 // Stringify all values to ensure that comparisons don't fail after
111 // they're coerced to strings in the location hash.
112 _yuitest_coverfunc("build/history-hash/history-hash.js", "_change", 57);
113 _yuitest_coverline("build/history-hash/history-hash.js", 60);
114 YObject.each(state, function (value, key) {
115 _yuitest_coverfunc("build/history-hash/history-hash.js", "(anonymous 2)", 60);
116 _yuitest_coverline("build/history-hash/history-hash.js", 61);
117 if (Lang.isValue(value)) {
118 _yuitest_coverline("build/history-hash/history-hash.js", 62);
119 state[key] = value.toString();
123 _yuitest_coverline("build/history-hash/history-hash.js", 66);
124 return HistoryHash.superclass._change.call(this, src, state, options);
127 _storeState: function (src, newState) {
128 _yuitest_coverfunc("build/history-hash/history-hash.js", "_storeState", 69);
129 _yuitest_coverline("build/history-hash/history-hash.js", 70);
130 var decode = HistoryHash.decode,
131 newHash = HistoryHash.createHash(newState);
133 _yuitest_coverline("build/history-hash/history-hash.js", 73);
134 HistoryHash.superclass._storeState.apply(this, arguments);
136 // Update the location hash with the changes, but only if the new hash
137 // actually differs from the current hash (this avoids creating multiple
138 // history entries for a single state).
140 // We always compare decoded hashes, since it's possible that the hash
141 // could be set incorrectly to a non-encoded value outside of
143 _yuitest_coverline("build/history-hash/history-hash.js", 82);
144 if (src !== SRC_HASH && decode(HistoryHash.getHash()) !== decode(newHash)) {
145 _yuitest_coverline("build/history-hash/history-hash.js", 83);
146 HistoryHash[src === HistoryBase.SRC_REPLACE ? 'replaceHash' : 'setHash'](newHash);
150 // -- Protected Event Handlers ---------------------------------------------
153 * Handler for hashchange events.
155 * @method _afterHashChange
159 _afterHashChange: function (e) {
160 _yuitest_coverfunc("build/history-hash/history-hash.js", "_afterHashChange", 96);
161 _yuitest_coverline("build/history-hash/history-hash.js", 97);
162 this._resolveChanges(SRC_HASH, HistoryHash.parseHash(e.newHash), {});
165 // -- Public Static Properties ---------------------------------------------
169 * Constant used to identify state changes originating from
170 * <code>hashchange</code> events.
181 * Prefix to prepend when setting the hash fragment. For example, if the
182 * prefix is <code>!</code> and the hash fragment is set to
183 * <code>#foo=bar&baz=quux</code>, the final hash fragment in the URL will
184 * become <code>#!foo=bar&baz=quux</code>. This can be used to help make an
185 * Ajax application crawlable in accordance with Google's guidelines at
186 * <a href="http://code.google.com/web/ajaxcrawling/">http://code.google.com/web/ajaxcrawling/</a>.
190 * Note that this prefix applies to all HistoryHash instances. It's not
191 * possible for individual instances to use their own prefixes since they
192 * all operate on the same URL.
195 * @property hashPrefix
202 // -- Protected Static Properties ------------------------------------------
205 * Regular expression used to parse location hash/query strings.
207 * @property _REGEX_HASH
213 _REGEX_HASH: /([^\?#&]+)=([^&]+)/g,
215 // -- Public Static Methods ------------------------------------------------
218 * Creates a location hash string from the specified object of key/value
222 * @param {Object} params object of key/value parameter pairs
223 * @return {String} location hash string
226 createHash: function (params) {
227 _yuitest_coverfunc("build/history-hash/history-hash.js", "createHash", 161);
228 _yuitest_coverline("build/history-hash/history-hash.js", 162);
229 var encode = HistoryHash.encode,
232 _yuitest_coverline("build/history-hash/history-hash.js", 165);
233 YObject.each(params, function (value, key) {
234 _yuitest_coverfunc("build/history-hash/history-hash.js", "(anonymous 3)", 165);
235 _yuitest_coverline("build/history-hash/history-hash.js", 166);
236 if (Lang.isValue(value)) {
237 _yuitest_coverline("build/history-hash/history-hash.js", 167);
238 hash.push(encode(key) + '=' + encode(value));
242 _yuitest_coverline("build/history-hash/history-hash.js", 171);
243 return hash.join('&');
247 * Wrapper around <code>decodeURIComponent()</code> that also converts +
251 * @param {String} string string to decode
252 * @return {String} decoded string
255 decode: function (string) {
256 _yuitest_coverfunc("build/history-hash/history-hash.js", "decode", 183);
257 _yuitest_coverline("build/history-hash/history-hash.js", 184);
258 return decodeURIComponent(string.replace(/\+/g, ' '));
262 * Wrapper around <code>encodeURIComponent()</code> that converts spaces to
266 * @param {String} string string to encode
267 * @return {String} encoded string
270 encode: function (string) {
271 _yuitest_coverfunc("build/history-hash/history-hash.js", "encode", 196);
272 _yuitest_coverline("build/history-hash/history-hash.js", 197);
273 return encodeURIComponent(string).replace(/%20/g, '+');
277 * Gets the raw (not decoded) current location hash, minus the preceding '#'
278 * character and the hashPrefix (if one is set).
281 * @return {String} current location hash
284 getHash: (Y.UA.gecko ? function () {
285 // Gecko's window.location.hash returns a decoded string and we want all
286 // encoding untouched, so we need to get the hash value from
287 // window.location.href instead. We have to use UA sniffing rather than
288 // feature detection, since the only way to detect this would be to
289 // actually change the hash.
290 _yuitest_coverfunc("build/history-hash/history-hash.js", "(anonymous 4)", 208);
291 _yuitest_coverline("build/history-hash/history-hash.js", 214);
292 var location = Y.getLocation(),
293 matches = /#(.*)$/.exec(location.href),
294 hash = matches && matches[1] || '',
295 prefix = HistoryHash.hashPrefix;
297 _yuitest_coverline("build/history-hash/history-hash.js", 219);
298 return prefix && hash.indexOf(prefix) === 0 ?
299 hash.replace(prefix, '') : hash;
301 _yuitest_coverfunc("build/history-hash/history-hash.js", "}", 221);
302 _yuitest_coverline("build/history-hash/history-hash.js", 222);
303 var location = Y.getLocation(),
304 hash = location.hash.substring(1),
305 prefix = HistoryHash.hashPrefix;
307 // Slight code duplication here, but execution speed is of the essence
308 // since getHash() is called every 50ms to poll for changes in browsers
309 // that don't support native onhashchange. An additional function call
310 // would add unnecessary overhead.
311 _yuitest_coverline("build/history-hash/history-hash.js", 230);
312 return prefix && hash.indexOf(prefix) === 0 ?
313 hash.replace(prefix, '') : hash;
317 * Gets the current bookmarkable URL.
320 * @return {String} current bookmarkable URL
323 getUrl: function () {
324 _yuitest_coverfunc("build/history-hash/history-hash.js", "getUrl", 241);
325 _yuitest_coverline("build/history-hash/history-hash.js", 242);
326 return location.href;
330 * Parses a location hash string into an object of key/value parameter
331 * pairs. If <i>hash</i> is not specified, the current location hash will
335 * @param {String} hash (optional) location hash string
336 * @return {Object} object of parsed key/value parameter pairs
339 parseHash: function (hash) {
340 _yuitest_coverfunc("build/history-hash/history-hash.js", "parseHash", 255);
341 _yuitest_coverline("build/history-hash/history-hash.js", 256);
342 var decode = HistoryHash.decode,
348 prefix = HistoryHash.hashPrefix,
351 _yuitest_coverline("build/history-hash/history-hash.js", 265);
352 hash = Lang.isValue(hash) ? hash : HistoryHash.getHash();
354 _yuitest_coverline("build/history-hash/history-hash.js", 267);
356 _yuitest_coverline("build/history-hash/history-hash.js", 268);
357 prefixIndex = hash.indexOf(prefix);
359 _yuitest_coverline("build/history-hash/history-hash.js", 270);
360 if (prefixIndex === 0 || (prefixIndex === 1 && hash.charAt(0) === '#')) {
361 _yuitest_coverline("build/history-hash/history-hash.js", 271);
362 hash = hash.replace(prefix, '');
366 _yuitest_coverline("build/history-hash/history-hash.js", 275);
367 matches = hash.match(HistoryHash._REGEX_HASH) || [];
369 _yuitest_coverline("build/history-hash/history-hash.js", 277);
370 for (i = 0, len = matches.length; i < len; ++i) {
371 _yuitest_coverline("build/history-hash/history-hash.js", 278);
372 param = matches[i].split('=');
373 _yuitest_coverline("build/history-hash/history-hash.js", 279);
374 params[decode(param[0])] = decode(param[1]);
377 _yuitest_coverline("build/history-hash/history-hash.js", 282);
382 * Replaces the browser's current location hash with the specified hash
383 * and removes all forward navigation states, without creating a new browser
384 * history entry. Automatically prepends the <code>hashPrefix</code> if one
387 * @method replaceHash
388 * @param {String} hash new location hash
391 replaceHash: function (hash) {
392 _yuitest_coverfunc("build/history-hash/history-hash.js", "replaceHash", 295);
393 _yuitest_coverline("build/history-hash/history-hash.js", 296);
394 var location = Y.getLocation(),
395 base = location.href.replace(/#.*$/, '');
397 _yuitest_coverline("build/history-hash/history-hash.js", 299);
398 if (hash.charAt(0) === '#') {
399 _yuitest_coverline("build/history-hash/history-hash.js", 300);
400 hash = hash.substring(1);
403 _yuitest_coverline("build/history-hash/history-hash.js", 303);
404 location.replace(base + '#' + (HistoryHash.hashPrefix || '') + hash);
408 * Sets the browser's location hash to the specified string. Automatically
409 * prepends the <code>hashPrefix</code> if one is set.
412 * @param {String} hash new location hash
415 setHash: function (hash) {
416 _yuitest_coverfunc("build/history-hash/history-hash.js", "setHash", 314);
417 _yuitest_coverline("build/history-hash/history-hash.js", 315);
418 var location = Y.getLocation();
420 _yuitest_coverline("build/history-hash/history-hash.js", 317);
421 if (hash.charAt(0) === '#') {
422 _yuitest_coverline("build/history-hash/history-hash.js", 318);
423 hash = hash.substring(1);
426 _yuitest_coverline("build/history-hash/history-hash.js", 321);
427 location.hash = (HistoryHash.hashPrefix || '') + hash;
431 // -- Synthetic hashchange Event -----------------------------------------------
433 // TODO: YUIDoc currently doesn't provide a good way to document synthetic DOM
434 // events. For now, we're just documenting the hashchange event on the YUI
435 // object, which is about the best we can do until enhancements are made to
439 Synthetic <code>window.onhashchange</code> event that normalizes differences
440 across browsers and provides support for browsers that don't natively support
441 <code>onhashchange</code>.
443 This event is provided by the <code>history-hash</code> module.
447 YUI().use('history-hash', function (Y) {
448 Y.on('hashchange', function (e) {
449 // Handle hashchange events on the current window.
454 @param {EventFacade} e Event facade with the following additional
460 Previous hash fragment value before the change.
465 Previous URL (including the hash fragment) before the change.
470 New hash fragment value after the change.
475 New URL (including the hash fragment) after the change.
482 _yuitest_coverline("build/history-hash/history-hash.js", 376);
483 hashNotifiers = GlobalEnv._notifiers;
485 _yuitest_coverline("build/history-hash/history-hash.js", 378);
486 if (!hashNotifiers) {
487 _yuitest_coverline("build/history-hash/history-hash.js", 379);
488 hashNotifiers = GlobalEnv._notifiers = [];
491 _yuitest_coverline("build/history-hash/history-hash.js", 382);
492 Y.Event.define('hashchange', {
493 on: function (node, subscriber, notifier) {
494 // Ignore this subscription if the node is anything other than the
495 // window or document body, since those are the only elements that
496 // should support the hashchange event. Note that the body could also be
497 // a frameset, but that's okay since framesets support hashchange too.
498 _yuitest_coverfunc("build/history-hash/history-hash.js", "on", 383);
499 _yuitest_coverline("build/history-hash/history-hash.js", 388);
500 if (node.compareTo(win) || node.compareTo(Y.config.doc.body)) {
501 _yuitest_coverline("build/history-hash/history-hash.js", 389);
502 hashNotifiers.push(notifier);
506 detach: function (node, subscriber, notifier) {
507 _yuitest_coverfunc("build/history-hash/history-hash.js", "detach", 393);
508 _yuitest_coverline("build/history-hash/history-hash.js", 394);
509 var index = YArray.indexOf(hashNotifiers, notifier);
511 _yuitest_coverline("build/history-hash/history-hash.js", 396);
513 _yuitest_coverline("build/history-hash/history-hash.js", 397);
514 hashNotifiers.splice(index, 1);
519 _yuitest_coverline("build/history-hash/history-hash.js", 402);
520 oldHash = HistoryHash.getHash();
521 _yuitest_coverline("build/history-hash/history-hash.js", 403);
522 oldUrl = HistoryHash.getUrl();
524 _yuitest_coverline("build/history-hash/history-hash.js", 405);
525 if (HistoryBase.nativeHashChange) {
526 // Wrap the browser's native hashchange event if there's not already a
528 _yuitest_coverline("build/history-hash/history-hash.js", 408);
529 if (!GlobalEnv._hashHandle) {
530 _yuitest_coverline("build/history-hash/history-hash.js", 409);
531 GlobalEnv._hashHandle = Y.Event.attach('hashchange', function (e) {
532 _yuitest_coverfunc("build/history-hash/history-hash.js", "(anonymous 5)", 409);
533 _yuitest_coverline("build/history-hash/history-hash.js", 410);
534 var newHash = HistoryHash.getHash(),
535 newUrl = HistoryHash.getUrl();
537 // Iterate over a copy of the hashNotifiers array since a subscriber
538 // could detach during iteration and cause the array to be re-indexed.
539 _yuitest_coverline("build/history-hash/history-hash.js", 415);
540 YArray.each(hashNotifiers.concat(), function (notifier) {
541 _yuitest_coverfunc("build/history-hash/history-hash.js", "(anonymous 6)", 415);
542 _yuitest_coverline("build/history-hash/history-hash.js", 416);
552 _yuitest_coverline("build/history-hash/history-hash.js", 425);
554 _yuitest_coverline("build/history-hash/history-hash.js", 426);
559 // Begin polling for location hash changes if there's not already a global
561 _yuitest_coverline("build/history-hash/history-hash.js", 432);
562 if (!GlobalEnv._hashPoll) {
563 _yuitest_coverline("build/history-hash/history-hash.js", 433);
564 GlobalEnv._hashPoll = Y.later(50, null, function () {
565 _yuitest_coverfunc("build/history-hash/history-hash.js", "(anonymous 7)", 433);
566 _yuitest_coverline("build/history-hash/history-hash.js", 434);
567 var newHash = HistoryHash.getHash(),
570 _yuitest_coverline("build/history-hash/history-hash.js", 437);
571 if (oldHash !== newHash) {
572 _yuitest_coverline("build/history-hash/history-hash.js", 438);
573 newUrl = HistoryHash.getUrl();
575 _yuitest_coverline("build/history-hash/history-hash.js", 440);
583 _yuitest_coverline("build/history-hash/history-hash.js", 447);
585 _yuitest_coverline("build/history-hash/history-hash.js", 448);
588 _yuitest_coverline("build/history-hash/history-hash.js", 450);
589 YArray.each(hashNotifiers.concat(), function (notifier) {
590 _yuitest_coverfunc("build/history-hash/history-hash.js", "(anonymous 8)", 450);
591 _yuitest_coverline("build/history-hash/history-hash.js", 451);
592 notifier.fire(facade);
599 _yuitest_coverline("build/history-hash/history-hash.js", 458);
600 Y.HistoryHash = HistoryHash;
602 // HistoryHash will never win over HistoryHTML5 unless useHistoryHTML5 is false.
603 _yuitest_coverline("build/history-hash/history-hash.js", 461);
604 if (useHistoryHTML5 === false || (!Y.History && useHistoryHTML5 !== true &&
605 (!HistoryBase.html5 || !Y.HistoryHTML5))) {
606 _yuitest_coverline("build/history-hash/history-hash.js", 463);
607 Y.History = HistoryHash;
611 }, '3.7.1', {"requires": ["event-synthetic", "history-base", "yui-later"]});