jquery.address-1.6.js 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. /*! jQuery Address v.1.6 | (c) 2009, 2013 Rostislav Hristov | jquery.org/license */
  2. (function ($) {
  3. $.address = (function () {
  4. var _trigger = function(name) {
  5. var e = $.extend($.Event(name), (function() {
  6. var parameters = {},
  7. parameterNames = $.address.parameterNames();
  8. for (var i = 0, l = parameterNames.length; i < l; i++) {
  9. parameters[parameterNames[i]] = $.address.parameter(parameterNames[i]);
  10. }
  11. return {
  12. value: $.address.value(),
  13. path: $.address.path(),
  14. pathNames: $.address.pathNames(),
  15. parameterNames: parameterNames,
  16. parameters: parameters,
  17. queryString: $.address.queryString()
  18. };
  19. }).call($.address));
  20. $($.address).trigger(e);
  21. return e;
  22. },
  23. _array = function(obj) {
  24. return Array.prototype.slice.call(obj);
  25. },
  26. _bind = function(value, data, fn) {
  27. $().bind.apply($($.address), Array.prototype.slice.call(arguments));
  28. return $.address;
  29. },
  30. _unbind = function(value, fn) {
  31. $().unbind.apply($($.address), Array.prototype.slice.call(arguments));
  32. return $.address;
  33. },
  34. _supportsState = function() {
  35. return (_h.pushState && _opts.state !== UNDEFINED);
  36. },
  37. _hrefState = function() {
  38. return ('/' + _l.pathname.replace(new RegExp(_opts.state), '') +
  39. _l.search + (_hrefHash() ? '#' + _hrefHash() : '')).replace(_re, '/');
  40. },
  41. _hrefHash = function() {
  42. var index = _l.href.indexOf('#');
  43. return index != -1 ? _l.href.substr(index + 1) : '';
  44. },
  45. _href = function() {
  46. return _supportsState() ? _hrefState() : _hrefHash();
  47. },
  48. _window = function() {
  49. try {
  50. return top.document !== UNDEFINED && top.document.title !== UNDEFINED && top.jQuery !== UNDEFINED &&
  51. top.jQuery.address !== UNDEFINED && top.jQuery.address.frames() !== false ? top : window;
  52. } catch (e) {
  53. return window;
  54. }
  55. },
  56. _js = function() {
  57. return 'javascript';
  58. },
  59. _strict = function(value) {
  60. value = value.toString();
  61. return (_opts.strict && value.substr(0, 1) != '/' ? '/' : '') + value;
  62. },
  63. _cssint = function(el, value) {
  64. return parseInt(el.css(value), 10);
  65. },
  66. _listen = function() {
  67. if (!_silent) {
  68. var hash = _href(),
  69. diff = decodeURI(_value) != decodeURI(hash);
  70. if (diff) {
  71. if (_msie && _version < 7) {
  72. _l.reload();
  73. } else {
  74. if (_msie && !_hashchange && _opts.history) {
  75. _st(_html, 50);
  76. }
  77. _value = hash;
  78. _update(FALSE);
  79. }
  80. }
  81. }
  82. },
  83. _update = function(internal) {
  84. _st(_track, 10);
  85. return _trigger(CHANGE).isDefaultPrevented() ||
  86. _trigger(internal ? INTERNAL_CHANGE : EXTERNAL_CHANGE).isDefaultPrevented();
  87. },
  88. _track = function() {
  89. if (_opts.tracker !== 'null' && _opts.tracker !== NULL) {
  90. var fn = $.isFunction(_opts.tracker) ? _opts.tracker : _t[_opts.tracker],
  91. value = (_l.pathname + _l.search +
  92. ($.address && !_supportsState() ? $.address.value() : ''))
  93. .replace(/\/\//, '/').replace(/^\/$/, '');
  94. if ($.isFunction(fn)) {
  95. fn(value);
  96. } else if ($.isFunction(_t.urchinTracker)) {
  97. _t.urchinTracker(value);
  98. } else if (_t.pageTracker !== UNDEFINED && $.isFunction(_t.pageTracker._trackPageview)) {
  99. _t.pageTracker._trackPageview(value);
  100. } else if (_t._gaq !== UNDEFINED && $.isFunction(_t._gaq.push)) {
  101. _t._gaq.push(['_trackPageview', decodeURI(value)]);
  102. }
  103. }
  104. },
  105. _html = function() {
  106. var src = _js() + ':' + FALSE + ';document.open();document.writeln(\'<html><head><title>' +
  107. _d.title.replace(/\'/g, '\\\'') + '</title><script>var ' + ID + ' = "' + encodeURIComponent(_href()).replace(/\'/g, '\\\'') +
  108. (_d.domain != _l.hostname ? '";document.domain="' + _d.domain : '') +
  109. '";</' + 'script></head></html>\');document.close();';
  110. if (_version < 7) {
  111. _frame.src = src;
  112. } else {
  113. _frame.contentWindow.location.replace(src);
  114. }
  115. },
  116. _options = function() {
  117. if (_url && _qi != -1) {
  118. var i, param, params = _url.substr(_qi + 1).split('&');
  119. for (i = 0; i < params.length; i++) {
  120. param = params[i].split('=');
  121. if (/^(autoUpdate|history|strict|wrap)$/.test(param[0])) {
  122. _opts[param[0]] = (isNaN(param[1]) ? /^(true|yes)$/i.test(param[1]) : (parseInt(param[1], 10) !== 0));
  123. }
  124. if (/^(state|tracker)$/.test(param[0])) {
  125. _opts[param[0]] = param[1];
  126. }
  127. }
  128. _url = NULL;
  129. }
  130. _value = _href();
  131. },
  132. _load = function() {
  133. if (!_loaded) {
  134. _loaded = TRUE;
  135. _options();
  136. $('a[rel*="address:"]').address();
  137. if (_opts.wrap) {
  138. var body = $('body'),
  139. wrap = $('body > *')
  140. .wrapAll('<div style="padding:' +
  141. (_cssint(body, 'marginTop') + _cssint(body, 'paddingTop')) + 'px ' +
  142. (_cssint(body, 'marginRight') + _cssint(body, 'paddingRight')) + 'px ' +
  143. (_cssint(body, 'marginBottom') + _cssint(body, 'paddingBottom')) + 'px ' +
  144. (_cssint(body, 'marginLeft') + _cssint(body, 'paddingLeft')) + 'px;" />')
  145. .parent()
  146. .wrap('<div id="' + ID + '" style="height:100%;overflow:auto;position:relative;' +
  147. (_webkit && !window.statusbar.visible ? 'resize:both;' : '') + '" />');
  148. $('html, body')
  149. .css({
  150. height: '100%',
  151. margin: 0,
  152. padding: 0,
  153. overflow: 'hidden'
  154. });
  155. if (_webkit) {
  156. $('<style type="text/css" />')
  157. .appendTo('head')
  158. .text('#' + ID + '::-webkit-resizer { background-color: #fff; }');
  159. }
  160. }
  161. if (_msie && !_hashchange) {
  162. var frameset = _d.getElementsByTagName('frameset')[0];
  163. _frame = _d.createElement((frameset ? '' : 'i') + 'frame');
  164. _frame.src = _js() + ':' + FALSE;
  165. if (frameset) {
  166. frameset.insertAdjacentElement('beforeEnd', _frame);
  167. frameset[frameset.cols ? 'cols' : 'rows'] += ',0';
  168. _frame.noResize = TRUE;
  169. _frame.frameBorder = _frame.frameSpacing = 0;
  170. } else {
  171. _frame.style.display = 'none';
  172. _frame.style.width = _frame.style.height = 0;
  173. _frame.tabIndex = -1;
  174. _d.body.insertAdjacentElement('afterBegin', _frame);
  175. }
  176. _st(function() {
  177. $(_frame).bind('load', function() {
  178. var win = _frame.contentWindow;
  179. _value = win[ID] !== UNDEFINED ? win[ID] : '';
  180. if (_value != _href()) {
  181. _update(FALSE);
  182. _l.hash = _value;
  183. }
  184. });
  185. if (_frame.contentWindow[ID] === UNDEFINED) {
  186. _html();
  187. }
  188. }, 50);
  189. }
  190. _st(function() {
  191. _trigger('init');
  192. _update(FALSE);
  193. }, 1);
  194. if (!_supportsState()) {
  195. if ((_msie && _version > 7) || (!_msie && _hashchange)) {
  196. if (_t.addEventListener) {
  197. _t.addEventListener(HASH_CHANGE, _listen, FALSE);
  198. } else if (_t.attachEvent) {
  199. _t.attachEvent('on' + HASH_CHANGE, _listen);
  200. }
  201. } else {
  202. _si(_listen, 50);
  203. }
  204. }
  205. if ('state' in window.history) {
  206. $(window).trigger('popstate');
  207. }
  208. }
  209. },
  210. _popstate = function() {
  211. if (decodeURI(_value) != decodeURI(_href())) {
  212. _value = _href();
  213. _update(FALSE);
  214. }
  215. },
  216. _unload = function() {
  217. if (_t.removeEventListener) {
  218. _t.removeEventListener(HASH_CHANGE, _listen, FALSE);
  219. } else if (_t.detachEvent) {
  220. _t.detachEvent('on' + HASH_CHANGE, _listen);
  221. }
  222. },
  223. _uaMatch = function(ua) {
  224. ua = ua.toLowerCase();
  225. var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
  226. /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
  227. /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
  228. /(msie) ([\w.]+)/.exec( ua ) ||
  229. ua.indexOf('compatible') < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
  230. [];
  231. return {
  232. browser: match[ 1 ] || '',
  233. version: match[ 2 ] || '0'
  234. };
  235. },
  236. _detectBrowser = function() {
  237. var browser = {},
  238. matched = _uaMatch(navigator.userAgent);
  239. if (matched.browser) {
  240. browser[matched.browser] = true;
  241. browser.version = matched.version;
  242. }
  243. if (browser.chrome) {
  244. browser.webkit = true;
  245. } else if (browser.webkit) {
  246. browser.safari = true;
  247. }
  248. return browser;
  249. },
  250. UNDEFINED,
  251. NULL = null,
  252. ID = 'jQueryAddress',
  253. STRING = 'string',
  254. HASH_CHANGE = 'hashchange',
  255. INIT = 'init',
  256. CHANGE = 'change',
  257. INTERNAL_CHANGE = 'internalChange',
  258. EXTERNAL_CHANGE = 'externalChange',
  259. TRUE = true,
  260. FALSE = false,
  261. _opts = {
  262. autoUpdate: TRUE,
  263. history: TRUE,
  264. strict: TRUE,
  265. frames: TRUE,
  266. wrap: FALSE
  267. },
  268. _browser = _detectBrowser(),
  269. _version = parseFloat(_browser.version),
  270. _webkit = _browser.webkit || _browser.safari,
  271. _msie = !$.support.opacity,
  272. _t = _window(),
  273. _d = _t.document,
  274. _h = _t.history,
  275. _l = _t.location,
  276. _si = setInterval,
  277. _st = setTimeout,
  278. _re = /\/{2,9}/g,
  279. _agent = navigator.userAgent,
  280. _hashchange = 'on' + HASH_CHANGE in _t,
  281. _frame,
  282. _form,
  283. _url = $('script:last').attr('src'),
  284. _qi = _url ? _url.indexOf('?') : -1,
  285. _title = _d.title,
  286. _silent = FALSE,
  287. _loaded = FALSE,
  288. _juststart = TRUE,
  289. _updating = FALSE,
  290. _listeners = {},
  291. _value = _href();
  292. if (_msie) {
  293. _version = parseFloat(_agent.substr(_agent.indexOf('MSIE') + 4));
  294. if (_d.documentMode && _d.documentMode != _version) {
  295. _version = _d.documentMode != 8 ? 7 : 8;
  296. }
  297. var pc = _d.onpropertychange;
  298. _d.onpropertychange = function() {
  299. if (pc) {
  300. pc.call(_d);
  301. }
  302. if (_d.title != _title && _d.title.indexOf('#' + _href()) != -1) {
  303. _d.title = _title;
  304. }
  305. };
  306. }
  307. if (_h.navigationMode) {
  308. _h.navigationMode = 'compatible';
  309. }
  310. if (document.readyState == 'complete') {
  311. var interval = setInterval(function() {
  312. if ($.address) {
  313. _load();
  314. clearInterval(interval);
  315. }
  316. }, 50);
  317. } else {
  318. _options();
  319. $(_load);
  320. }
  321. $(window).bind('popstate', _popstate).bind('unload', _unload);
  322. return {
  323. bind: function(type, data, fn) {
  324. return _bind.apply(this, _array(arguments));
  325. },
  326. unbind: function(type, fn) {
  327. return _unbind.apply(this, _array(arguments));
  328. },
  329. init: function(data, fn) {
  330. return _bind.apply(this, [INIT].concat(_array(arguments)));
  331. },
  332. change: function(data, fn) {
  333. return _bind.apply(this, [CHANGE].concat(_array(arguments)));
  334. },
  335. internalChange: function(data, fn) {
  336. return _bind.apply(this, [INTERNAL_CHANGE].concat(_array(arguments)));
  337. },
  338. externalChange: function(data, fn) {
  339. return _bind.apply(this, [EXTERNAL_CHANGE].concat(_array(arguments)));
  340. },
  341. baseURL: function() {
  342. var url = _l.href;
  343. if (url.indexOf('#') != -1) {
  344. url = url.substr(0, url.indexOf('#'));
  345. }
  346. if (/\/$/.test(url)) {
  347. url = url.substr(0, url.length - 1);
  348. }
  349. return url;
  350. },
  351. autoUpdate: function(value) {
  352. if (value !== UNDEFINED) {
  353. _opts.autoUpdate = value;
  354. return this;
  355. }
  356. return _opts.autoUpdate;
  357. },
  358. history: function(value) {
  359. if (value !== UNDEFINED) {
  360. _opts.history = value;
  361. return this;
  362. }
  363. return _opts.history;
  364. },
  365. state: function(value) {
  366. if (value !== UNDEFINED) {
  367. _opts.state = value;
  368. var hrefState = _hrefState();
  369. if (_opts.state !== UNDEFINED) {
  370. if (_h.pushState) {
  371. if (hrefState.substr(0, 3) == '/#/') {
  372. _l.replace(_opts.state.replace(/^\/$/, '') + hrefState.substr(2));
  373. }
  374. } else if (hrefState != '/' && hrefState.replace(/^\/#/, '') != _hrefHash()) {
  375. _st(function() {
  376. _l.replace(_opts.state.replace(/^\/$/, '') + '/#' + hrefState);
  377. }, 1);
  378. }
  379. }
  380. return this;
  381. }
  382. return _opts.state;
  383. },
  384. frames: function(value) {
  385. if (value !== UNDEFINED) {
  386. _opts.frames = value;
  387. _t = _window();
  388. return this;
  389. }
  390. return _opts.frames;
  391. },
  392. strict: function(value) {
  393. if (value !== UNDEFINED) {
  394. _opts.strict = value;
  395. return this;
  396. }
  397. return _opts.strict;
  398. },
  399. tracker: function(value) {
  400. if (value !== UNDEFINED) {
  401. _opts.tracker = value;
  402. return this;
  403. }
  404. return _opts.tracker;
  405. },
  406. wrap: function(value) {
  407. if (value !== UNDEFINED) {
  408. _opts.wrap = value;
  409. return this;
  410. }
  411. return _opts.wrap;
  412. },
  413. update: function() {
  414. _updating = TRUE;
  415. this.value(_value);
  416. _updating = FALSE;
  417. return this;
  418. },
  419. title: function(value) {
  420. if (value !== UNDEFINED) {
  421. _st(function() {
  422. _title = _d.title = value;
  423. if (_juststart && _frame && _frame.contentWindow && _frame.contentWindow.document) {
  424. _frame.contentWindow.document.title = value;
  425. _juststart = FALSE;
  426. }
  427. }, 50);
  428. return this;
  429. }
  430. return _d.title;
  431. },
  432. value: function(value) {
  433. if (value !== UNDEFINED) {
  434. value = _strict(value);
  435. if (_value == value && !_updating) {
  436. return;
  437. }
  438. _value = value;
  439. if (_opts.autoUpdate || _updating) {
  440. if (_update(TRUE)) {
  441. return this;
  442. }
  443. if (_supportsState()) {
  444. _h[_opts.history ? 'pushState' : 'replaceState']({}, '',
  445. _opts.state.replace(/\/$/, '') + (_value === '' ? '/' : _value));
  446. } else {
  447. _silent = TRUE;
  448. if (_webkit) {
  449. if (_opts.history) {
  450. _l.hash = '#' + _value;
  451. } else {
  452. _l.replace('#' + _value);
  453. }
  454. } else if (_value != _href()) {
  455. if (_opts.history) {
  456. _l.hash = '#' + _value;
  457. } else {
  458. _l.replace('#' + _value);
  459. }
  460. }
  461. if ((_msie && !_hashchange) && _opts.history) {
  462. _st(_html, 50);
  463. }
  464. if (_webkit) {
  465. _st(function(){ _silent = FALSE; }, 1);
  466. } else {
  467. _silent = FALSE;
  468. }
  469. }
  470. }
  471. return this;
  472. }
  473. return _strict(_value);
  474. },
  475. path: function(value) {
  476. if (value !== UNDEFINED) {
  477. var qs = this.queryString(),
  478. hash = this.hash();
  479. this.value(value + (qs ? '?' + qs : '') + (hash ? '#' + hash : ''));
  480. return this;
  481. }
  482. return _strict(_value).split('#')[0].split('?')[0];
  483. },
  484. pathNames: function() {
  485. var path = this.path(),
  486. names = path.replace(_re, '/').split('/');
  487. if (path.substr(0, 1) == '/' || path.length === 0) {
  488. names.splice(0, 1);
  489. }
  490. if (path.substr(path.length - 1, 1) == '/') {
  491. names.splice(names.length - 1, 1);
  492. }
  493. return names;
  494. },
  495. queryString: function(value) {
  496. if (value !== UNDEFINED) {
  497. var hash = this.hash();
  498. this.value(this.path() + (value ? '?' + value : '') + (hash ? '#' + hash : ''));
  499. return this;
  500. }
  501. var arr = _value.split('?');
  502. return arr.slice(1, arr.length).join('?').split('#')[0];
  503. },
  504. parameter: function(name, value, append) {
  505. var i, params;
  506. if (value !== UNDEFINED) {
  507. var names = this.parameterNames();
  508. params = [];
  509. value = value === UNDEFINED || value === NULL ? '' : value.toString();
  510. for (i = 0; i < names.length; i++) {
  511. var n = names[i],
  512. v = this.parameter(n);
  513. if (typeof v == STRING) {
  514. v = [v];
  515. }
  516. if (n == name) {
  517. v = (value === NULL || value === '') ? [] :
  518. (append ? v.concat([value]) : [value]);
  519. }
  520. for (var j = 0; j < v.length; j++) {
  521. params.push(n + '=' + v[j]);
  522. }
  523. }
  524. if ($.inArray(name, names) == -1 && value !== NULL && value !== '') {
  525. params.push(name + '=' + value);
  526. }
  527. this.queryString(params.join('&'));
  528. return this;
  529. }
  530. value = this.queryString();
  531. if (value) {
  532. var r = [];
  533. params = value.split('&');
  534. for (i = 0; i < params.length; i++) {
  535. var p = params[i].split('=');
  536. if (p[0] == name) {
  537. r.push(p.slice(1).join('='));
  538. }
  539. }
  540. if (r.length !== 0) {
  541. return r.length != 1 ? r : r[0];
  542. }
  543. }
  544. },
  545. parameterNames: function() {
  546. var qs = this.queryString(),
  547. names = [];
  548. if (qs && qs.indexOf('=') != -1) {
  549. var params = qs.split('&');
  550. for (var i = 0; i < params.length; i++) {
  551. var name = params[i].split('=')[0];
  552. if ($.inArray(name, names) == -1) {
  553. names.push(name);
  554. }
  555. }
  556. }
  557. return names;
  558. },
  559. hash: function(value) {
  560. if (value !== UNDEFINED) {
  561. this.value(_value.split('#')[0] + (value ? '#' + value : ''));
  562. return this;
  563. }
  564. var arr = _value.split('#');
  565. return arr.slice(1, arr.length).join('#');
  566. }
  567. };
  568. })();
  569. $.fn.address = function(fn) {
  570. $(this).each(function(index) {
  571. if (!$(this).data('address')) {
  572. $(this).on('click', function(e) {
  573. if (e.shiftKey || e.ctrlKey || e.metaKey || e.which == 2) {
  574. return true;
  575. }
  576. var target = e.currentTarget;
  577. if ($(target).is('a')) {
  578. e.preventDefault();
  579. var value = fn ? fn.call(target) :
  580. /address:/.test($(target).attr('rel')) ? $(target).attr('rel').split('address:')[1].split(' ')[0] :
  581. $.address.state() !== undefined && !/^\/?$/.test($.address.state()) ?
  582. $(target).attr('href').replace(new RegExp('^(.*' + $.address.state() + '|\\.)'), '') :
  583. $(target).attr('href').replace(/^(#\!?|\.)/, '');
  584. $.address.value(value);
  585. }
  586. }).on('submit', function(e) {
  587. var target = e.currentTarget;
  588. if ($(target).is('form')) {
  589. e.preventDefault();
  590. var action = $(target).attr('action'),
  591. value = fn ? fn.call(target) : (action.indexOf('?') != -1 ? action.replace(/&$/, '') : action + '?') +
  592. $(target).serialize();
  593. $.address.value(value);
  594. }
  595. }).data('address', true);
  596. }
  597. });
  598. return this;
  599. };
  600. })(jQuery);