/*
* jQuery Address Plugin v1.1
* http://www.asual.com/jquery/address/
*
* Copyright (c) 2009 Rostislav Hristov
* Dual licensed under the MIT and GPL licenses.
* http://docs.jquery.com/License
*
* Date: 2009-12-23 14:27:00 +0200 (Wed, 23 Dec 2009)
*/
(function ($) {
$.address = (function () {
var _trigger = function(name) {
$(this).trigger(
$.extend($.Event(name),
(function() {
var event = {
value: this.value(),
path: this.path(),
pathNames: this.pathNames(),
parameterNames: this.parameterNames(),
parameters: {},
queryString: this.queryString()
};
for (var i = 0, l = event.parameterNames.length; i < l; i++)
event.parameters[event.parameterNames[i]] = this.parameter(event.parameterNames[i]);
return event;
}).call(this)
)
);
};
var _init = function() {
_trigger.call($.address, 'init');
};
var _change = function() {
_trigger.call($.address, 'change');
};
var _getHash = function() {
var index = _l.href.indexOf('#');
return index != -1 ? _ec(_dc(_l.href.substr(index + 1))) : '';
};
var _getWindow = function() {
try {
return top.document != undefined ? top : window;
} catch (e) {
return window;
}
};
var _strictCheck = function(value, force) {
if (_opts.strict)
value = force ? (value.substr(0, 1) != '/' ? '/' + value : value) : (value == '' ? '/' : value);
return value;
};
var _ieLocal = function(value, direction) {
return (_msie && _l.protocol == 'file:') ?
(direction ? _value.replace(/\?/, '%3F') : _value.replace(/%253F/, '?')) : value;
};
var _searchScript = function(el) {
for (var i = 0, l = el.childNodes.length, s; i < l; i++) {
if (el.childNodes[i].src)
_url = String(el.childNodes[i].src);
if (s = _searchScript(el.childNodes[i]))
return s;
}
};
var _listen = function() {
if (!_silent) {
var hash = _getHash();
var diff = !(_value == hash);
if (_safari && _version < 523) {
if (_length != _h.length) {
_length = _h.length;
if (typeof _stack[_length - 1] != UNDEFINED)
_value = _stack[_length - 1];
_update(false);
}
} else if (_msie && _version < 7 && diff) {
_l.reload();
} else if (diff) {
_value = hash;
_update(false);
}
}
};
var _update = function(internal) {
_change();
if (internal) {
_trigger.call($.address, 'internalChange');
} else {
_trigger.call($.address, 'externalChange');
}
_st(_track, 10);
};
var _track = function() {
var value = (_l.pathname + (/\/$/.test(_l.pathname) ? '' : '/') + _getters.value()).replace(/\/\//, '/').replace(/^\/$/, '');
var fn = window[_opts.tracker];
if (typeof fn == FUNCTION)
fn(value);
else if (typeof pageTracker != UNDEFINED && typeof pageTracker._trackPageview == FUNCTION)
pageTracker._trackPageview(value);
else if (typeof urchinTracker == FUNCTION)
urchinTracker(value);
};
var _htmlWrite = function() {
var doc = _frame.contentWindow.document;
doc.open();
doc.write('
' + _d.title + '');
doc.close();
};
var _load = function() {
if (!_loaded) {
_loaded = TRUE;
if (_msie && _version < 8) {
var frameset = _d.getElementsByTagName('frameset')[0];
_frame = _d.createElement((frameset ? '' : 'i') + 'frame');
if (frameset) {
frameset.insertAdjacentElement('beforeEnd', _frame);
frameset[frameset.cols ? 'cols' : 'rows'] += ',0';
_frame.src = 'javascript:false';
_frame.noResize = true;
_frame.frameBorder = _frame.frameSpacing = 0;
} else {
_frame.src = 'javascript:false';
_frame.style.display = 'none';
_d.body.insertAdjacentElement('afterBegin', _frame);
}
_st(function() {
$(_frame).bind('load', function() {
var win = _frame.contentWindow;
var src = win.location.href;
_value = (typeof win[ID] != UNDEFINED ? win[ID] : '');
if (_value != _getHash()) {
_update(false);
_l.hash = _ieLocal(_value, TRUE);
}
});
if (typeof _frame.contentWindow[ID] == UNDEFINED)
_htmlWrite();
}, 50);
} else if (_safari) {
if (_version < 418) {
$(_d.body).append('');
_form = _d.getElementById(ID);
}
if (typeof _l[ID] == UNDEFINED) _l[ID] = {};
if (typeof _l[ID][_l.pathname] != UNDEFINED) _stack = _l[ID][_l.pathname].split(',');
}
_st(function() {
_init();
_update(false);
}, 1);
if (_msie && _version >= 8)
_d.body.onhashchange = _listen;
else
_si(_listen, 50);
$('a[rel*=address:]').address();
}
};
var _getters = {
baseURL: function() {
var url = _l.href;
if (url.indexOf('#') != -1)
url = url.substr(0, url.indexOf('#'));
if (url.substr(url.length - 1) == '/')
url = url.substr(0, url.length - 1);
return url;
},
strict: function() {
return _opts.strict;
},
history: function() {
return _opts.history;
},
tracker: function() {
return _opts.tracker;
},
title: function() {
return _d.title;
},
value: function() {
if (!_supported) return null;
return _dc(_strictCheck(_ieLocal(_value, FALSE), FALSE));
},
path: function() {
var value = this.value();
return (value.indexOf('?') != -1) ? value.split('?')[0] : value;
},
pathNames: function() {
var path = this.path();
var names = path.split('/');
if (path.substr(0, 1) == '/' || path.length == 0)
names.splice(0, 1);
if (path.substr(path.length - 1, 1) == '/')
names.splice(names.length - 1, 1);
return names;
},
queryString: function() {
var value = this.value();
var index = value.indexOf('?');
if (index != -1 && index < value.length)
return value.substr(index + 1);
},
parameter: function(param) {
var value = this.value();
var index = value.indexOf('?');
if (index != -1) {
value = value.substr(index + 1);
var params = value.split('&');
var p, i = params.length, r = [];
while(i--) {
p = params[i].split('=');
if (p[0] == param)
r.push(p[1]);
}
if (r.length != 0)
return r.length != 1 ? r : r[0];
}
},
parameterNames: function() {
var value = this.value();
var index = value.indexOf('?');
var names = [];
if (index != -1) {
value = value.substr(index + 1);
if (value != '' && value.indexOf('=') != -1) {
var params = value.split('&');
var i = 0;
while(i < params.length) {
names.push(params[i].split('=')[0]);
i++;
}
}
}
return names;
}
};
var _setters = {
strict: function(strict) {
_opts.strict = strict;
},
history: function(history) {
_opts.history = history;
},
tracker: function(tracker) {
_opts.tracker = tracker;
},
title: function(title) {
title = _dc(title);
_st(function() {
_title = _d.title = title;
if (_juststart && _frame && _frame.contentWindow && _frame.contentWindow.document) {
_frame.contentWindow.document.title = title;
_juststart = FALSE;
}
if (!_justset && _mozilla)
_l.replace(_l.href.indexOf('#') != -1 ? _l.href : _l.href + '#');
_justset = FALSE;
}, 50);
},
value: function(value) {
value = _ec(_dc(_strictCheck(value, TRUE)));
if (value == '/') value = '';
if (_value == value) return;
_justset = TRUE;
_value = value;
_silent = TRUE;
_update(true);
_stack[_h.length] = _value;
if (_safari) {
if (_opts.history) {
_l[ID][_l.pathname] = _stack.toString();
_length = _h.length + 1;
if (_version < 418) {
if (_l.search == '') {
_form.action = '#' + _value;
_form.submit();
}
} else if (_version < 523 || _value == '') {
var evt = _d.createEvent('MouseEvents');
evt.initEvent('click', TRUE, TRUE);
var anchor = _d.createElement('a');
anchor.href = '#' + _value;
anchor.dispatchEvent(evt);
} else {
_l.hash = '#' + _value;
}
} else {
_l.replace('#' + _value);
}
} else if (_value != _getHash()) {
if (_opts.history)
_l.hash = '#' + _ieLocal(_value, TRUE);
else
_l.replace('#' + _value);
}
if ((_msie && _version < 8) && _opts.history) {
_st(_htmlWrite, 50);
}
if (_safari)
_st(function(){ _silent = FALSE; }, 1);
else
_silent = FALSE;
}
};
var ID = 'jQueryAddress',
FUNCTION = 'function',
UNDEFINED = 'undefined',
TRUE = true,
FALSE = false,
_browser = $.browser,
_version = parseFloat($.browser.version),
_mozilla = _browser.mozilla,
_msie = _browser.msie,
_opera = _browser.opera,
_safari = _browser.safari,
_supported = FALSE,
_t = _getWindow(),
_d = _t.document,
_h = _t.history,
_l = _t.location,
_si = setInterval,
_st = setTimeout,
_dc = decodeURI,
_ec = encodeURI,
_agent = navigator.userAgent,
_frame,
_form,
_url,
_title = _d.title,
_length = _h.length,
_silent = FALSE,
_loaded = FALSE,
_justset = TRUE,
_juststart = TRUE,
_stack = [],
_listeners = {},
_value = _getHash(),
_api = {},
_opts = {history: TRUE, strict: TRUE};
if (_msie) {
_version = parseFloat(_agent.substr(_agent.indexOf('MSIE') + 4));
if (_d.documentMode && _d.documentMode != _version)
_version = _d.documentMode != 8 ? 7 : 8;
}
_supported =
(_mozilla && _version >= 1) ||
(_msie && _version >= 6) ||
(_opera && _version >= 9.5) ||
(_safari && _version >= 312);
if (_supported) {
for (var i = 1; i < _length; i++)
_stack.push('');
_stack.push(_getHash());
if (_msie && _l.hash != _getHash())
_l.hash = '#' + _ieLocal(_getHash(), TRUE);
if (_opera)
history.navigationMode = 'compatible';
_searchScript(document);
var _qi = _url.indexOf('?');
if (_url && _qi > -1) {
var param, params = _url.substr(_qi + 1).split('&');
for (var i = 0, p; p = params[i]; i++) {
param = p.split('=');
if (/^(history|strict)$/.test(param[0])) {
_opts[param[0]] = (isNaN(param[1]) ? /^(true|yes)$/i.test(param[1]) : (parseInt(param[1]) != 0));
}
if (/^tracker$/.test(param[0]))
_opts[param[0]] = param[1];
}
}
$(_load);
} else if ((!_supported && _l.href.indexOf('#') != -1) ||
(_safari && _version < 418 && _l.href.indexOf('#') != -1 && _l.search != '')){
_d.open();
_d.write('');
_d.close();
} else {
_track();
}
$.each(('init,change,internalChange,externalChange').split(','), function(i, name){
_api[name] = function(data, fn){
$($.address).bind(name, fn || data, fn && data);
return this;
};
});
$.each(('strict,history,tracker,title,value').split(','), function(i, name){
_api[name] = function(value){
if (typeof value != 'undefined') {
if (_supported)
_setters[name](value);
return $.address;
} else {
return _getters[name]();
}
};
});
$.each(('baseURL,path,pathNames,queryString,parameter,parameterNames').split(','), function(i, name){
_api[name] = function(value){
return _getters[name](value);
};
});
return _api;
})();
$.fn.address = function (fn) {
$(this).click(function() {
var value = fn ? fn.call(this) :
/address:/.test($(this).attr('rel')) ? $(this).attr('rel').split('address:')[1].split(' ')[0] :
$(this).attr('href').replace(/^#/, '');
$.address.value(value);
return false;
});
};
}(jQuery));