diff options
Diffstat (limited to 'itjs/state.js')
-rw-r--r-- | itjs/state.js | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/itjs/state.js b/itjs/state.js new file mode 100644 index 0000000..70d9909 --- /dev/null +++ b/itjs/state.js @@ -0,0 +1,120 @@ +/** + * Generic state object (singleton), for supporting Ajax browser history + * + * $Id$ + * + */ +var it_state = +{ +it_iframe: null, +it_history_field: null, +it_state_saved: false, +it_store_handlers: [], +it_restore_handlers: [], + +/** + * Register a handler that gets called before creating a history entry + * @param p.object Object that contains handler method + * @param p.method Method of p.object to call + */ +register_store_handler: function(p) +{ + this.it_store_handlers[this.it_store_handlers.length] = p; +}, + + +/** + * Register a handler that gets called after restoring a history entry + * @param p.object Object that contains handler method + * @param p.method Method of p.object to call + * @param p.initial optional flag: if true, handler is called with initial empty state + */ +register_restore_handler: function(p) +{ + this.it_restore_handlers[this.it_restore_handlers.length] = p; + + // If we already have state data, call registered handler immediately. Yup this _is_ needed! + if (this.it_history_field && this.it_history_field.value) + p.object[p.method](); +}, + + +/** + * Create a new history entry, saving all values of it_state (asynchronously) + * Users must call this without parameter! + */ +new_history_entry: function(p) +{ + this.store_state(); + this.it_state_saved = true; + + if (!this.it_iframe && !(this.it_iframe = document.getElementById('it_state'))) + ED('it_state::new_history_entry(): it_state object not found!'); + + var idoc; + if ((idoc = it_get_iframe_document(this.it_iframe))) + { + idoc.title = document.title; + idoc.forms[0].submit(); + } + this.it_history_field = null; +}, + + +/** + * Restore state from history, called from iframe's onload handler but in main window's context + */ +restore_history: function() +{ + if (!this.it_iframe && !(this.it_iframe = document.getElementById('it_state'))) + ED('it_state::restore_history(): it_state object not found!'); + + var idoc = it_get_iframe_document(this.it_iframe); + this.it_history_field = idoc ? idoc.getElementById('state') : {}; // Work-around IE5 not returning iframe document + this.it_state_saved = false; + + if (this.it_history_field.value) + { + var res = eval('({' + this.it_history_field.value + '})'); + for (var key in res) + this[key] = res[key]; + } + + for (var i in this.it_restore_handlers) + { + if (this.it_history_field.value || (this.it_restore_handlers[i].initial && (!idoc || !idoc.location.href.match(/s=/)))) + this.it_restore_handlers[i].object[this.it_restore_handlers[i].method](); + } +}, + + +/** + * Call all store handlers and store state in it_history_field + */ +store_state: function() +{ + if (!this.it_iframe && !(this.it_iframe = document.getElementById('it_state'))) + ED('it_state::store_state(): it_state object not found!'); + + var idoc = it_get_iframe_document(this.it_iframe); + this.it_history_field = idoc ? idoc.getElementById('state') : {}; // Work-around IE5 not returning iframe document + + for (var i in this.it_store_handlers) + this.it_store_handlers[i].object[this.it_store_handlers[i].method](); + + var ser = []; + for (var key in this) + { + var value = this[key], type = typeof(value); + if (!key.match(/^it_/) && type.match(/boolean|number|string/)) + ser[ser.length] = key + ':' + ((type == 'string') ? "'" + value.replace(/([\\'])/g, '\\\1') + "'" : value); + } + + this.it_history_field.value = ser.join(','); +}/* NO COMMA */ +} + +function it_state_restore_history() +{ + it_state.restore_history(); +} |