Debug uses now pretty printing for better readability for objects
[ajatus.git] / js / ajatus.history.js
blob7d46fc6b002d2f9c1fca6048d228ee59f6f7c83f
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 enabled: true,
20 _handler: false,
21 last_checked: ''
23 $.extend($.ajatus.history, {
24 init: function() {
25 $.ajatus.history.enabled = typeof($.ajatus.history.handler) != 'undefined' ? true : false;
27 if ($.ajatus.history.enabled) {
28 $.ajatus.history._handler = new $.ajatus.history.handler;
29 $.ajatus.history._handler.initialize(function(){
30 $.ajatus.tabs.set_active_by_hash('#view.frontpage');
31 $.ajatus.views.system.frontpage.render();
32 });
35 add_map: function(hash, action) {
36 $.ajatus.history._handler.add_map(hash, action);
38 add_dynamic_map: function() {
39 var statics = [];
40 var mods = [];
41 var action = '';
42 if (arguments[0]) {
43 statics = arguments[0];
45 if (arguments[1]) {
46 mods = arguments[1];
48 if (arguments[2]) {
49 action = arguments[2];
51 $.ajatus.history._handler.add_dynamic_map(statics, mods, action);
53 update: function(hash) {
54 $.ajatus.history._handler.update(hash);
56 check: function(hash) {
57 if (typeof hash == 'undefined') {
58 var hash = $.ajatus.history._handler.get_hash();
60 // $.ajatus.debug('$.ajatus.history.check('+hash+')');
62 if ( !$.browser.mozilla
63 && $.ajatus.history.last_checked == hash)
65 //$.ajatus.debug('$.ajatus.history.check skipping hash '+hash);
66 return false;
68 $.ajatus.history.last_checked = hash;
70 if ($.ajatus.history._handler.executable(hash)) {
71 $.ajatus.tabs.set_active_by_hash(hash);
72 $.ajatus.history._handler.execute(hash);
73 return true;
76 return false;
78 navigate: function(count) {
79 if (typeof count == 'undefined') {
80 return;
83 $.ajatus.history._handler.navigate(count);
85 });
87 /**
88 * Base idea is taken from $.ajaxHistory plugin by Klaus Hartl
89 * Difference in this is that we evaluate predefined actions
90 * that are mapped against hashes.
92 $.ajatus.history.handler = function(){
94 var mappings = {};
95 var dyn_mappings = [];
97 var RESET_EVENT = 'historyReset';
99 var _currentHash = location.hash;
100 var _intervalId = null;
101 var _observeHistory;
103 this.update = function(){}; // empty function body for graceful degradation
105 this.add_map = function(hash, action) {
106 mappings[hash] = action;
109 this.add_dynamic_map = function(statics, mods, action) {
110 var hash = '#';
111 $.each(statics, function(i,s){
112 hash += s + '.';
114 var dyn_map = {
115 'hash': hash,
116 'statics': statics,
117 'mods': mods,
118 'action': action
120 dyn_mappings.push(dyn_map);
123 this.is_dyn_mapping = function(hash) {
124 var ch = hash.replace('#','');
125 var hash_parts = ch.split(/\./);
127 var ret_val = false;
128 var func_args = [];
129 $.each(dyn_mappings, function(i,dm){
130 var matched = false;
131 var matched_key = 0;
132 $.each(dm.statics, function(k,n){
133 if (hash_parts[k] == n) {
134 matched = true;
135 matched_key = k;
139 $.each(hash_parts, function(hk,hp){
140 if ( hk > matched_key
141 && hk <= dm.mods) {
142 func_args.push(hp);
146 if (matched) {
147 ret_val = {
148 id: Number(i),
149 args: func_args
154 return ret_val;
157 this.executable = function(hash){
158 if (mappings[hash]) {
159 return true;
160 } else {
161 var dm_data = this.is_dyn_mapping(hash);
162 if (dm_data !== false) {
163 return true;
166 return false;
169 this.execute = function(hash){
170 //$.ajatus.debug('$.ajatus.extension.history.execute('+hash+')');
172 if (mappings[hash]) {
173 eval(mappings[hash]);
175 //$.ajatus.debug('$.ajatus.extension.history.execute evaled from mappings: '+mappings[hash]);
177 return true;
178 } else {
179 var dm_data = this.is_dyn_mapping(hash);
180 if (dm_data !== false) {
181 //$.ajatus.debug('$.ajatus.extension.history.execute hash is dynamic mapping. Evaling: '+dyn_mappings[dm_data.id].action);
183 var func = eval(dyn_mappings[dm_data.id].action);
184 func.apply(func, dm_data.args);
186 return true;
189 return false;
192 this.get_hash = function(){
193 var hash = '';
195 if ($.browser.safari) {
196 if (window.document.URL.indexOf('#') >= 0) {
197 hash = '#'+window.document.URL.split('#')[1];
199 } else {
200 hash = location.hash;
203 return hash;
206 // create custom event for state reset
207 var _defaultReset = function() {
209 $(window.document).bind(RESET_EVENT, _defaultReset);
211 if ($.browser.safari) {
213 var _backStack, _forwardStack, _addHistory; // for Safari
215 // establish back/forward stacks
216 $(function() {
217 _backStack = [];
218 _backStack.length = history.length;
219 _forwardStack = [];
221 var isFirst = false, initialized = false;
222 _addHistory = function(hash) {
223 _backStack.push(hash);
224 _forwardStack.length = 0; // clear forwardStack (true click occured)
225 isFirst = false;
228 this.update = function(hash) {
229 _currentHash = hash;
230 location.hash = hash;
231 _addHistory(_currentHash);
234 this.navigate = function(count) {
235 if (count < 0) {
236 var idx = (_backStack.length + count) - 1;
237 var newHash = _backStack[idx];
238 } else {
239 var idx = (_forwardStack.length - count) - 1;
240 var newHash = _forwardStack[idx];
243 if (typeof newHash != 'undefined') {
244 $.ajatus.history.update(newHash);
248 _observeHistory = function() {
249 var historyDelta = history.length - _backStack.length;
250 if (historyDelta) { // back or forward button has been pushed
251 isFirst = false;
252 if (historyDelta < 0) { // back button has been pushed
253 // move items to forward stack
254 for (var i = 0; i < Math.abs(historyDelta); i++) _forwardStack.unshift(_backStack.pop());
255 } else { // forward button has been pushed
256 // move items to back stack
257 for (var i = 0; i < historyDelta; i++) _backStack.push(_forwardStack.shift());
259 var cachedHash = _backStack[_backStack.length - 1];
260 _currentHash = location.hash;
262 $.ajatus.history.check(_currentHash);
263 } else if (typeof(_backStack[_backStack.length - 1]) == 'undefined' && !isFirst) {
264 if (location.hash == '') {
265 $(window.document).trigger(RESET_EVENT);
268 isFirst = true;
270 initialized = true;
272 } else {
273 this.update = function(hash) {
274 location.hash = hash;
275 _currentHash = hash;
278 _observeHistory = function() {
279 if (location.hash) {
280 if (_currentHash != location.hash) {
281 _currentHash = location.hash;
282 $.ajatus.history.check(_currentHash);
284 } else if (_currentHash) {
285 _currentHash = '';
286 $(window.document).trigger(RESET_EVENT);
290 this.navigate = function(count) {
291 window.history.go(count);
295 this.initialize = function(callback) {
296 // custom callback to reset app state (no hash in url)
297 if (typeof callback == 'function') {
298 $(window.document).unbind(RESET_EVENT, _defaultReset).bind(RESET_EVENT, callback);
300 // look for hash in current URL (not Safari) and execute predefined action if one is found
301 if (location.hash && typeof _addHistory == 'undefined') {
302 $.ajatus.history.check(location.hash);
304 // start observer
305 if (_observeHistory && _intervalId == null) {
306 _intervalId = setInterval(_observeHistory, 200); // Safari needs at least 200 ms
311 })(jQuery);