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