summaryrefslogtreecommitdiff
path: root/itjs/state.js
diff options
context:
space:
mode:
Diffstat (limited to 'itjs/state.js')
-rw-r--r--itjs/state.js120
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();
+}