include request info on transport exception, sanity check tag parser results
[ajatus.git] / js / ajatus.history.js
blob59fde869980833ef6457570b3cb368fdee9d424f
1 /*
2 * This file is part of
4 * Ajatus - Distributed CRM
5 * @requires jQuery v1.2.1
6 *
7 * Copyright (c) 2007 Jerry Jalava <jerry.jalava@gmail.com>
8 * Copyright (c) 2007 Nemein Oy <http://nemein.com>
9 * Website: http://ajatus.info
10 * Licensed under the GPL license
11 * http://www.gnu.org/licenses/gpl.html
15 (function($){
16 $.ajatus = $.ajatus || {};
18 $.ajatus.history = {
19 _handler: false,
20 last_checked: ''
22 $.extend($.ajatus.history, {
23 init: function() {
24 $.ajatus.history._handler = new $.ajatus.history.handler;
25 $.ajatus.history._handler.initialize(function(){
26 $.ajatus.tabs.set_active_by_hash('#view.frontpage');
27 $.ajatus.views.system.frontpage.render();
28 });
30 add_map: function(hash, action) {
31 $.ajatus.history._handler.add_map(hash, action);
33 add_dynamic_map: function() {
34 var statics = [];
35 var mods = [];
36 var action = '';
37 if (arguments[0]) {
38 statics = arguments[0];
40 if (arguments[1]) {
41 mods = arguments[1];
43 if (arguments[2]) {
44 action = arguments[2];
46 $.ajatus.history._handler.add_dynamic_map(statics, mods, action);
48 update: function(hash) {
49 $.ajatus.history._handler.update(hash);
51 check: function(hash) {
52 if (typeof hash == 'undefined') {
53 var hash = $.ajatus.history._handler.get_hash();
55 // $.ajatus.debug('$.ajatus.history.check('+hash+')');
57 if ( !$.browser.mozilla
58 && $.ajatus.history.last_checked == hash)
60 //$.ajatus.debug('$.ajatus.history.check skipping hash '+hash);
61 return false;
63 $.ajatus.history.last_checked = hash;
65 if ($.ajatus.history._handler.executable(hash)) {
66 $.ajatus.tabs.set_active_by_hash(hash);
67 $.ajatus.history._handler.execute(hash);
68 return true;
71 return false;
73 navigate: function(count) {
74 if (typeof count == 'undefined') {
75 return;
78 $.ajatus.history._handler.navigate(count);
80 });
82 /**
83 * Base idea is taken from $.ajaxHistory plugin by Klaus Hartl
84 * Difference in this is that we evaluate predefined actions
85 * that are mapped against hashes.
87 $.ajatus.history.handler = function(){
89 var mappings = {};
90 var dyn_mappings = [];
92 var RESET_EVENT = 'historyReset';
94 var _currentHash = location.hash;
95 var _intervalId = null;
96 var _observeHistory;
98 this.update = function(){}; // empty function body for graceful degradation
100 this.add_map = function(hash, action) {
101 mappings[hash] = action;
104 this.add_dynamic_map = function(statics, mods, action) {
105 var hash = '#';
106 $.each(statics, function(i,s){
107 hash += s + '.';
109 var dyn_map = {
110 'hash': hash,
111 'statics': statics,
112 'mods': mods,
113 'action': action
115 dyn_mappings.push(dyn_map);
118 this.is_dyn_mapping = function(hash) {
119 var ch = hash.replace('#','');
120 var hash_parts = ch.split(/\./);
122 var ret_val = false;
123 var func_args = [];
124 var added_args = [];
125 $.each(dyn_mappings, function(i,dm){
126 var matched = false;
127 var matched_key = 0;
128 $.each(dm.statics, function(k,n){
129 if (hash_parts[k] == n) {
130 matched = true;
131 matched_key = k;
135 $.each(hash_parts, function(hk,hp){
136 if ( hk > matched_key
137 && hk < dm.mods)
140 if ($.inArray(hp, added_args) == -1) {
141 added_args.push(hp);
142 func_args.push(hp);
147 if (func_args.length > dm.mods) {
148 matched = false;
151 if (matched) {
152 ret_val = {
153 id: Number(i),
154 args: func_args
161 return ret_val;
164 this.executable = function(hash){
165 if (mappings[hash]) {
166 return true;
167 } else {
168 var dm_data = this.is_dyn_mapping(hash);
169 if (dm_data !== false) {
170 return true;
173 return false;
176 this.execute = function(hash){
177 //$.ajatus.debug('$.ajatus.extension.history.execute('+hash+')');
179 if (mappings[hash]) {
180 eval(mappings[hash]);
182 //$.ajatus.debug('$.ajatus.extension.history.execute evaled from mappings: '+mappings[hash]);
184 return true;
185 } else {
186 var dm_data = this.is_dyn_mapping(hash);
187 if (dm_data !== false) {
188 //$.ajatus.debug('$.ajatus.extension.history.execute hash is dynamic mapping. Evaling: '+dyn_mappings[dm_data.id].action);
190 var func = eval(dyn_mappings[dm_data.id].action);
191 func.apply(func, dm_data.args);
193 return true;
196 return false;
199 this.get_hash = function(){
200 var hash = '';
202 if ($.browser.safari) {
203 if (window.document.URL.indexOf('#') >= 0) {
204 hash = '#'+window.document.URL.split('#')[1];
206 } else {
207 hash = location.hash;
210 return hash;
213 // create custom event for state reset
214 var _defaultReset = function() {
216 $(window.document).bind(RESET_EVENT, _defaultReset);
218 if ($.browser.safari) {
220 var _backStack, _forwardStack, _addHistory; // for Safari
222 // establish back/forward stacks
223 $(function() {
224 _backStack = [];
225 _backStack.length = history.length;
226 _forwardStack = [];
228 var isFirst = false, initialized = false;
229 _addHistory = function(hash) {
230 _backStack.push(hash);
231 _forwardStack.length = 0; // clear forwardStack (true click occured)
232 isFirst = false;
235 this.update = function(hash) {
236 _currentHash = hash;
237 location.hash = hash;
238 _addHistory(_currentHash);
241 this.navigate = function(count) {
242 if (count < 0) {
243 var idx = (_backStack.length + count) - 1;
244 var newHash = _backStack[idx];
245 } else {
246 var idx = (_forwardStack.length - count) - 1;
247 var newHash = _forwardStack[idx];
250 if (typeof newHash != 'undefined') {
251 $.ajatus.history.update(newHash);
255 _observeHistory = function() {
256 var historyDelta = history.length - _backStack.length;
257 if (historyDelta) { // back or forward button has been pushed
258 isFirst = false;
259 if (historyDelta < 0) { // back button has been pushed
260 // move items to forward stack
261 for (var i = 0; i < Math.abs(historyDelta); i++) _forwardStack.unshift(_backStack.pop());
262 } else { // forward button has been pushed
263 // move items to back stack
264 for (var i = 0; i < historyDelta; i++) _backStack.push(_forwardStack.shift());
266 var cachedHash = _backStack[_backStack.length - 1];
267 _currentHash = location.hash;
269 $.ajatus.history.check(_currentHash);
270 } else if (typeof(_backStack[_backStack.length - 1]) == 'undefined' && !isFirst) {
271 if (location.hash == '') {
272 $(window.document).trigger(RESET_EVENT);
275 isFirst = true;
277 initialized = true;
279 } else {
280 this.update = function(hash) {
281 if (_currentHash != hash) {
282 location.hash = hash;
283 _currentHash = hash;
287 _observeHistory = function() {
288 if (location.hash) {
289 if (_currentHash != location.hash) {
290 _currentHash = location.hash;
291 $.ajatus.history.check(_currentHash);
293 } else if (_currentHash) {
294 _currentHash = '';
295 $(window.document).trigger(RESET_EVENT);
299 this.navigate = function(count) {
300 window.history.go(count);
304 this.initialize = function(callback) {
305 // custom callback to reset app state (no hash in url)
306 if (typeof callback == 'function') {
307 $(window.document).unbind(RESET_EVENT, _defaultReset).bind(RESET_EVENT, callback);
309 // look for hash in current URL (not Safari) and execute predefined action if one is found
310 if (location.hash && typeof _addHistory == 'undefined') {
311 $.ajatus.history.check(location.hash);
313 // start observer
314 if (_observeHistory && _intervalId == null) {
315 _intervalId = setInterval(_observeHistory, 200); // Safari needs at least 200 ms
320 })(jQuery);