4 * Ajatus - Distributed CRM
5 * @requires jQuery v1.2.1
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
16 $.ajatus
= $.ajatus
|| {};
22 $.extend($.ajatus
.history
, {
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();
30 add_map: function(hash
, action
) {
31 $.ajatus
.history
._handler
.add_map(hash
, action
);
33 add_dynamic_map: function() {
38 statics
= arguments
[0];
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);
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
);
73 navigate: function(count
) {
74 if (typeof count
== 'undefined') {
78 $.ajatus
.history
._handler
.navigate(count
);
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(){
90 var dyn_mappings
= [];
92 var RESET_EVENT
= 'historyReset';
94 var _currentHash
= location
.hash
;
95 var _intervalId
= null;
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
) {
106 $.each(statics
, function(i
,s
){
115 dyn_mappings
.push(dyn_map
);
118 this.is_dyn_mapping = function(hash
) {
119 var ch
= hash
.replace('#','');
120 var hash_parts
= ch
.split(/\./);
125 $.each(dyn_mappings
, function(i
,dm
){
128 $.each(dm
.statics
, function(k
,n
){
129 if (hash_parts
[k
] == n
) {
135 $.each(hash_parts
, function(hk
,hp
){
136 if ( hk
> matched_key
140 if ($.inArray(hp
, added_args
) == -1) {
147 if (func_args
.length
> dm
.mods
) {
164 this.executable = function(hash
){
165 if (mappings
[hash
]) {
168 var dm_data
= this.is_dyn_mapping(hash
);
169 if (dm_data
!== 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]);
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
);
199 this.get_hash = function(){
202 if ($.browser
.safari
) {
203 if (window
.document
.URL
.indexOf('#') >= 0) {
204 hash
= '#'+window
.document
.URL
.split('#')[1];
207 hash
= location
.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
225 _backStack
.length
= history
.length
;
228 var isFirst
= false, initialized
= false;
229 _addHistory = function(hash
) {
230 _backStack
.push(hash
);
231 _forwardStack
.length
= 0; // clear forwardStack (true click occured)
235 this.update = function(hash
) {
237 location
.hash
= hash
;
238 _addHistory(_currentHash
);
241 this.navigate = function(count
) {
243 var idx
= (_backStack
.length
+ count
) - 1;
244 var newHash
= _backStack
[idx
];
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
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
);
280 this.update = function(hash
) {
281 if (_currentHash
!= hash
) {
282 location
.hash
= hash
;
287 _observeHistory = function() {
289 if (_currentHash
!= location
.hash
) {
290 _currentHash
= location
.hash
;
291 $.ajatus
.history
.check(_currentHash
);
293 } else if (_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
);
314 if (_observeHistory
&& _intervalId
== null) {
315 _intervalId
= setInterval(_observeHistory
, 200); // Safari needs at least 200 ms