details: http://www.bx.psu.edu/hg/galaxy/rev/5536d57237a3 changeset: 3626:5536d57237a3 user: Kanwei Li <kanwei@gmail.com> date: Fri Apr 09 18:09:54 2010 -0400 description: - Update jQuery.jStore, JSON2 - Fix issue with all local prefs being deleted on "collapse all" - Refactored history display code into galaxy.base diffstat: static/jStore.Flash.html | 19 - static/jStore.swf | 0 static/scripts/class.js | 80 + static/scripts/galaxy.base.js | 87 + static/scripts/jquery.jstore-all.js | 748 ----------- static/scripts/jquery.jstore.js | 1810 ++++++++++++++++++++++++++++ static/scripts/json2.js | 26 +- static/scripts/packed/class.js | 7 + static/scripts/packed/galaxy.base.js | 2 +- static/scripts/packed/jquery.jstore-all.js | 1 - static/scripts/packed/jquery.jstore.js | 17 + static/scripts/packed/json2.js | 2 +- templates/display_base.mako | 29 +- templates/history/display.mako | 264 +--- templates/history/view.mako | 259 +--- templates/page/display.mako | 272 +--- templates/root/history.mako | 222 +-- templates/workflow/editor.mako | 42 +- 18 files changed, 2216 insertions(+), 1671 deletions(-) diffs (truncated from 4199 to 3000 lines): diff -r a9402fc7ce1b -r 5536d57237a3 static/jStore.Flash.html --- a/static/jStore.Flash.html Fri Apr 09 13:02:15 2010 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> - <head> - <title>Flash External Object</title> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> - <script type="text/javascript"> - /** - * This function captures the flash_ready event. We need to relay this - * back to the parent so it knows flash is ready. - */ - function flash_ready(){ - parent.flash_ready(); - } - </script> - </head> - <body> - <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#versio..." width="1" height="1" id="jStoreFlash"><param name="allowScriptAccess" value="always" /><param name="movie" value="jStore.swf" /><param name="quality" value="high" /><param name="bgcolor" value="#ffcc00" /><embed src="jStore.swf" quality="high" bgcolor="#ffcc00" width="1" height="1" name="jStoreFlash" align="middle" allowScriptAccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" /></object> - </body> -</html> \ No newline at end of file diff -r a9402fc7ce1b -r 5536d57237a3 static/jStore.swf Binary file static/jStore.swf has changed diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/class.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/static/scripts/class.js Fri Apr 09 18:09:54 2010 -0400 @@ -0,0 +1,80 @@ +/*! + * Class definition + * + * Copyright (c) 2008 John Resig (http://ejohn.org/blog/simple-javascript-inheritance/) + * Inspired by base2 and Prototype + */ + +"use strict"; + +(function () { + + var initializing = false, + + fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; + + // The base Class implementation (does nothing) + this.Class = function(){}; + + // Create a new Class that inherits from this class + Class.extend = function (prop) + { + var _super = this.prototype; + + // Instantiate a base class (but only create the instance, don't run the init constructor) + initializing = true; + + var prototype = new this(); + + initializing = false; + + // Copy the properties over onto the new prototype + for (var name in prop) + { + + // Check if we're overwriting an existing function + prototype[name] = (typeof prop[name] === "function" && typeof _super[name] === "function" && fnTest.test(prop[name]) ? + + (function(name, fn) + { + return function() + { + var tmp = this._super; + + // Add a new ._super() method that is the same method + // but on the super-class + this._super = _super[name]; + + // The method only need to be bound temporarily, so we + // remove it when we're done executing + var ret = fn.apply(this, arguments); + this._super = tmp; + + return ret; + }; + }(name, prop[name])) : prop[name]); + } + + // The dummy class constructor + function Class() + { + // All construction is actually done in the init method + if (!initializing && this.init) + { + this.init.apply(this, arguments); + } + } + + // Populate our constructed prototype object + Class.prototype = prototype; + + // Enforce the constructor to be what we expect + Class.constructor = Class; + + // And make this class extendable + Class.extend = arguments.callee; + + return Class; + }; + +}()); diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/galaxy.base.js --- a/static/scripts/galaxy.base.js Fri Apr 09 13:02:15 2010 -0400 +++ b/static/scripts/galaxy.base.js Fri Apr 09 18:09:54 2010 -0400 @@ -275,6 +275,93 @@ }); } +function init_history_items(historywrapper, noinit) { + + var action = function() { + // Load saved state and show as necessary + try { + var stored = $.jStore.store("history_expand_state"); + if (stored) { + for (var id in stored) { + $("#" + id + " div.historyItemBody" ).show(); + } + } + } catch(err) { + // Something was wrong with values in storage, so clear storage + $.jStore.remove("history_expand_state"); + } + + // If Mozilla, hide scrollbars in hidden items since they cause animation bugs + if ( $.browser.mozilla ) { + $( "div.historyItemBody" ).each( function() { + if ( ! $(this).is( ":visible" ) ) $(this).find( "pre.peek" ).css( "overflow", "hidden" ); + }) + } + + historywrapper.each( function() { + var id = this.id; + var body = $(this).children( "div.historyItemBody" ); + var peek = body.find( "pre.peek" ) + $(this).children( ".historyItemTitleBar" ).find( ".historyItemTitle" ).wrap( "<a href='#'></a>" ).click( function() { + if ( body.is(":visible") ) { + // Hiding stuff here + if ( $.browser.mozilla ) { peek.css( "overflow", "hidden" ) } + body.slideUp( "fast" ); + + if (!noinit) { // Ignore embedded item actions + // Save setting + var prefs = $.jStore.store("history_expand_state"); + if (prefs) { + delete prefs[id]; + $.jStore.store("history_expand_state", prefs); + } + } + } else { + // Showing stuff here + body.slideDown( "fast", function() { + if ( $.browser.mozilla ) { peek.css( "overflow", "auto" ); } + }); + + if (!noinit) { + // Save setting + var prefs = $.jStore.store("history_expand_state"); + if (prefs === undefined) { prefs = {}; } + prefs[id] = true; + $.jStore.store("history_expand_state", prefs); + } + } + return false; + }); + }); + + // Generate 'collapse all' link + $("#top-links > a.toggle").click( function() { + var prefs = $.jStore.store("history_expand_state"); + if (prefs === undefined) { prefs = {}; } + $( "div.historyItemBody:visible" ).each( function() { + if ( $.browser.mozilla ) { + $(this).find( "pre.peek" ).css( "overflow", "hidden" ); + } + $(this).slideUp( "fast" ); + if (prefs) { + delete prefs[$(this).parent().attr("id")]; + } + }); + $.jStore.store("history_expand_state", prefs); + }).show(); + } + + if (noinit) { + action(); + } else { + // Load jStore for local storage + $.jStore.init("galaxy"); // Auto-select best storage + $.jStore.engineReady(function() { + action(); + }); + } +} + $(document).ready( function() { // Links with confirmation $( "a[confirm]" ).click( function() { diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/jquery.jstore-all.js --- a/static/scripts/jquery.jstore-all.js Fri Apr 09 13:02:15 2010 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,748 +0,0 @@ -/* - * jStore - Persistent Client-Side Storage - * - * Copyright (c) 2009 Eric Garside (http://eric.garside.name) - * - * Dual licensed under: - * MIT: http://www.opensource.org/licenses/mit-license.php - * GPLv3: http://www.opensource.org/licenses/gpl-3.0.html - *//** - * Javascript Class Framework - * - * Copyright (c) 2008 John Resig (http://ejohn.org/blog/simple-javascript-inheritance/) - * Inspired by base2 and Prototype - */ -(function(){ - var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; - - // The base Class implementation (does nothing) - this.Class = function(){}; - - // Create a new Class that inherits from this class - Class.extend = function(prop) { - var _super = this.prototype; - - // Instantiate a base class (but only create the instance, - // don't run the init constructor) - initializing = true; - var prototype = new this(); - initializing = false; - - // Copy the properties over onto the new prototype - for (var name in prop) { - // Check if we're overwriting an existing function - prototype[name] = typeof prop[name] == "function" && - typeof _super[name] == "function" && fnTest.test(prop[name]) ? - (function(name, fn){ - return function() { - var tmp = this._super; - - // Add a new ._super() method that is the same method - // but on the super-class - this._super = _super[name]; - - // The method only need to be bound temporarily, so we - // remove it when we're done executing - var ret = fn.apply(this, arguments); - this._super = tmp; - - return ret; - }; - })(name, prop[name]) : - prop[name]; - } - - // The dummy class constructor - function Class() { - // All construction is actually done in the init method - if ( !initializing && this.init ) - this.init.apply(this, arguments); - } - - // Populate our constructed prototype object - Class.prototype = prototype; - - // Enforce the constructor to be what we expect - Class.constructor = Class; - - // And make this class extendable - Class.extend = arguments.callee; - - return Class; - }; -})(); -/* - * jStore Delegate Framework - * Copyright (c) 2009 Eric Garside (http://eric.garside.name) - */ -(function($){ - - this.jStoreDelegate = Class.extend({ - init: function(parent){ - // The Object this delgate operates for - this.parent = parent; - // Container for callbacks to dispatch. - // eventType => [ callback, callback, ... ] - this.callbacks = {}; - }, - bind: function(event, callback){ - if ( !$.isFunction(callback) ) return this; - if ( !this.callbacks[ event ] ) this.callbacks[ event ] = []; - - this.callbacks[ event ].push(callback); - - return this; - }, - trigger: function(){ - var parent = this.parent, - args = [].slice.call(arguments), - event = args.shift(), - handlers = this.callbacks[ event ]; - - if ( !handlers ) return false; - - $.each(handlers, function(){ this.apply(parent, args) }); - return this; - } - }); - -})(jQuery);/** - * jStore-jQuery Interface - * Copyright (c) 2009 Eric Garside (http://eric.garside.name) - */ -(function($){ - - // Setup the jStore namespace in jQuery for options storage - $.jStore = {}; - - // Seed the options in - $.extend($.jStore, { - EngineOrder: [], - // Engines should put their availability tests within jStore.Availability - Availability: {}, - // Defined engines should enter themselves into the jStore.Engines - Engines: {}, - // Instanciated engines should exist within jStore.Instances - Instances: {}, - // The current engine to use for storage - CurrentEngine: null, - // Provide global settings for overwriting - defaults: { - project: null, - engine: null, - autoload: true, - flash: 'jStore.Flash.html' - }, - // Boolean for ready state handling - isReady: false, - // Boolean for flash ready state handling - isFlashReady: false, - // An event delegate - delegate: new jStoreDelegate($.jStore) - .bind('jStore-ready', function(engine){ - $.jStore.isReady = true; - if ($.jStore.defaults.autoload) engine.connect(); - }) - .bind('flash-ready', function(){ - $.jStore.isFlashReady = true; - }) - }); - - // Enable ready callback for jStore - $.jStore.ready = function(callback){ - if ($.jStore.isReady) callback.apply($.jStore, [$.jStore.CurrentEngine]); - else $.jStore.delegate.bind('jStore-ready', callback); - } - - // Enable failure callback registration for jStore - $.jStore.fail = function(callback){ - $.jStore.delegate.bind('jStore-failure', callback); - } - - // Enable ready callback for Flash - $.jStore.flashReady = function(callback){ - if ($.jStore.isFlashReady) callback.apply($.jStore, [$.jStore.CurrentEngine]); - else $.jStore.delegate.bind('flash-ready', callback); - } - - // Enable and test an engine - $.jStore.use = function(engine, project, identifier){ - project = project || $.jStore.defaults.project || location.hostname.replace(/\./g, '-') || 'unknown'; - - var e = $.jStore.Engines[engine.toLowerCase()] || null, - name = (identifier ? identifier + '.' : '') + project + '.' + engine; - - if ( !e ) throw 'JSTORE_ENGINE_UNDEFINED'; - - // Instanciate the engine - e = new e(project, name); - - // Prevent against naming conflicts - if ($.jStore.Instances[name]) throw 'JSTORE_JRI_CONFLICT'; - - // Test the engine - if (e.isAvailable()){ - $.jStore.Instances[name] = e; // The Easy Way - if (!$.jStore.CurrentEngine){ - $.jStore.CurrentEngine = e; - } - $.jStore.delegate.trigger('jStore-ready', e); - } else { - if (!e.autoload) // Not available - throw 'JSTORE_ENGINE_UNAVILABLE'; - else { // The hard way - e.included(function(){ - if (this.isAvailable()) { // Worked out - $.jStore.Instances[name] = this; - // If there is no current engine, use this one - if (!$.jStore.CurrentEngine){ - $.jStore.CurrentEngine = this; - } - $.jStore.delegate.trigger('jStore-ready', this); - } - else $.jStore.delegate.trigger('jStore-failure', this); - }).include(); - } - } - } - - // Set the current storage engine - $.jStore.setCurrentEngine = function(name){ - if (!$.jStore.Instances.length ) // If no instances exist, attempt to load one - return $.jStore.FindEngine(); - - if (!name && $.jStore.Instances.length >= 1) { // If no name is specified, use the first engine - $.jStore.delegate.trigger('jStore-ready', $.jStore.Instances[0]); - return $.jStore.CurrentEngine = $.jStore.Instances[0]; - } - - if (name && $.jStore.Instances[name]) { // If a name is specified and exists, use it - $.jStore.delegate.trigger('jStore-ready', $.jStore.Instances[name]); - return $.jStore.CurrentEngine = $.jStore.Instances[name]; - } - - throw 'JSTORE_JRI_NO_MATCH'; - } - - // Test all possible engines for straightforward useability - $.jStore.FindEngine = function(){ - $.each($.jStore.EngineOrder, function(k){ - if ($.jStore.Availability[this]()){ // Find the first, easiest option and use it. - $.jStore.use(this, $.jStore.defaults.project, 'default'); - return false; - } - }) - } - - // Provide a simple interface for storing/getting values - $.jStore.store = function(key, value){ - if (!$.jStore.CurrentEngine) return false; - - if ( !value ) // Executing a get command - return $.jStore.CurrentEngine.get(key); - // Executing a set command - return $.jStore.CurrentEngine.set(key, value); - } - // Provide a simple interface for storing/getting values - $.jStore.remove = function(key){ - if (!$.jStore.CurrentEngine) return false; - - return $.jStore.CurrentEngine.rem(key); - } - - // Provide a chainable interface for storing values/getting a value at the end of a chain - $.fn.store = function(key, value){ - if (!$.jStore.CurrentEngine) return this; - - var result = $.jStore.store(key, value); - - return !value ? result : this; - } - - // Provide a chainable interface for removing values - $.fn.removeStore = function(key){ - $.jStore.remove(key); - - return this; - } - - // Provide a way for users to call for auto-loading - $.jStore.load = function(){ - if ($.jStore.defaults.engine) - return $.jStore.use($.jStore.defaults.engine, $.jStore.defaults.project, 'default'); - - // Attempt to find a valid engine, and catch any exceptions if we can't - try { - $.jStore.FindEngine(); - } catch (e) {} - } - -})(jQuery); -/** - * jStore Engine Core - * Copyright (c) 2009 Eric Garside (http://eric.garside.name) - */ -(function($){ - - this.StorageEngine = Class.extend({ - init: function(project, name){ - // Configure the project name - this.project = project; - // The JRI name given by the manager - this.jri = name; - // Cache the data so we can work synchronously - this.data = {}; - // The maximum limit of the storage engine - this.limit = -1; - // Third party script includes - this.includes = []; - // Create an event delegate for users to subscribe to event triggers - this.delegate = new jStoreDelegate(this) - .bind('engine-ready', function(){ - this.isReady = true; - }) - .bind('engine-included', function(){ - this.hasIncluded = true; - }); - // If enabled, the manager will check availability, then run include(), then check again - this.autoload = false; // This should be changed by the engines, if they have required includes - // When set, we're ready to transact data - this.isReady = false; - // When the includer is finished, it will set this to true - this.hasIncluded = false; - }, - // Performs all necessary script includes - include: function(){ - var self = this, - total = this.includes.length, - count = 0; - - $.each(this.includes, function(){ - $.ajax({type: 'get', url: this, dataType: 'script', cache: true, - success: function(){ - count++; - if (count == total) self.delegate.trigger('engine-included'); - } - }) - }); - }, - // This should be overloaded with an actual functionality presence check - isAvailable: function(){ - return false; - }, - /** Event Subscription Shortcuts **/ - ready: function(callback){ - if (this.isReady) callback.apply(this); - else this.delegate.bind('engine-ready', callback); - return this; - }, - included: function(callback){ - if (this.hasIncluded) callback.apply(this); - else this.delegate.bind('engine-included', callback); - return this; - }, - /** Cache Data Access **/ - get: function(key){ - return this.data[key] || null; - }, - set: function(key, value){ - this.data[key] = value; - return value; - }, - rem: function(key){ - var beforeDelete = this.data[key]; - this.data[key] = null; - return beforeDelete; - } - }); - -})(jQuery); -/* - * jStore DOM Storage Engine - * Copyright (c) 2009 Eric Garside (http://eric.garside.name) - */ -(function($){ - - // Set up a static test function for this instance - var sessionAvailability = $.jStore.Availability.session = function(){ - return !!window.sessionStorage; - }, - localAvailability = $.jStore.Availability.local = function(){ - return !!(window.localStorage || window.globalStorage); - }; - - this.jStoreDom = StorageEngine.extend({ - init: function(project, name){ - // Call the parental init object - this._super(project, name); - - // The type of storage engine - this.type = 'DOM'; - - // Set the Database limit - this.limit = 5 * 1024 * 1024; - }, - connect: function(){ - // Fire our delegate to indicate we're ready for data transactions - this.delegate.trigger('engine-ready'); - }, - get: function(key){ - var out = this.db.getItem(key); - // Gecko's getItem returns {value: 'the value'}, WebKit returns 'the value' - return out && out.value ? out.value : out - }, - set: function(key, value){ - this.db.setItem(key,value); - return value; - }, - rem: function(key){ - var out = this.get(key); - this.db.removeItem(key); - return out - } - }) - - this.jStoreLocal = jStoreDom.extend({ - connect: function(){ - // Gecko uses a non-standard globalStorage[ www.example.com ] DOM access object for persistant storage. - this.db = !window.globalStorage ? window.localStorage : window.globalStorage[location.hostname]; - this._super(); - }, - isAvailable: localAvailability - }) - - this.jStoreSession = jStoreDom.extend({ - connect: function(){ - this.db = sessionStorage; - this._super(); - }, - isAvailable: sessionAvailability - }) - - $.jStore.Engines.local = jStoreLocal; - $.jStore.Engines.session = jStoreSession; - - // Store the ordering preference - $.jStore.EngineOrder[ 1 ] = 'local'; - -})(jQuery); -/* - * jStore Flash Storage Engine - * Copyright (c) 2009 Eric Garside (http://eric.garside.name) - * jStore.swf Copyright (c) 2008 Daniel Bulli (http://www.nuff-respec.com) - */ -(function($){ - - // Set up a static test function for this instance - var avilability = $.jStore.Availability.flash = function(){ - return !!($.jStore.hasFlash('8.0.0')); - } - - this.jStoreFlash = StorageEngine.extend({ - init: function(project, name){ - // Call the parental init object - this._super(project, name); - - // The type of storage engine - this.type = 'Flash'; - - // Bind our flashReady function to the jStore Delegate - var self = this; - $.jStore.flashReady(function(){ self.flashReady() }); - }, - connect: function(){ - var name = 'jstore-flash-embed-' + this.project; - - // To make Flash Storage work on IE, we have to load up an iFrame - // which contains an HTML page that embeds the object using an - // object tag wrapping an embed tag. Of course, this is unnecessary for - // all browsers except for IE, which, to my knowledge, is the only browser - // in existance where you need to complicate your code to fix bugs. Goddamnit. :( - $(document.body) - .append('<iframe style="height:1px;width:1px;position:absolute;left:0;top:0;margin-left:-100px;" ' + - 'id="jStoreFlashFrame" src="' +$.jStore.defaults.flash + '"></iframe>'); - }, - flashReady: function(e){ - var iFrame = $('#jStoreFlashFrame')[0]; - - // IE - if (iFrame.Document && $.isFunction(iFrame.Document['jStoreFlash'].f_get_cookie)) this.db = iFrame.Document['jStoreFlash']; - // Safari && Firefox - else if (iFrame.contentWindow && iFrame.contentWindow.document){ - var doc = iFrame.contentWindow.document; - // Safari - if ($.isFunction($('object', $(doc))[0].f_get_cookie)) this.db = $('object', $(doc))[0]; - // Firefox - else if ($.isFunction($('embed', $(doc))[0].f_get_cookie)) this.db = $('embed', $(doc))[0]; - } - - // We're ready to process data - if (this.db) this.delegate.trigger('engine-ready'); - }, - isAvailable: avilability, - get: function(key){ - var out = this.db.f_get_cookie(key); - return out == 'null' ? null : out; - }, - set: function(key, value){ - this.db.f_set_cookie(key, value); - return value; - }, - rem: function(key){ - var beforeDelete = this.get(key); - this.db.f_delete_cookie(key); - return beforeDelete; - } - }) - - $.jStore.Engines.flash = jStoreFlash; - - // Store the ordering preference - $.jStore.EngineOrder[ 2 ] = 'flash'; - - /** - * Flash Detection functions copied from the jQuery Flash Plugin - * Copyright (c) 2006 Luke Lutman (http://jquery.lukelutman.com/plugins/flash) - * Dual licensed under the MIT and GPL licenses. - * http://www.opensource.org/licenses/mit-license.php - * http://www.opensource.org/licenses/gpl-license.php - */ - $.jStore.hasFlash = function(version){ - var pv = $.jStore.flashVersion().match(/\d+/g), - rv = version.match(/\d+/g); - - for(var i = 0; i < 3; i++) { - pv[i] = parseInt(pv[i] || 0); - rv[i] = parseInt(rv[i] || 0); - // player is less than required - if(pv[i] < rv[i]) return false; - // player is greater than required - if(pv[i] > rv[i]) return true; - } - // major version, minor version and revision match exactly - return true; - } - - $.jStore.flashVersion = function(){ - // ie - try { - try { - // avoid fp6 minor version lookup issues - // see: http://blog.deconcept.com/2006/01/11/getvariable-setvariable-crash-internet-... - var axo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash.6'); - try { axo.AllowScriptAccess = 'always'; } - catch(e) { return '6,0,0'; } - } catch(e) {} - return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\D+/g, ',').match(/^,?(.+),?$/)[1]; - // other browsers - } catch(e) { - try { - if(navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin){ - return (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]).description.replace(/\D+/g, ",").match(/^,?(.+),?$/)[1]; - } - } catch(e) {} - } - return '0,0,0'; - } - -})(jQuery); - -// Callback fired when ExternalInterface is established -function flash_ready(){ - $.jStore.delegate.trigger('flash-ready'); -} -/* - * jStore Google Gears Storage Engine - * Copyright (c) 2009 Eric Garside (http://eric.garside.name) - */ -(function($){ - - // Set up a static test function for this instance - var avilability = $.jStore.Availability.gears = function(){ - return !!(window.google && window.google.gears) - } - - this.jStoreGears = StorageEngine.extend({ - init: function(project, name){ - // Call the parental init object - this._super(project, name); - - // The type of storage engine - this.type = 'Google Gears'; - - // Add required third-party scripts - this.includes.push('http://code.google.com/apis/gears/gears_init.js'); - - // Allow Autoloading on fail - this.autoload = true; - }, - connect: function(){ - // Create our database connection - var db = this.db = google.gears.factory.create('beta.database'); - db.open( 'jstore-' + this.project ); - db.execute( 'CREATE TABLE IF NOT EXISTS jstore (k TEXT UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)' ); - - // Cache the data from the table - this.updateCache(); - }, - updateCache: function(){ - // Read the database into our cache object - var result = this.db.execute( 'SELECT k,v FROM jstore' ); - while (result.isValidRow()){ - this.data[result.field(0)] = result.field(1); - result.next(); - } result.close(); - - // Fire our delegate to indicate we're ready for data transactions - this.delegate.trigger('engine-ready'); - }, - isAvailable: avilability, - set: function(key, value){ - // Update the database - var db = this.db; - db.execute( 'BEGIN' ); - db.execute( 'INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)', [key,value] ); - db.execute( 'COMMIT' ); - return this._super(key, value); - }, - rem: function(key){ - // Update the database - var db = this.db; - db.execute( 'BEGIN' ); - db.execute( 'DELETE FROM jstore WHERE k = ?', [key] ); - db.execute( 'COMMIT' ); - return this._super(key); - } - }) - - $.jStore.Engines.gears = jStoreGears; - - // Store the ordering preference - $.jStore.EngineOrder[ 3 ] = 'gears'; - -})(jQuery); -/* - * jStore HTML5 Specification Storage Engine - * Copyright (c) 2009 Eric Garside (http://eric.garside.name) - */ -(function($){ - - // Set up a static test function for this instance - var avilability = $.jStore.Availability.html5 = function(){ - return !!window.openDatabase - } - - this.jStoreHtml5 = StorageEngine.extend({ - init: function(project, name){ - // Call the parental init object - this._super(project, name); - - // The type of storage engine - this.type = 'HTML5'; - - // Set the Database limit - this.limit = 1024 * 200; - }, - connect: function(){ - // Create our database connection - var db = this.db = openDatabase('jstore-' + this.project, '1.0', this.project, this.limit); - if (!db) throw 'JSTORE_ENGINE_HTML5_NODB'; - db.transaction(function(db){ - db.executeSql( 'CREATE TABLE IF NOT EXISTS jstore (k TEXT UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)' ); - }); - - // Cache the data from the table - this.updateCache(); - }, - updateCache: function(){ - var self = this; - // Read the database into our cache object - this.db.transaction(function(db){ - db.executeSql( 'SELECT k,v FROM jstore', [], function(db, result){ - var rows = result.rows, i = 0, row; - for (; i < rows.length; ++i){ - row = rows.item(i); - self.data[row.k] = row.v; - } - - // Fire our delegate to indicate we're ready for data transactions - self.delegate.trigger('engine-ready'); - }); - }); - }, - isAvailable: avilability, - set: function(key, value){ - // Update the database - this.db.transaction(function(db){ - db.executeSql( 'INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)', [key,value]); - }); - return this._super(key, value); - }, - rem: function(key){ - // Update the database - this.db.transaction(function(db){ - db.executeSql( 'DELETE FROM jstore WHERE k = ?', [key] ) - }) - return this._super(key); - } - }) - - $.jStore.Engines.html5 = jStoreHtml5; - - // Store the ordering preference - $.jStore.EngineOrder[ 0 ] = 'html5'; - -})(jQuery); -/* - * jStore IE Storage Engine - * Copyright (c) 2009 Eric Garside (http://eric.garside.name) - */ -(function($){ - - // Set up a static test function for this instance - var avilability = $.jStore.Availability.ie = function(){ - return !!window.ActiveXObject; - } - - this.jStoreIE = StorageEngine.extend({ - init: function(project, name){ - // Call the parental init object - this._super(project, name); - - // The type of storage engine - this.type = 'IE'; - - // Allow Autoloading on fail - this.limit = 64 * 1024; - }, - connect: function(){ - // Create a hidden div to store attributes in - this.db = $('<div style="display:none;behavior:url(\'#default#userData\')" id="jstore-' + this.project + '"></div>') - .appendTo(document.body).get(0); - // Fire our delegate to indicate we're ready for data transactions - this.delegate.trigger('engine-ready'); - }, - isAvailable: avilability, - get: function(key){ - this.db.load(this.project); - return this.db.getAttribute(key); - }, - set: function(key, value){ - this.db.setAttribute(key, value); - this.db.save(this.project); - return value; - }, - rem: function(key){ - var beforeDelete = this.get(key); - this.db.removeAttribute(key); - this.db.save(this.project); - return beforeDelete; - } - }) - - $.jStore.Engines.ie = jStoreIE; - - // Store the ordering preference - $.jStore.EngineOrder[ 4 ] = 'ie'; - -})(jQuery); diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/jquery.jstore.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/static/scripts/jquery.jstore.js Fri Apr 09 18:09:54 2010 -0400 @@ -0,0 +1,1810 @@ +/*! + * jStore 2.0 - Persistent Client Side Storage + * + * Copyright (c) 2010 Eric Garside (http://eric.garside.name/) + * Dual licensed under: + * MIT: http://www.opensource.org/licenses/mit-license.php + * GPLv3: http://www.opensource.org/licenses/gpl-3.0.html + * + * --------------------------- + * + * jStore Flash Storage Component + * + * Copyright (c) 2006 Jeff Lerman (jeff@blip.tv) + * Licensed under the Creative Commons Attribution 3.0 United States License: + * http://creativecommons.org/licenses/by/3.0/us + */ + +"use strict"; + +/*global Class, window, jQuery, ActiveXObject, google */ + +/*jslint white: true, browser: true, onevar: true, undef: true, eqeqeq: true, bitwise: true, regexp: false, strict: true, newcap: true, immed: true, maxerr: 50, indent: 4 */ + +(function ($, window) { + + //------------------------------ + // + // Constants + // + //------------------------------ + + //------------------------------ + // Exceptions + //------------------------------ + + /** + * An exception thrown by the StorageEngine class whenever its data accessor methods + * are called before the engine is ready to transact data. + */ + var EX_UNSTABLE = 'JSTORE_ENGINE_UNSTABLE', + + /** + * An exception thrown by jStore whenever an undefined storage engine is referenced for + * some task by an invalid JRI (jStore Resource Identifier). + */ + EX_UNKNOWN = 'JSTORE_UNKNOWN_ENGINE_REQUESTED', + + /** + * An exception thrown by jStore whenever a given flavor of storage is double defined. + */ + EX_COLLISION = 'JSTORE_ENGINE_NAMESPACE_COLLISION', + + /** + * An exception thrown by jStore whenever a jri is double applied to a resource. + */ + EX_DUPLICATE = 'JSTORE_RESOURCE_NAMESPACE_COLLISION', + + /** + * An exception thrown by jStore whenever a given flavor of storage has no defined engine. + */ + EX_UNAVAILABLE = 'JSTORE_ENGINE_UNAVAILABLE', + + /** + * An exception thrown by jStore whenever an invalid flavor type is used. + */ + EX_INVALID = 'JSTORE_INVALID_FLAVOR', + + //------------------------------ + // Regular Expressions + //------------------------------ + + /** + * Regular expression to test property values for being JSON. + */ + RX_JSON = (function () + { + try + { + return new RegExp('^("(\\\\.|[^"\\\\\\n\\r])*?"|[,:{}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t])+?$'); + } + catch (e) + { + return (/^(true|false|null|\[.*\]|\{.*\}|".*"|\d+|\d+\.\d+)$/); + } + }()), + + //------------------------------ + // Storage Flavors + //------------------------------ + + /** + * The storage flavor identifier for HTML5 local storage. + */ + FLAVOR_LOCAL = 'jstore-html5-local', + + /** + * The storage flavor identifier for HTML5 database storage. + */ + FLAVOR_SQL = 'jstore-html5-sql', + + /** + * The storage flavor identifier for Adobe Flash SharedObject storage. + */ + FLAVOR_FLASH = 'jstore-flash', + + /** + * The storage flavor identifier for Google Gears storage. + */ + FLAVOR_GEARS = 'jstore-google-gears', + + /** + * The storage flavor identifier for Internet Explorer storage, available to IE7 and IE6. + */ + FLAVOR_MSIE = 'jstore-msie', + + //------------------------------ + // + // Property Declaration + // + //------------------------------ + + /** + * The base StorageEngine class which each "storage flavor" will extend to meet the + * requirements for its specific implementation. + */ + StorageEngine, + + /** + * The jStore object. Internal to this closure, jStore is referenced by "_". It is + * exposed to jQuery below, and made publicly accessible through jQuery.jStore + */ + _ = {}, + + /** + * The engines available to jStore for use. These are the class definitions for flavored + * storage engines. + * + * Signature: + * { + * <storageFlavor>: <flavoredStorageEngineDefinition>, + * + * ... + * } + */ + definitions = {}, + + /** + * Active engines instantiated by jStore, indexed by their JRI. + * + * Signature: + * { + * <engineJRI>: <engineInstance>, + * + * ... + * } + */ + engines = {}, + + /** + * If we are going to be using the flash storage engine, we want to postpone the jStore ready event until the jStore + * isFlashReady flag is also true. This property is set whenever flash is determined to be the storage engine. + */ + waitForFlash = false, + + /** + * Storage for listeners, indexed by content and event type. + * + * Signature: + * { + * <context>: + * { + * <eventType>: [<listener>, ...], + * + * ... + * }, + * + * ... + * } + */ + events = {}, + + /** + * The configuration for this implementation. + * + * Signature: + * { + * project: <defaultProjectName>, + * + * flash: <pathToFlashBootloader>, + * + * json: <pathToJSONFile>, + * + * errorCallback: <listenerToNotifyOnError> + * } + */ + configurations = + { + project: undefined, + + flash: 'jStore.Flash.html', + + json: 'browser.json.js' + }, + + /** + * The active storage engine, being used to satisfy the get/set/remove functions on the jStore and jQuery + * objects. + */ + active; + + //------------------------------ + // + // Internal Methods + // + //------------------------------ + + /** + * Determine if the given flavor is valid. + * + * @param flavor The flavor to test. + * + * @return True if the flavor is valid, false otherwise. + */ + function validFlavor(flavor) + { + switch (flavor) + { + + case FLAVOR_LOCAL: + case FLAVOR_SQL: + case FLAVOR_FLASH: + case FLAVOR_GEARS: + case FLAVOR_MSIE: + return true; + + default: + return false; + + } + } + + /** + * Performs enhanced type comparison on an object. This is more reliable method + * of type checking a variable than a simple typeof comparison. The reason is that, + * typeof will reduce to the lowest common type. + * + * "typeof []" returns Object, and not Array. + * "typeof {}" returns Object as well. + * + * typecheck( [], 'Array' ) : returns true; + * typecheck( [], 'Object' ) : returns false; + * + * @param type The variable type to check. + * + * @param compare A string representing the literal type to check. + * + * @return True if the variable "type" matches the compare literal. + */ + function typecheck(type, compare) + { + return !type ? false : type.constructor.toString().match(new RegExp(compare + '\\(\\)', 'i')) !== null; + } + + /** + * If the provided listener is a valid function, it will be triggered with the provided context + * and parameters. + * + * @param listener The listener being triggered. + * + * @param context The context to provide to the listener. + * + * @param parameters The parameters to pass to the listener as arguments. + * + * @return The response of the notified listener. + */ + function notify(listener, context, parameters) + { + if (typecheck(listener, 'Function')) + { + return listener.apply(context || _, typecheck(parameters, 'Array') ? parameters : [parameters]); + } + } + + /** + * Load the given script. + * + * @param path The path to the file to include. + * + * @param listener The listener to notify when the file finishes loading. + */ + function loadScript(path, listener) + { + $.ajax( + { + url: path, + complete: listener || $.noop(), + type: 'GET', + dataType: 'script', + cache: false + }); + } + + /** + * Checks the type of the value, and returns a value safe to persist in any client-side mechanism. + * + * @param value The value which should be prepared for storage. + * + * @return A value safe for storage. + */ + function prepareForStorage(value) + { + if (value === undefined) + { + return ''; + } + + if (typecheck(value, 'Object') || + typecheck(value, 'Array') || + typecheck(value, 'Function')) + { + return JSON.stringify(value); + } + + return value; + } + + /** + * Checks the type of the value, and returns a value safe for access in any client-side mechanism. + * + * @param value The value which should be prepared for use. + * + * @return A value safe for use. + */ + function prepareForRevival(value) + { + return RX_JSON.test(value) ? JSON.parse(value) : value; + } + + /** + * Normalize a key before using it, to ensure it's valid. + * + * @param key The key to normalize. + * + * @return A normalized key, safe for storage. + */ + function normalizeKey(key) + { + return key.replace(/^\s+|\s+$/g, ""); + } + + /** + * Define a flavored storage engine. + * + * @throws EX_COLLISION, EX_INVALID + * + * @param flavor The flavor of engine being defined. + * + * @param definition An object containing the new properties and methods for the engine extension. + * + * @param availability A function to invoke which must return a boolean value indicating the + * availability of the storage flavor on this browser. + */ + function define(flavor, definition, availability) + { + if (!validFlavor(flavor)) + { + throw EX_INVALID; + } + + if (availability[flavor] !== undefined) + { + throw EX_COLLISION; + } + + /** + * The logic here has been reworked so unavailable flavors are discarded, so we don't needlessly + * bloat the runtime size of jStore. + */ + if (notify(availability) === true) + { + _.available[flavor] = true; + + definition.flavor = flavor; + + definitions[flavor] = StorageEngine.extend(definition); + } + else + { + _.available[flavor] = false; + + // Filter the invalid flavor out of the priority list. + _.enginePriority = $.map(_.enginePriority, function (engine) + { + if (engine === flavor) + { + return null; + } + else + { + return engine; + } + }); + } + } + + /** + * Make the jStore library ready. + */ + function makeReady() + { + if (_.isReady) + { + return; + } + + if ((waitForFlash && _.isFlashReady) || !waitForFlash) + { + _.isReady = true; + _.trigger('jstore-ready', [engines[active]]); + } + } + + /** + * Create a best-fit engine. + */ + function createBestFitEngine() + { + _.create(_.enginePriority[0], undefined, 'best-fit'); + } + + /** + * Get the flash version currently supported in this browser. + * + * @return The flash version. + */ + function flashVersion() + { + // MSIE + try + { + // avoid fp6 minor version lookup issues + // see: http://blog.deconcept.com/2006/01/11/getvariable-setvariable-crash-internet-... + var axo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash.6'); + + try + { + axo.AllowScriptAccess = 'always'; + } + catch (axo_e) + { + return '6,0,0'; + } + + return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\D+/g, ',').match(/^,?(.+),?$/)[1]; + } + + // Real browsers + catch (e) + { + try + { + if (navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin) + { + return (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]).description.replace(/\D+/g, ",").match(/^,?(.+),?$/)[1]; + } + } + catch (flash_e) + {} + } + + return '0,0,0'; + } + + /** + * Flash Detection functions copied from the jQuery Flash Plugin + * + * Copyright (c) 2006 Luke Lutman (http://jquery.lukelutman.com/plugins/flash) + * + * Dual licensed under the MIT and GPL licenses. + * http://www.opensource.org/licenses/mit-license.php + * http://www.opensource.org/licenses/gpl-license.php + * + * @param version The version to compare to. + * + * @return True if the version is greater than or equal to the required version, false otherwise. + */ + function hasFlashVersion(version) + { + var playerVersion = flashVersion().match(/\d+/g), + requiredVersion = version.match(/\d+/g), + index = 0, + player, + required; + + for (; index < 3; index++) + { + player = parseInt(playerVersion[index], 10); + required = parseInt(requiredVersion[index], 10); + + // Player version is less than what is required. + if (player < required) + { + return false; + } + + // Player version is greater than what is required. + else if (player > required) + { + return true; + } + } + + // Player and required version match exactly. + return true; + } + + //------------------------------ + // + // Plugin Definition + // + //------------------------------ + + //------------------------------ + // Error Declaration + //------------------------------ + + //------------------------------ + // Plugin Creation + //------------------------------ + + /** + * The jStore object. Manages a collection of StorageEngines for particular "storage flavors", or the types + * of storage solutions available to each browser. + * + * 2.0 Version Notes: + * + * - The user is now responsible for third-party script includes, with the exception of flash. + * + * - jStore has been given sole responsibility for testing engine availability. + * + * - For the sake of naming conventions, all property names now start with a lowercase, and are camel-cased. + * + * The following properties have been changed since the 1.2.x release: + * + * - EngineOrder: For the sake of naming conventions, renamed to enginePriority. + * + * The following properties and methods have been removed since the 1.2.x release: + * + * - Availability: jStore's engines would add their availability tests to this object, so jStore could test + * them. With the changes to how availability testing works, this property has been removed. + * A new property, "available" on jStore contains a set of available engines. + * + * - Engines: Formerly contained the definitions of storage engines. This property has been removed, and + * storage of these definitions has been moved internal to the closure. + * + * - Instances: Formerly contained instantiated storage engines. This property has been removed, and storage + * of instantiated engines has been moved internal to the closure. + * + * - CurrentEngine: Formerly contained the active storage engine being used for transacting data through the jStore + * and/or jQuery objects. This property has been removed, and storage of the current engine has + * been moved internal to the closure. A new method, "activeEngine" has been added to jQuery to + * get and set the active engine to use. + * + * - defaults: Formerly used to set the implementation options for jStore. This property has been removed and + * replaced with a new configuration metho on the jStore object. + * + * - delegate: The delegate class has been removed in favor of a much simpler bind/trigger accessor system, which + * is accessible contextually through storage engines, or generically through jStore. + * + * + fail: This registration class bound events on the delegate for jstore-fail events. Instead, use: + * jStore.bind('jstore-failure', listener); + * + * + flashReady: This registration class bound events on the delegate for flash-ready events. The jstore-ready method + * now accounts for waiting for flash readyness, if and only if the flash engine is being used. Simply + * call to jStore.ready(). + * + * + load: Replaced with the init() method, which performs the same basic functions as the old load() method. Also, + * the init function is now domready safe, meaning it wraps itself in a domready listener, so the end user + * doesn't have to. + * + * + FindEngine: Removed entirely. The functionality provided by this method now implicitly occurs with the new define() + * system implemented for engine flavors. + * + * + setCurrentEngine: Replaced by activeEngine(). Set the current active engine by passing in the JRI. + * + * + safeStore: Replaced by a method internal to this closure, "prepareForStorage". + * + * + safeResurrect: Replaced by a method internal to this closure, "prepareForRevival". + * + * + use: Replaced by "create". + */ + $.extend(_, { + + //------------------------------ + // Properties + //------------------------------ + + /** + * The priority order in which engines should be tested for use. The lower their index in the array, the higher + * their priority for use. + * + * Be weary when reconfiguring the priority order of engines! jStore will use the first available engine it finds + * based on its priority when autoloading. + * + * This array is filtered out as engines are defined, with invalid engines being removed. + * + * Signature: + * [FLAVOR_<storageFlavor>, ...] + */ + enginePriority: [FLAVOR_LOCAL, FLAVOR_SQL, FLAVOR_FLASH, FLAVOR_MSIE], + + /** + * A collection of the availability states of engines, indexed by their flavor. + * + * Signature: + * { + * <storageFlavor>: true|false, + * + * ... + * } + */ + available: {}, + + /** + * Flag to determine if the jStore library is ready. jStore becomes ready once the dom is ready and all necessary + * startup procedures required by jStore to function properly are completed. + */ + isReady: false, + + /** + * With the flash storage engine, we have to jump through a couple of hoops before the flash engine is ready to work. + * This flag tracks whether or not the flash storage is available. + */ + isFlashReady: false, + + /** + * The available engine flavors. + */ + flavors: + { + local: FLAVOR_LOCAL, + + sql: FLAVOR_SQL, + + flash: FLAVOR_FLASH, + + gears: FLAVOR_GEARS, + + msie: FLAVOR_MSIE + }, + + //------------------------------ + // Constructor + //------------------------------ + + /** + * Constructor. + * + * @throws EX_INVALID + * + * @param project The name of the jStore project. Used to generate a JRI for the engine we create. + * + * @param configuration Optionally, an object containing configuration options for this implementation. + * + * @param flavor Optionally, the flavor of storage to use. If not provided, jStore will pick the + * best flavor, based on the current browser. + * + * @return jStore + */ + init: function (project, configuration, flavor) + { + // Extend our plugin configurations + $.extend(configurations, {project: project}, configuration); + + $(function () + { + // If JSON parsing isn't defined in this browser, include it. + if (window.JSON === undefined) + { + loadScript(configurations.json); + } + + // If we have an explicit flavor to use, use it. + if (flavor !== undefined) + { + _.create(flavor, project, 'default'); + } + + // Otherwise, attempt to create a best-fit engine. + else + { + createBestFitEngine(); + } + }); + + return _; + }, + + //------------------------------ + // Methods + //------------------------------ + + /** + * Create an instance of a flavored engine. + * + * @throws EX_INVALID, EX_UNAVAILABLE, EX_DUPLICATE + * + * @param flavor The flavor to create the engine with. + * + * @param project The project identifier for this instance. + * + * @param identifier Some arbitrary identifier for this project instance of the engine. + * + * @return The created instance. + */ + create: function (flavor, project, identifier) + { + project = project || configurations.project || location.hostname.replace(/\./g, '-') || 'unknown'; + + if (!validFlavor(flavor)) + { + throw EX_INVALID; + } + + if (definitions[flavor] === undefined) + { + throw EX_UNAVAILABLE; + } + + var jri = (identifier !== undefined ? identifier + '.' : '') + project + '.' + flavor, + engine; + + if (engines[jri] !== undefined) + { + throw EX_DUPLICATE; + } + + // Create our engine instance. + engine = engines[jri] = new definitions[flavor](project, jri); + + // Set up a listener for our jstore-engine-ready event. + engine.ready(function () + { + _.trigger('jstore-engine-ready', [engine]); + }); + + if (flavor === FLAVOR_FLASH && !_.isFlashReady) + { + if (active === undefined) + { + waitForFlash = true; + } + + // Define a window-accessible function for flash to call via ExternalInterface + window.jstore_ready = function () + { + _.isFlashReady = true; + _.trigger('flash-ready'); + + if (active === undefined) + { + makeReady(); + } + + // Remove the callback from the window scope, as it is no longer necessary + window.flash_ready = undefined; + }; + + window.jstore_error = function (message) + { + _.trigger('jstore-error', ['JSTORE_FLASH_EXCEPTION', null, message]); + }; + + $('<iframe style="height:1px;width:1px;position:absolute;left:0;top:0;margin-left:-100px;" id="jStoreFlashFrame" src="' + + configurations.flash + '"></iframe>').appendTo('body'); + } + else if (active === undefined) + { + active = jri; + makeReady(); + } + + return engine; + }, + + /** + * Fetch an engine by it's JRI. + * + * @param jri The JRI of the engine to retrieve. + * + * @return The requested engine. + */ + engine: function (jri) + { + return engines[jri]; + }, + + /** + * Returns the active storage engine being used. If a value is passed, sets that engine as the active engine. + * + * @throws EX_UNKNOWN + * + * @param jri Optionally, the JRI of the engine to make active, if it should be changed. + * + * @return The active storage engine. + */ + activeEngine: function (jri) + { + if (jri !== undefined) + { + if (engines[jri] === undefined) + { + throw EX_UNKNOWN; + } + else + { + active = jri; + } + } + + return engines[active]; + }, + + /** + * Bind an event listener. + * + * @param event The event to bind a listener on. + * + * @param listener The listener to notify when the event occurs. + * + * @param context The context of the binding. A string representing the engine flavor + * binding the event, or undefined to indicate it's a jStore event. + * + * @return jStore + */ + bind: function (event, listener, context) + { + context = context || 'jstore'; + + if (events[context] === undefined) + { + events[context] = {}; + } + + if (events[context][event] === undefined) + { + events[context][event] = [listener]; + } + else + { + events[context][event].push(listener); + } + + return _; + }, + + /** + * Trigger an event, notifying any bound listeners. + * + * @param event The event to trigger. + * + * @param parameters Any additional parameters to pass to the listeners being notified. + * + * @param context The context of the binding. A string representing the engine flavor + * binding the event, or undefined to indicate it's a jStore event. + * + * @return jStore + */ + trigger: function (event, parameters, context) + { + context = context || 'jstore'; + + if (events[context] !== undefined) + { + if (events[context][event] !== undefined) + { + $.each(events[context][event], function () + { + notify(this, _, parameters); + }); + } + } + + return _; + }, + + /** + * Bind a listener to be notified when jStore causes a non-fatal exception. + * + * @param listener The listener to notify when a failure occurs. + */ + error: function (listener) + { + _.bind('jstore-error', listener); + }, + + /** + * Bind a listener to be notified when jStore is ready. + * + * @param listener The listener to notify when jStore is ready. + * + * @return jStore + */ + ready: function (listener) + { + if (_.isReady) + { + notify(listener); + } + else + { + _.bind('jstore-ready', listener); + } + + return _; + }, + + /** + * Bind a listener to be notified when jStore and the default engine are ready. + * + * @param listener The listener to notify when jStore and it's default engine are ready. + * + * @return jStore + */ + engineReady: function (listener) + { + if (_.isReady) + { + notify(listener); + } + else + { + _.bind('jstore-engine-ready', listener); + } + + return _; + }, + + /** + * A combined getter/setter for the active engine. + * + * @param key The key of the property to get, or set. + * + * @param value If a valid value is provided, sets the engine. + * + * @return The requested property value. + */ + store: function (key, value) + { + return value === undefined ? _.get(key) : _.set(key, value); + }, + + /** + * Remove a property from the active engine. + * + * @param key The key of the property to remove. + * + * @return The value of the property before removal. + */ + remove: function (key) + { + return _.activeEngine().remove(key); + }, + + /** + * Get a property from the active engine. + * + * @param key The key of the property to get. + * + * @return The value of the property. + */ + get: function (key) + { + return _.activeEngine().get(key); + }, + + /** + * Set a property on the active engine. + * + * @param key The key of the property to set. + * + * @param value The value to set the property to. + * + * @return The new value of the property. + */ + set: function (key, value) + { + return _.activeEngine().set(key, value); + } + + }); + + //------------------------------ + // Core Extension + //------------------------------ + + //------------------------------ + // + // Class Definition + // + //------------------------------ + + /** + * The StorageEngine class is the unified API through which jStore accesses and manipulates + * the various storage flavors available. + * + * 2.0 Version Notes: + * + * - All third-party loading is now the responsibility of the developer. + * + * - The delegate class has been removed entirely. Engines have been given "bind" and "trigger" methods + * to interact directly with the delegate like-replacement that has been added to jStore. + * + * - Engine availability has been moved out of the engines themselves, and elevated to a jStore + * responsibility. + * + * The following methods have changed since the 1.2.x release: + * + * - get: When "get"ting a non-stored property, the get function will now return "undefined" + * instead of "null". "null" can now be used as a valid property value. + * + * - rem: Renamed to "remove". I always felt dirty about "rem" being vaguely explicit. + * + * The following properties have been removed since the 1.2.x release: + * + * - autoload: Part of the third-party loading logic. + * + * - hasIncluded: Part of the third-party loading logic. + * + * - includes: Part of the third-party loading logic. + * + * - isAvailable: Part of the availability logic elevated to jStore. + * + * @throws EX_UNSTABLE + */ + StorageEngine = Class.extend({ + + //------------------------------ + // Properties + //------------------------------ + + /** + * The project which owns this storage engine. + */ + project: undefined, + + /** + * The JRI (jStore Resource Identifier) acts as a uuid for this specific instance + * of the storage engine. + */ + jri: undefined, + + /** + * The flavor of this engine. + */ + flavor: undefined, + + /** + * The actual database object which data is transacted through. + */ + database: undefined, + + /** + * A StorageEngine should always respond to fetch requests synchronously. However, some + * of the storage flavors require callback-based asynchronous access. To get around this, + * we simlpy require all engines to function off a primary data cache, to allow for + * synchronous access across all implementations. + * + * Signature: + * { + * <propertyKey>: <propertyValue>, + * + * ... + * } + */ + data: undefined, + + /** + * A number of storage engines enforce a size limit as to what they will persist for a given site. + * This limit is not monitored or computed by jStore currently, and this property will merely give + * a static indication of the total size alloted to the engine, as defined by the storage flavor. + */ + limit: undefined, + + /** + * Each storage flavor has a different process to go through before it's "ready" to transact data. This + * property stores the state of the engine's readyness, and uses it to notify listeners whenever jStore + * is ready to function. + */ + isReady: undefined, + + //------------------------------ + // Constructor + //------------------------------ + + /** + * Constructor. + * + * @param project The project which instantiated this engine. + * + * @param jri The uuid assigned to this instance by jStore. + */ + init: function (project, jri) + { + this.project = project; + this.jri = jri; + this.data = {}; + this.isReady = false; + this.updateCache(); + }, + + //------------------------------ + // Methods + //------------------------------ + + /** + * Update the cache. + */ + updateCache: function () + { + this.isReady = true; + this.trigger('engine-ready', [this]); + }, + + /** + * Bind a listener to an event dispatched by this engine. + * + * @param event The event to bind on. + * + * @param listener The listener to notify when the event occurs. + */ + bind: function (event, listener) + { + _.bind(event, listener, this.jri); + }, + + /** + * Trigger an event, notifying all bound listeners. + * + * @param event The event to trigger. + * + * @param parameters An optional Array of parameters to pass to the listeners. + */ + trigger: function (event, parameters) + { + _.trigger(event, parameters, this.jri); + }, + + /** + * Bind a listener to the StorageEngine's ready event. + * + * @param listener The listener to notify whenever this engine is ready to transact data. + */ + ready: function (listener) + { + if (this.isReady) + { + notify(listener, this); + } + else + { + this.bind('engine-ready', listener); + } + }, + + /** + * Get a property from the StorageEngine. + * + * @param key The property key of the data to retrieve. + * + * @return The property value, or "undefined" if the property isn't stored. + */ + get: function (key) + { + this.__interruptAccess(); + + return this.data[key]; + }, + + /** + * Sets a property in the StorageEngine. + * + * @param key The key of the property. + * + * @param value The value of the property. + * + * @return The new value of the property. + */ + set: function (key, value) + { + this.__interruptAccess(); + + key = normalizeKey(key); + + try + { + this.__set(key, value); + } + catch (e) + { + _.trigger('jstore-error', ['JSTORE_STORAGE_FAILURE', this.jri, e]); + } + + this.data[key] = value; + + return value; + }, + + /** + * Removes a property from the StorageEngine. + * + * @param key The property key of the data to remove. + * + * @return The value of the property, before it was removed. + */ + remove: function (key) + { + this.__interruptAccess(); + + key = normalizeKey(key); + + try + { + this.__remove(key); + } + catch (e) + { + _.trigger('jstore-error', ['JSTORE_REMOVE_FAILURE', this.jri, e]); + } + + var buffer = this.data[key]; + + this.data[key] = undefined; + + return buffer; + }, + + //------------------------------ + // Internal Methods + //------------------------------ + + /** + * Ensures the engine is in a stable state for transacting data. + * + * @throws EX_UNSTABLE + */ + __interruptAccess: function () + { + if (!this.isReady) + { + throw EX_UNSTABLE; + } + }, + + /** + * Sets a property in the StorageEngine. This method should be overloaded to provide actual + * storage flavor integration. + * + * @param key The key of the property. + * + * @param value The value of the property. + * + * @return The new value of the property. + */ + __set: function (key, value) + { + return; + }, + + /** + * Removes a property from the StorageEngine. This method should be overloaded to provide actual + * storage flavor integration. + * + * @param key The property key of the data to remove. + * + * @return The value of the property, before it was removed. + */ + __remove: function (key) + { + return; + } + + }); + + //------------------------------ + // + // jQuery Hooks + // + //------------------------------ + + $.extend($.fn, { + + //------------------------------ + // Methods + //------------------------------ + + /** + * A combined getter/setter for the active engine. + * + * @param key The key of the property to get, or set. + * + * @param value If a valid value is provided, sets the engine. + * + * @return jQuery + */ + store: function (key, value) + { + if (value === undefined) + { + _.get(key); + } + else + { + _.set(key, value); + } + + return this; + }, + + /** + * Remove a property from the active engine. + * + * @param key The key of the property to remove. + * + * @return jQuery + */ + removeStore: function (key) + { + _.activeEngine().remove(key); + + return this; + }, + + /** + * Get a property from the active engine. + * + * @param key The key of the property to get. + * + * @return The value of the property. + */ + getStore: function (key) + { + return _.activeEngine().get(key); + }, + + /** + * Set a property on the active engine. + * + * @param key The key of the property to set. + * + * @param value The value to set the property to. + * + * @return jQuery + */ + setStore: function (key, value) + { + _.activeEngine().set(key, value); + + return this; + } + + }); + + //------------------------------ + // + // Event Bindings + // + //------------------------------ + + //------------------------------ + // + // Startup Code + // + //------------------------------ + + //------------------------------ + // Expose jStore through jQuery + //------------------------------ + + window.jStore = $.jStore = _; + + //------------------------------ + // + // Engine Definitions + // + //------------------------------ + + //------------------------------ + // Local + //------------------------------ + + define(FLAVOR_LOCAL, + { + //------------------------------ + // Properties + //------------------------------ + + limit: parseInt(5e5, 16), + + //------------------------------ + // Constructor + //------------------------------ + + init: function (project, name) + { + this.database = window.globalStorage === undefined ? window.localStorage : window.globalStorage[location.hostname]; + + this._super(project, name); + }, + + //------------------------------ + // Methods + //------------------------------ + + updateCache: function () + { + var key, value; + + for (key in this.database) + { + var has_key = false; + if (this.database.hasOwnProperty) { + if (this.database.hasOwnProperty(key)) { + has_key = true; + } + } else { // IE 8 + if (this.database.getItem(key) !== null) { + has_key = true; + } + } + + if (has_key) { + value = this.database.getItem(key); + + // Gecko's getItem returns {value: 'the value'}, WebKit returns 'the value' + this.data[key] = prepareForRevival(value && value.value ? value.value : value); + } + } + + this._super(); + }, + + //------------------------------ + // Internal methods + //------------------------------ + + __set: function (key, value) + { + this.database.setItem(key, prepareForStorage(value)); + }, + + __remove: function (key) + { + this.database.removeItem(key); + } + }, + + function () + { + return window.localStorage !== undefined || window.globalStorage !== undefined; + }); + + //------------------------------ + // SQL + //------------------------------ + + define(FLAVOR_SQL, + { + //------------------------------ + // Properties + //------------------------------ + + limit: parseInt(32e3, 16), + + //------------------------------ + // Constructor + //------------------------------ + + init: function (project, name) + { + this.database = window.openDatabase('jstore-' + project, '1.0', project, this.limit); + + if (!this.database) + { + throw 'JSTORE_SQL_NO_DB'; + } + + this.database.transaction(function (database) + { + database.executeSql('CREATE TABLE IF NOT EXISTS jstore (k TEXT UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)'); + }); + + this._super(project, name); + }, + + //------------------------------ + // Methods + //------------------------------ + + updateCache: function () + { + var self = this, + _super = this._super; + + this.database.transaction(function (database) + { + database.executeSql('SELECT k,v FROM jstore', [], function (database, result) + { + var rows = result.rows, + index = 0, + row; + + for (; index < rows.length; ++index) + { + row = rows.item(index); + self.data[row.k] = prepareForRevival(row.v); + } + + _super.apply(self); + }); + }); + }, + + //------------------------------ + // Internal methods + //------------------------------ + + __set: function (key, value) + { + this.database.transaction(function (database) + { + database.executeSql('INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)', [key, prepareForStorage(value)]); + }); + }, + + __remove: function (key) + { + this.database.transaction(function (database) + { + database.executeSql('DELETE FROM jstore WHERE k = ?', [key]); + }); + } + }, + + function () + { + return window.openDatabase !== undefined; + }); + + //------------------------------ + // Flash + //------------------------------ + + define(FLAVOR_FLASH, + { + //------------------------------ + // Properties + //------------------------------ + + limit: -1, + + //------------------------------ + // Constructor + //------------------------------ + + init: function (project, name) + { + var self = this; + + _.bind('flash-ready', function () + { + self.__flashReadyListener(); + }); + + this._super(project, name); + }, + + //------------------------------ + // Methods + //------------------------------ + + updateCache: function (enable) + { + /** + * The default call to updateCache passes no variable, so we can short circuit the + * ready state until we explictly call this after flash ready. + */ + if (enable === true) + { + var key, + dataset = this.database.jstore_get_all(); + + for (key in dataset) + { + if (dataset.hasOwnProperty(key)) + { + this.data[key] = prepareForRevival(this.database.jstore_get(key)); + } + } + + this._super(); + } + }, + + //------------------------------ + // Internal methods + //------------------------------ + + __set: function (key, value) + { + if (!this.database.jstore_set(key, prepareForStorage(value))) + { + _.trigger('jstore-error', ['JSTORE_STORAGE_FAILURE', this.jri, 'Flash Exception']); + } + }, + + __remove: function (key) + { + this.database.jstore_remove(key); + }, + + /** + * Triggered whenever flash is ready. + */ + __flashReadyListener: function () + { + var iFrame = $('#jStoreFlashFrame')[0], + frameDocument; + + // MSIE + if (iFrame.Document !== undefined && typecheck(iFrame.Document.jStoreFlash.jstore_get, 'Function')) + { + this.database = iFrame.Document.jStoreFlash; + } + + // Real Browsers + else if (iFrame.contentWindow && iFrame.contentWindow.document) + { + frameDocument = $(iFrame.contentWindow.document); + + // Webkit + if (typecheck($('object', frameDocument)[0].jstore_get, 'Function')) + { + this.database = $('object', frameDocument)[0]; + } + + // Gecko + else if (typecheck($('embed', frameDocument)[0].jstore_get, 'Function')) + { + this.database = $('embed', frameDocument)[0]; + } + } + + if (this.database === undefined) + { + throw 'JSTORE_FLASH_REFERENCE_ISSUE'; + } + else + { + this.updateCache(true); + } + } + }, + + function () + { + return hasFlashVersion('9.0.0'); + }); + + //------------------------------ + // Gears + //------------------------------ + + define(FLAVOR_GEARS, + { + //------------------------------ + // Properties + //------------------------------ + + limit: -1, + + //------------------------------ + // Constructor + //------------------------------ + + init: function (project, name) + { + this.database = google.gears.factory.create('beta.database'); + this.database.open('jstore-' + project); + this.database.execute('CREATE TABLE IF NOT EXISTS jstore (k TEXT UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)'); + + this._super(project, name); + }, + + //------------------------------ + // Methods + //------------------------------ + + updateCache: function () + { + var result = this.database.execute('SELECT k,v FROM jstore'); + + while (result.isValidRow()) + { + this.data[result.field(0)] = prepareForRevival(result.field(1)); + result.next(); + } + + result.close(); + + this._super(); + }, + + //------------------------------ + // Internal methods + //------------------------------ + + __set: function (key, value) + { + this.database.execute('BEGIN'); + this.database.execute('INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)', [key, prepareForStorage(value)]); + this.database.execute('COMMIT'); + }, + + __remove: function (key) + { + this.database.execute('BEGIN'); + this.database.execute('DELETE FROM jstore WHERE k = ?', [key]); + this.database.execute('COMMIT'); + } + }, + + function () + { + return window.google !== undefined && window.google.gears !== undefined; + }); + + //------------------------------ + // MSIE + //------------------------------ + + define(FLAVOR_MSIE, + { + //------------------------------ + // Properties + //------------------------------ + + limit: parseInt(1e4, 16), + + //------------------------------ + // Constructor + //------------------------------ + + init: function (project, name) + { + this.database = $('<div style="display:none;behavior:url(\'#default#userData\')" id="jstore-' + project + '"></div>') + .appendTo(document.body).get(0); + + this._super(project, name); + }, + + //------------------------------ + // Methods + //------------------------------ + + updateCache: function () + { + this.database.load(this.project); + + var node = document.getElementById('jstore-' + this.project), + xmlDoc = node.XMLDocument, + root, + index = 0; + + if (xmlDoc && xmlDoc.documentElement && xmlDoc.documentElement.attributes) + { + root = xmlDoc.documentElement; + + for (; index < root.attributes.length; ++index) + { + this.data[root.attributes.item(index).nodeName] = prepareForRevival(root.attributes.item(index).nodeValue); + } + } + + this._super(); + }, + + //------------------------------ + // Internal methods + //------------------------------ + + __set: function (key, value) + { + this.database.setAttribute(key, prepareForStorage(value)); + this.database.save(this.project); + }, + + __remove: function (key) + { + this.database.removeAttribute(key); + this.database.save(this.project); + } + }, + + function () + { + return window.ActiveXObject !== undefined; + }); + +}(jQuery, window)); diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/json2.js --- a/static/scripts/json2.js Fri Apr 09 13:02:15 2010 -0400 +++ b/static/scripts/json2.js Fri Apr 09 18:09:54 2010 -0400 @@ -1,6 +1,6 @@ /* http://www.JSON.org/json2.js - 2009-06-29 + 2010-03-20 Public Domain. @@ -8,6 +8,14 @@ See http://www.JSON.org/js.html + + This code should be minified before deployment. + See http://javascript.crockford.com/jsmin.html + + USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO + NOT CONTROL. + + This file creates a global JSON object containing two methods: stringify and parse. @@ -33,7 +41,7 @@ value represented by the name/value pair that should be serialized, or undefined if nothing should be serialized. The toJSON method will be passed the key associated with the value, and this will be - bound to the object holding the key. + bound to the value For example, this would serialize Dates as ISO strings. @@ -136,15 +144,9 @@ This is a reference implementation. You are free to copy, modify, or redistribute. - - This code should be minified before deployment. - See http://javascript.crockford.com/jsmin.html - - USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO - NOT CONTROL. */ -/*jslint evil: true */ +/*jslint evil: true, strict: false */ /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, @@ -153,10 +155,13 @@ test, toJSON, toString, valueOf */ + // Create a JSON object only if one does not already exist. We create the // methods in a closure to avoid creating global variables. -var JSON = JSON || {}; +if (!this.JSON) { + this.JSON = {}; +} (function () { @@ -428,6 +433,7 @@ // Unicode characters with escape sequences. JavaScript handles many characters // incorrectly, either silently deleting them, or treating them as line endings. + text = String(text); cx.lastIndex = 0; if (cx.test(text)) { text = text.replace(cx, function (a) { diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/packed/class.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/static/scripts/packed/class.js Fri Apr 09 18:09:54 2010 -0400 @@ -0,0 +1,7 @@ +/* + * Class definition + * + * Copyright (c) 2008 John Resig (http://ejohn.org/blog/simple-javascript-inheritance/) + * Inspired by base2 and Prototype + */ +"use strict";(function(){var a=false,b=/xyz/.test(function(){xyz})?/\b_super\b/:/.*/;this.Class=function(){};Class.extend=function(g){var f=this.prototype;a=true;var e=new this();a=false;for(var d in g){e[d]=(typeof g[d]==="function"&&typeof f[d]==="function"&&b.test(g[d])?(function(h,i){return function(){var k=this._super;this._super=f[h];var j=i.apply(this,arguments);this._super=k;return j}}(d,g[d])):g[d])}function c(){if(!a&&this.init){this.init.apply(this,arguments)}}c.prototype=e;c.constructor=c;c.extend=arguments.callee;return c}}()); \ No newline at end of file diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/packed/galaxy.base.js --- a/static/scripts/packed/galaxy.base.js Fri Apr 09 13:02:15 2010 -0400 +++ b/static/scripts/packed/galaxy.base.js Fri Apr 09 18:09:54 2010 -0400 @@ -1,1 +1,1 @@ -$(document).ready(function(){replace_big_select_inputs()});$.fn.makeAbsolute=function(a){return this.each(function(){var b=$(this);var c=b.position();b.css({position:"absolute",marginLeft:0,marginTop:0,top:c.top,left:c.left,right:$(window).width()-(c.left+b.width())});if(a){b.remove().appendTo("body")}})};function ensure_popup_helper(){if($("#popup-helper").length===0){$("<div id='popup-helper'/>").css({background:"white",opacity:0,zIndex:15000,position:"absolute",top:0,left:0,width:"100%",height:"100%"}).appendTo("body").hide()}}function attach_popupmenu(b,d){var a=function(){d.unbind().hide();$("#popup-helper").unbind("click.popupmenu").hide()};var c=function(g){$("#popup-helper").bind("click.popupmenu",a).show();d.click(a).css({left:0,top:-1000}).show();var f=g.pageX-d.width()/2;f=Math.min(f,$(document).scrollLeft()+$(window).width()-$(d).width()-20);f=Math.max(f,$(document).scrollLeft()+20);d.css({top:g.pageY-5,left:f});return false};$(b).click(c)}function make_popupmen! u(c,b){ensure_popup_helper();var a=$("<ul id='"+c.attr("id")+"-menu'></ul>");$.each(b,function(f,e){if(e){$("<li/>").html(f).click(e).appendTo(a)}else{$("<li class='head'/>").html(f).appendTo(a)}});var d=$("<div class='popmenu-wrapper'>");d.append(a).append("<div class='overlay-border'>").css("position","absolute").appendTo("body").hide();attach_popupmenu(c,d)}function make_popup_menus(){jQuery("div[popupmenu]").each(function(){var c={};$(this).find("a").each(function(){var b=$(this).attr("confirm"),d=$(this).attr("href"),e=$(this).attr("target");c[$(this).text()]=function(){if(!b||confirm(b)){var g=window;if(e=="_parent"){g=window.parent}else{if(e=="_top"){g=window.top}}g.location=d}}});var a=$("#"+$(this).attr("popupmenu"));make_popupmenu(a,c);$(this).remove();a.addClass("popup").show()})}function array_length(b){if(b.length){return b.length}var c=0;for(var a in b){c++}return c}function replace_big_select_inputs(){$("select[name=dbkey]").each(function(){var a=$(this);if(a! .find("option").length<20){return}var b=a.attr("value");var c=$("<inpu t type='text' class='text-and-autocomplete-select'></input>");c.attr("size",40);c.attr("name",a.attr("name"));c.click(function(){var g=$(this).attr("value");$(this).attr("value","Loading...");$(this).showAllInCache();$(this).attr("value",g);$(this).select()});var f=[];var e={};a.children("option").each(function(){var h=$(this).text();var g=$(this).attr("value");if(g=="?"){return}f.push(h);e[h]=g;e[g]=g;if(g==b){c.attr("value",h)}});if(c.attr("value")==""){c.attr("value","Click to Search or Select")}var d={selectFirst:false,autoFill:false,mustMatch:false,matchContains:true,max:1000,minChars:0,hideForLessThanMinChars:false};c.autocomplete(f,d);a.replaceWith(c);c.parents("form").submit(function(){var h=c.attr("value");var g=e[h];if(g!==null&&g!==undefined){c.attr("value",g)}else{if(b!=""){c.attr("value",b)}else{c.attr("value","?")}}})})}function async_save_text(d,f,e,a,c,h,i,g,b){if(c===undefined){c=30}if(i===undefined){i=4}$("#"+d).live("click",function(){if($("#renaming-activ! e").length>0){return}var l=$("#"+f),k=l.text(),j;if(h){j=$("<textarea></textarea>").attr({rows:i,cols:c}).text(k)}else{j=$("<input type='text'></input>").attr({value:k,size:c})}j.attr("id","renaming-active");j.blur(function(){$(this).remove();l.show();if(b){b(j)}});j.keyup(function(n){if(n.keyCode===27){$(this).trigger("blur")}else{if(n.keyCode===13){var m={};m[a]=$(this).val();$(this).trigger("blur");$.ajax({url:e,data:m,error:function(){alert("Text editing for elt "+f+" failed")},success:function(o){l.text(o);if(b){b(j)}}})}}});if(g){g(j)}l.hide();j.insertAfter(l);j.focus();j.select();return})}$(document).ready(function(){$("a[confirm]").click(function(){return confirm($(this).attr("confirm"))});if($.fn.tipsy){$(".tooltip").tipsy({gravity:"s"})}make_popup_menus()}); \ No newline at end of file +$(document).ready(function(){replace_big_select_inputs()});$.fn.makeAbsolute=function(a){return this.each(function(){var b=$(this);var c=b.position();b.css({position:"absolute",marginLeft:0,marginTop:0,top:c.top,left:c.left,right:$(window).width()-(c.left+b.width())});if(a){b.remove().appendTo("body")}})};function ensure_popup_helper(){if($("#popup-helper").length===0){$("<div id='popup-helper'/>").css({background:"white",opacity:0,zIndex:15000,position:"absolute",top:0,left:0,width:"100%",height:"100%"}).appendTo("body").hide()}}function attach_popupmenu(b,d){var a=function(){d.unbind().hide();$("#popup-helper").unbind("click.popupmenu").hide()};var c=function(g){$("#popup-helper").bind("click.popupmenu",a).show();d.click(a).css({left:0,top:-1000}).show();var f=g.pageX-d.width()/2;f=Math.min(f,$(document).scrollLeft()+$(window).width()-$(d).width()-20);f=Math.max(f,$(document).scrollLeft()+20);d.css({top:g.pageY-5,left:f});return false};$(b).click(c)}function make_popupmen! u(c,b){ensure_popup_helper();var a=$("<ul id='"+c.attr("id")+"-menu'></ul>");$.each(b,function(f,e){if(e){$("<li/>").html(f).click(e).appendTo(a)}else{$("<li class='head'/>").html(f).appendTo(a)}});var d=$("<div class='popmenu-wrapper'>");d.append(a).append("<div class='overlay-border'>").css("position","absolute").appendTo("body").hide();attach_popupmenu(c,d)}function make_popup_menus(){jQuery("div[popupmenu]").each(function(){var c={};$(this).find("a").each(function(){var b=$(this).attr("confirm"),d=$(this).attr("href"),e=$(this).attr("target");c[$(this).text()]=function(){if(!b||confirm(b)){var g=window;if(e=="_parent"){g=window.parent}else{if(e=="_top"){g=window.top}}g.location=d}}});var a=$("#"+$(this).attr("popupmenu"));make_popupmenu(a,c);$(this).remove();a.addClass("popup").show()})}function array_length(b){if(b.length){return b.length}var c=0;for(var a in b){c++}return c}function replace_big_select_inputs(){$("select[name=dbkey]").each(function(){var a=$(this);if(a! .find("option").length<20){return}var b=a.attr("value");var c=$("<inpu t type='text' class='text-and-autocomplete-select'></input>");c.attr("size",40);c.attr("name",a.attr("name"));c.click(function(){var g=$(this).attr("value");$(this).attr("value","Loading...");$(this).showAllInCache();$(this).attr("value",g);$(this).select()});var f=[];var e={};a.children("option").each(function(){var h=$(this).text();var g=$(this).attr("value");if(g=="?"){return}f.push(h);e[h]=g;e[g]=g;if(g==b){c.attr("value",h)}});if(c.attr("value")==""){c.attr("value","Click to Search or Select")}var d={selectFirst:false,autoFill:false,mustMatch:false,matchContains:true,max:1000,minChars:0,hideForLessThanMinChars:false};c.autocomplete(f,d);a.replaceWith(c);c.parents("form").submit(function(){var h=c.attr("value");var g=e[h];if(g!==null&&g!==undefined){c.attr("value",g)}else{if(b!=""){c.attr("value",b)}else{c.attr("value","?")}}})})}function async_save_text(d,f,e,a,c,h,i,g,b){if(c===undefined){c=30}if(i===undefined){i=4}$("#"+d).live("click",function(){if($("#renaming-activ! e").length>0){return}var l=$("#"+f),k=l.text(),j;if(h){j=$("<textarea></textarea>").attr({rows:i,cols:c}).text(k)}else{j=$("<input type='text'></input>").attr({value:k,size:c})}j.attr("id","renaming-active");j.blur(function(){$(this).remove();l.show();if(b){b(j)}});j.keyup(function(n){if(n.keyCode===27){$(this).trigger("blur")}else{if(n.keyCode===13){var m={};m[a]=$(this).val();$(this).trigger("blur");$.ajax({url:e,data:m,error:function(){alert("Text editing for elt "+f+" failed")},success:function(o){l.text(o);if(b){b(j)}}})}}});if(g){g(j)}l.hide();j.insertAfter(l);j.focus();j.select();return})}function init_history_items(c,a){var b=function(){try{var d=$.jStore.store("history_expand_state");if(d){for(var f in d){$("#"+f+" div.historyItemBody").show()}}}catch(e){$.jStore.remove("history_expand_state")}if($.browser.mozilla){$("div.historyItemBody").each(function(){if(!$(this).is(":visible")){$(this).find("pre.peek").css("overflow","hidden")}})}c.each(function(){var i=this.i! d;var g=$(this).children("div.historyItemBody");var h=g.find("pre.peek ");$(this).children(".historyItemTitleBar").find(".historyItemTitle").wrap("<a href='#'></a>").click(function(){if(g.is(":visible")){if($.browser.mozilla){h.css("overflow","hidden")}g.slideUp("fast");if(!a){var j=$.jStore.store("history_expand_state");if(j){delete j[i];$.jStore.store("history_expand_state",j)}}}else{g.slideDown("fast",function(){if($.browser.mozilla){h.css("overflow","auto")}});if(!a){var j=$.jStore.store("history_expand_state");if(j===undefined){j={}}j[i]=true;$.jStore.store("history_expand_state",j)}}return false})});$("#top-links > a.toggle").click(function(){var g=$.jStore.store("history_expand_state");if(g===undefined){g={}}$("div.historyItemBody:visible").each(function(){if($.browser.mozilla){$(this).find("pre.peek").css("overflow","hidden")}$(this).slideUp("fast");if(g){delete g[$(this).parent().attr("id")]}});$.jStore.store("history_expand_state",g)}).show()};if(a){b()}else{$.jStore.init("galaxy");$.jStore.engineReady(function(){b()})}}$(document).re! ady(function(){$("a[confirm]").click(function(){return confirm($(this).attr("confirm"))});if($.fn.tipsy){$(".tooltip").tipsy({gravity:"s"})}make_popup_menus()}); \ No newline at end of file diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/packed/jquery.jstore-all.js --- a/static/scripts/packed/jquery.jstore-all.js Fri Apr 09 13:02:15 2010 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -(function(){var a=false,b=/xyz/.test(function(){xyz})?/\b_super\b/:/.*/;this.Class=function(){};Class.extend=function(g){var f=this.prototype;a=true;var e=new this();a=false;for(var d in g){e[d]=typeof g[d]=="function"&&typeof f[d]=="function"&&b.test(g[d])?(function(h,i){return function(){var k=this._super;this._super=f[h];var j=i.apply(this,arguments);this._super=k;return j}})(d,g[d]):g[d]}function c(){if(!a&&this.init){this.init.apply(this,arguments)}}c.prototype=e;c.constructor=c;c.extend=arguments.callee;return c}})();(function(a){this.jStoreDelegate=Class.extend({init:function(b){this.parent=b;this.callbacks={}},bind:function(b,c){if(!a.isFunction(c)){return this}if(!this.callbacks[b]){this.callbacks[b]=[]}this.callbacks[b].push(c);return this},trigger:function(){var d=this.parent,c=[].slice.call(arguments),e=c.shift(),b=this.callbacks[e];if(!b){return false}a.each(b,function(){this.apply(d,c)});return this}})})(jQuery);(function(a){a.jStore={};a.extend(a.jStore,{Engi! neOrder:[],Availability:{},Engines:{},Instances:{},CurrentEngine:null,defaults:{project:null,engine:null,autoload:true,flash:"jStore.Flash.html"},isReady:false,isFlashReady:false,delegate:new jStoreDelegate(a.jStore).bind("jStore-ready",function(b){a.jStore.isReady=true;if(a.jStore.defaults.autoload){b.connect()}}).bind("flash-ready",function(){a.jStore.isFlashReady=true})});a.jStore.ready=function(b){if(a.jStore.isReady){b.apply(a.jStore,[a.jStore.CurrentEngine])}else{a.jStore.delegate.bind("jStore-ready",b)}};a.jStore.fail=function(b){a.jStore.delegate.bind("jStore-failure",b)};a.jStore.flashReady=function(b){if(a.jStore.isFlashReady){b.apply(a.jStore,[a.jStore.CurrentEngine])}else{a.jStore.delegate.bind("flash-ready",b)}};a.jStore.use=function(d,g,c){g=g||a.jStore.defaults.project||location.hostname.replace(/\./g,"-")||"unknown";var f=a.jStore.Engines[d.toLowerCase()]||null,b=(c?c+".":"")+g+"."+d;if(!f){throw"JSTORE_ENGINE_UNDEFINED"}f=new f(g,b);if(a.jStore.Instances[b]! ){throw"JSTORE_JRI_CONFLICT"}if(f.isAvailable()){a.jStore.Instances[b] =f;if(!a.jStore.CurrentEngine){a.jStore.CurrentEngine=f}a.jStore.delegate.trigger("jStore-ready",f)}else{if(!f.autoload){throw"JSTORE_ENGINE_UNAVILABLE"}else{f.included(function(){if(this.isAvailable()){a.jStore.Instances[b]=this;if(!a.jStore.CurrentEngine){a.jStore.CurrentEngine=this}a.jStore.delegate.trigger("jStore-ready",this)}else{a.jStore.delegate.trigger("jStore-failure",this)}}).include()}}};a.jStore.setCurrentEngine=function(b){if(!a.jStore.Instances.length){return a.jStore.FindEngine()}if(!b&&a.jStore.Instances.length>=1){a.jStore.delegate.trigger("jStore-ready",a.jStore.Instances[0]);return a.jStore.CurrentEngine=a.jStore.Instances[0]}if(b&&a.jStore.Instances[b]){a.jStore.delegate.trigger("jStore-ready",a.jStore.Instances[b]);return a.jStore.CurrentEngine=a.jStore.Instances[b]}throw"JSTORE_JRI_NO_MATCH"};a.jStore.FindEngine=function(){a.each(a.jStore.EngineOrder,function(b){if(a.jStore.Availability[this]()){a.jStore.use(this,a.jStore.defaults.project,"default");re! turn false}})};a.jStore.store=function(b,c){if(!a.jStore.CurrentEngine){return false}if(!c){return a.jStore.CurrentEngine.get(b)}return a.jStore.CurrentEngine.set(b,c)};a.jStore.remove=function(b){if(!a.jStore.CurrentEngine){return false}return a.jStore.CurrentEngine.rem(b)};a.fn.store=function(c,d){if(!a.jStore.CurrentEngine){return this}var b=a.jStore.store(c,d);return !d?b:this};a.fn.removeStore=function(b){a.jStore.remove(b);return this};a.jStore.load=function(){if(a.jStore.defaults.engine){return a.jStore.use(a.jStore.defaults.engine,a.jStore.defaults.project,"default")}try{a.jStore.FindEngine()}catch(b){}}})(jQuery);(function(a){this.StorageEngine=Class.extend({init:function(c,b){this.project=c;this.jri=b;this.data={};this.limit=-1;this.includes=[];this.delegate=new jStoreDelegate(this).bind("engine-ready",function(){this.isReady=true}).bind("engine-included",function(){this.hasIncluded=true});this.autoload=false;this.isReady=false;this.hasIncluded=false},include:func! tion(){var b=this,d=this.includes.length,c=0;a.each(this.includes,func tion(){a.ajax({type:"get",url:this,dataType:"script",cache:true,success:function(){c++;if(c==d){b.delegate.trigger("engine-included")}}})})},isAvailable:function(){return false},ready:function(b){if(this.isReady){b.apply(this)}else{this.delegate.bind("engine-ready",b)}return this},included:function(b){if(this.hasIncluded){b.apply(this)}else{this.delegate.bind("engine-included",b)}return this},get:function(b){return this.data[b]||null},set:function(b,c){this.data[b]=c;return c},rem:function(b){var c=this.data[b];this.data[b]=null;return c}})})(jQuery);(function(c){var b=c.jStore.Availability.session=function(){return !!window.sessionStorage},a=c.jStore.Availability.local=function(){return !!(window.localStorage||window.globalStorage)};this.jStoreDom=StorageEngine.extend({init:function(e,d){this._super(e,d);this.type="DOM";this.limit=5*1024*1024},connect:function(){this.delegate.trigger("engine-ready")},get:function(e){var d=this.db.getItem(e);return d&&d.value?d.value:d},set:! function(d,e){this.db.setItem(d,e);return e},rem:function(e){var d=this.get(e);this.db.removeItem(e);return d}});this.jStoreLocal=jStoreDom.extend({connect:function(){this.db=!window.globalStorage?window.localStorage:window.globalStorage[location.hostname];this._super()},isAvailable:a});this.jStoreSession=jStoreDom.extend({connect:function(){this.db=sessionStorage;this._super()},isAvailable:b});c.jStore.Engines.local=jStoreLocal;c.jStore.Engines.session=jStoreSession;c.jStore.EngineOrder[1]="local"})(jQuery);(function(b){var a=b.jStore.Availability.flash=function(){return !!(b.jStore.hasFlash("8.0.0"))};this.jStoreFlash=StorageEngine.extend({init:function(e,d){this._super(e,d);this.type="Flash";var c=this;b.jStore.flashReady(function(){c.flashReady()})},connect:function(){var c="jstore-flash-embed-"+this.project;b(document.body).append('<iframe style="height:1px;width:1px;position:absolute;left:0;top:0;margin-left:-100px;" id="jStoreFlashFrame" src="'+b.jStore.defaults.flas! h+'"></iframe>')},flashReady:function(f){var c=b("#jStoreFlashFrame")[ 0];if(c.Document&&b.isFunction(c.Document.jStoreFlash.f_get_cookie)){this.db=c.Document.jStoreFlash}else{if(c.contentWindow&&c.contentWindow.document){var d=c.contentWindow.document;if(b.isFunction(b("object",b(d))[0].f_get_cookie)){this.db=b("object",b(d))[0]}else{if(b.isFunction(b("embed",b(d))[0].f_get_cookie)){this.db=b("embed",b(d))[0]}}}}if(this.db){this.delegate.trigger("engine-ready")}},isAvailable:a,get:function(d){var c=this.db.f_get_cookie(d);return c=="null"?null:c},set:function(c,d){this.db.f_set_cookie(c,d);return d},rem:function(c){var d=this.get(c);this.db.f_delete_cookie(c);return d}});b.jStore.Engines.flash=jStoreFlash;b.jStore.EngineOrder[2]="flash";b.jStore.hasFlash=function(c){var e=b.jStore.flashVersion().match(/\d+/g),f=c.match(/\d+/g);for(var d=0;d<3;d++){e[d]=parseInt(e[d]||0);f[d]=parseInt(f[d]||0);if(e[d]<f[d]){return false}if(e[d]>f[d]){return true}}return true};b.jStore.flashVersion=function(){try{try{var c=new ActiveXObject("ShockwaveFlash.Shock! waveFlash.6");try{c.AllowScriptAccess="always"}catch(d){return"6,0,0"}}catch(d){}return new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version").replace(/\D+/g,",").match(/^,?(.+),?$/)[1]}catch(d){try{if(navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin){return(navigator.plugins["Shockwave Flash 2.0"]||navigator.plugins["Shockwave Flash"]).description.replace(/\D+/g,",").match(/^,?(.+),?$/)[1]}}catch(d){}}return"0,0,0"}})(jQuery);function flash_ready(){$.jStore.delegate.trigger("flash-ready")}(function(b){var a=b.jStore.Availability.gears=function(){return !!(window.google&&window.google.gears)};this.jStoreGears=StorageEngine.extend({init:function(d,c){this._super(d,c);this.type="Google Gears";this.includes.push("http://code.google.com/apis/gears/gears_init.js");this.autoload=true},connect:function(){var c=this.db=google.gears.factory.create("beta.database");c.open("jstore-"+this.project);c.execute("CREATE TABLE IF NOT EXISTS jstore (k TEX! T UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)");this.updateCache()}, updateCache:function(){var c=this.db.execute("SELECT k,v FROM jstore");while(c.isValidRow()){this.data[c.field(0)]=c.field(1);c.next()}c.close();this.delegate.trigger("engine-ready")},isAvailable:a,set:function(d,e){var c=this.db;c.execute("BEGIN");c.execute("INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)",[d,e]);c.execute("COMMIT");return this._super(d,e)},rem:function(d){var c=this.db;c.execute("BEGIN");c.execute("DELETE FROM jstore WHERE k = ?",[d]);c.execute("COMMIT");return this._super(d)}});b.jStore.Engines.gears=jStoreGears;b.jStore.EngineOrder[3]="gears"})(jQuery);(function(b){var a=b.jStore.Availability.html5=function(){return !!window.openDatabase};this.jStoreHtml5=StorageEngine.extend({init:function(d,c){this._super(d,c);this.type="HTML5";this.limit=1024*200},connect:function(){var c=this.db=openDatabase("jstore-"+this.project,"1.0",this.project,this.limit);if(!c){throw"JSTORE_ENGINE_HTML5_NODB"}c.transaction(function(d){d.executeSql("CREATE TABLE IF NOT EXISTS! jstore (k TEXT UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)")});this.updateCache()},updateCache:function(){var c=this;this.db.transaction(function(d){d.executeSql("SELECT k,v FROM jstore",[],function(f,e){var h=e.rows,g=0,j;for(;g<h.length;++g){j=h.item(g);c.data[j.k]=j.v}c.delegate.trigger("engine-ready")})})},isAvailable:a,set:function(c,d){this.db.transaction(function(e){e.executeSql("INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)",[c,d])});return this._super(c,d)},rem:function(c){this.db.transaction(function(d){d.executeSql("DELETE FROM jstore WHERE k = ?",[c])});return this._super(c)}});b.jStore.Engines.html5=jStoreHtml5;b.jStore.EngineOrder[0]="html5"})(jQuery);(function(b){var a=b.jStore.Availability.ie=function(){return !!window.ActiveXObject};this.jStoreIE=StorageEngine.extend({init:function(d,c){this._super(d,c);this.type="IE";this.limit=64*1024},connect:function(){this.db=b('<div style="display:none;behavior:url(\'#default#userData\')" id="jstore-'+this.proj! ect+'"></div>').appendTo(document.body).get(0);this.delegate.trigger(" engine-ready")},isAvailable:a,get:function(c){this.db.load(this.project);return this.db.getAttribute(c)},set:function(c,d){this.db.setAttribute(c,d);this.db.save(this.project);return d},rem:function(c){var d=this.get(c);this.db.removeAttribute(c);this.db.save(this.project);return d}});b.jStore.Engines.ie=jStoreIE;b.jStore.EngineOrder[4]="ie"})(jQuery); \ No newline at end of file diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/packed/jquery.jstore.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/static/scripts/packed/jquery.jstore.js Fri Apr 09 18:09:54 2010 -0400 @@ -0,0 +1,17 @@ +/* + * jStore 2.0 - Persistent Client Side Storage + * + * Copyright (c) 2010 Eric Garside (http://eric.garside.name/) + * Dual licensed under: + * MIT: http://www.opensource.org/licenses/mit-license.php + * GPLv3: http://www.opensource.org/licenses/gpl-3.0.html + * + * --------------------------- + * + * jStore Flash Storage Component + * + * Copyright (c) 2006 Jeff Lerman (jeff@blip.tv) + * Licensed under the Creative Commons Attribution 3.0 United States License: + * http://creativecommons.org/licenses/by/3.0/us + */ +"use strict";(function(i,n){var h="JSTORE_ENGINE_UNSTABLE",t="JSTORE_UNKNOWN_ENGINE_REQUESTED",r="JSTORE_ENGINE_NAMESPACE_COLLISION",j="JSTORE_RESOURCE_NAMESPACE_COLLISION",m="JSTORE_ENGINE_UNAVAILABLE",o="JSTORE_INVALID_FLAVOR",f=(function(){try{return new RegExp('^("(\\\\.|[^"\\\\\\n\\r])*?"|[,:{}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t])+?$')}catch(I){return(/^(true|false|null|\[.*\]|\{.*\}|".*"|\d+|\d+\.\d+)$/)}}()),b="jstore-html5-local",y="jstore-html5-sql",F="jstore-flash",G="jstore-google-gears",A="jstore-msie",u,E={},D={},C={},c=false,d={},q={project:undefined,flash:"jStore.Flash.html",json:"browser.json.js"},l;function z(I){switch(I){case b:case y:case F:case G:case A:return true;default:return false}}function g(I,J){return !I?false:I.constructor.toString().match(new RegExp(J+"\\(\\)","i"))!==null}function s(K,I,J){if(g(K,"Function")){return K.apply(I||E,g(J,"Array")?J:[J])}}function p(J,I){i.ajax({url:J,complete:I||i.noop(),type:"GET",dataType:"script",cache:false})}fun! ction x(I){if(I===undefined){return""}if(g(I,"Object")||g(I,"Array")||g(I,"Function")){return JSON.stringify(I)}return I}function k(I){return f.test(I)?JSON.parse(I):I}function w(I){return I.replace(/^\s+|\s+$/g,"")}function e(I,J,K){if(!z(I)){throw o}if(K[I]!==undefined){throw r}if(s(K)===true){E.available[I]=true;J.flavor=I;D[I]=u.extend(J)}else{E.available[I]=false;E.enginePriority=i.map(E.enginePriority,function(L){if(L===I){return null}else{return L}})}}function v(){if(E.isReady){return}if((c&&E.isFlashReady)||!c){E.isReady=true;E.trigger("jstore-ready",[C[l]])}}function a(){E.create(E.enginePriority[0],undefined,"best-fit")}function H(){try{var J=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");try{J.AllowScriptAccess="always"}catch(L){return"6,0,0"}return new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version").replace(/\D+/g,",").match(/^,?(.+),?$/)[1]}catch(K){try{if(navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin){return(na! vigator.plugins["Shockwave Flash 2.0"]||navigator.plugins["Shockwave F lash"]).description.replace(/\D+/g,",").match(/^,?(.+),?$/)[1]}}catch(I){}}return"0,0,0"}function B(I){var N=H().match(/\d+/g),L=I.match(/\d+/g),J=0,K,M;for(;J<3;J++){K=parseInt(N[J],10);M=parseInt(L[J],10);if(K<M){return false}else{if(K>M){return true}}}return true}i.extend(E,{enginePriority:[b,y,F,A],available:{},isReady:false,isFlashReady:false,flavors:{local:b,sql:y,flash:F,gears:G,msie:A},init:function(J,K,I){i.extend(q,{project:J},K);i(function(){if(n.JSON===undefined){p(q.json)}if(I!==undefined){E.create(I,J,"default")}else{a()}});return E},create:function(I,M,J){M=M||q.project||location.hostname.replace(/\./g,"-")||"unknown";if(!z(I)){throw o}if(D[I]===undefined){throw m}var L=(J!==undefined?J+".":"")+M+"."+I,K;if(C[L]!==undefined){throw j}K=C[L]=new D[I](M,L);K.ready(function(){E.trigger("jstore-engine-ready",[K])});if(I===F&&!E.isFlashReady){if(l===undefined){c=true}n.jstore_ready=function(){E.isFlashReady=true;E.trigger("flash-ready");if(l===undefined){v()}n.flash! _ready=undefined};n.jstore_error=function(N){E.trigger("jstore-error",["JSTORE_FLASH_EXCEPTION",null,N])};i('<iframe style="height:1px;width:1px;position:absolute;left:0;top:0;margin-left:-100px;" id="jStoreFlashFrame" src="'+q.flash+'"></iframe>').appendTo("body")}else{if(l===undefined){l=L;v()}}return K},engine:function(I){return C[I]},activeEngine:function(I){if(I!==undefined){if(C[I]===undefined){throw t}else{l=I}}return C[l]},bind:function(J,K,I){I=I||"jstore";if(d[I]===undefined){d[I]={}}if(d[I][J]===undefined){d[I][J]=[K]}else{d[I][J].push(K)}return E},trigger:function(K,J,I){I=I||"jstore";if(d[I]!==undefined){if(d[I][K]!==undefined){i.each(d[I][K],function(){s(this,E,J)})}}return E},error:function(I){E.bind("jstore-error",I)},ready:function(I){if(E.isReady){s(I)}else{E.bind("jstore-ready",I)}return E},engineReady:function(I){if(E.isReady){s(I)}else{E.bind("jstore-engine-ready",I)}return E},store:function(I,J){return J===undefined?E.get(I):E.set(I,J)},remove:function! (I){return E.activeEngine().remove(I)},get:function(I){return E.active Engine().get(I)},set:function(I,J){return E.activeEngine().set(I,J)}});u=Class.extend({project:undefined,jri:undefined,flavor:undefined,database:undefined,data:undefined,limit:undefined,isReady:undefined,init:function(J,I){this.project=J;this.jri=I;this.data={};this.isReady=false;this.updateCache()},updateCache:function(){this.isReady=true;this.trigger("engine-ready",[this])},bind:function(I,J){E.bind(I,J,this.jri)},trigger:function(J,I){E.trigger(J,I,this.jri)},ready:function(I){if(this.isReady){s(I,this)}else{this.bind("engine-ready",I)}},get:function(I){this.__interruptAccess();return this.data[I]},set:function(I,J){this.__interruptAccess();I=w(I);try{this.__set(I,J)}catch(K){E.trigger("jstore-error",["JSTORE_STORAGE_FAILURE",this.jri,K])}this.data[I]=J;return J},remove:function(J){this.__interruptAccess();J=w(J);try{this.__remove(J)}catch(K){E.trigger("jstore-error",["JSTORE_REMOVE_FAILURE",this.jri,K])}var I=this.data[J];this.data[J]=undefined;return I},__interruptAcces! s:function(){if(!this.isReady){throw h}},__set:function(I,J){return},__remove:function(I){return}});i.extend(i.fn,{store:function(I,J){if(J===undefined){E.get(I)}else{E.set(I,J)}return this},removeStore:function(I){E.activeEngine().remove(I);return this},getStore:function(I){return E.activeEngine().get(I)},setStore:function(I,J){E.activeEngine().set(I,J);return this}});n.jStore=i.jStore=E;e(b,{limit:parseInt(500000,16),init:function(J,I){this.database=n.globalStorage===undefined?n.localStorage:n.globalStorage[location.hostname];this._super(J,I)},updateCache:function(){var J,K;for(J in this.database){var I=false;if(this.database.hasOwnProperty){if(this.database.hasOwnProperty(J)){I=true}}else{if(this.database.getItem(J)!==null){I=true}}if(I){K=this.database.getItem(J);this.data[J]=k(K&&K.value?K.value:K)}}this._super()},__set:function(I,J){this.database.setItem(I,x(J))},__remove:function(I){this.database.removeItem(I)}},function(){return n.localStorage!==undefined||n.globalS! torage!==undefined});e(y,{limit:parseInt(32000,16),init:function(J,I){ this.database=n.openDatabase("jstore-"+J,"1.0",J,this.limit);if(!this.database){throw"JSTORE_SQL_NO_DB"}this.database.transaction(function(K){K.executeSql("CREATE TABLE IF NOT EXISTS jstore (k TEXT UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)")});this._super(J,I)},updateCache:function(){var I=this,J=this._super;this.database.transaction(function(K){K.executeSql("SELECT k,v FROM jstore",[],function(O,L){var N=L.rows,M=0,P;for(;M<N.length;++M){P=N.item(M);I.data[P.k]=k(P.v)}J.apply(I)})})},__set:function(I,J){this.database.transaction(function(K){K.executeSql("INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)",[I,x(J)])})},__remove:function(I){this.database.transaction(function(J){J.executeSql("DELETE FROM jstore WHERE k = ?",[I])})}},function(){return n.openDatabase!==undefined});e(F,{limit:-1,init:function(K,J){var I=this;E.bind("flash-ready",function(){I.__flashReadyListener()});this._super(K,J)},updateCache:function(I){if(I===true){var J,K=this.database.jstore_get_all();f! or(J in K){if(K.hasOwnProperty(J)){this.data[J]=k(this.database.jstore_get(J))}}this._super()}},__set:function(I,J){if(!this.database.jstore_set(I,x(J))){E.trigger("jstore-error",["JSTORE_STORAGE_FAILURE",this.jri,"Flash Exception"])}},__remove:function(I){this.database.jstore_remove(I)},__flashReadyListener:function(){var I=i("#jStoreFlashFrame")[0],J;if(I.Document!==undefined&&g(I.Document.jStoreFlash.jstore_get,"Function")){this.database=I.Document.jStoreFlash}else{if(I.contentWindow&&I.contentWindow.document){J=i(I.contentWindow.document);if(g(i("object",J)[0].jstore_get,"Function")){this.database=i("object",J)[0]}else{if(g(i("embed",J)[0].jstore_get,"Function")){this.database=i("embed",J)[0]}}}}if(this.database===undefined){throw"JSTORE_FLASH_REFERENCE_ISSUE"}else{this.updateCache(true)}}},function(){return B("9.0.0")});e(G,{limit:-1,init:function(J,I){this.database=google.gears.factory.create("beta.database");this.database.open("jstore-"+J);this.database.execute("CREA! TE TABLE IF NOT EXISTS jstore (k TEXT UNIQUE NOT NULL PRIMARY KEY, v T EXT NOT NULL)");this._super(J,I)},updateCache:function(){var I=this.database.execute("SELECT k,v FROM jstore");while(I.isValidRow()){this.data[I.field(0)]=k(I.field(1));I.next()}I.close();this._super()},__set:function(I,J){this.database.execute("BEGIN");this.database.execute("INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)",[I,x(J)]);this.database.execute("COMMIT")},__remove:function(I){this.database.execute("BEGIN");this.database.execute("DELETE FROM jstore WHERE k = ?",[I]);this.database.execute("COMMIT")}},function(){return n.google!==undefined&&n.google.gears!==undefined});e(A,{limit:parseInt(10000,16),init:function(J,I){this.database=i('<div style="display:none;behavior:url(\'#default#userData\')" id="jstore-'+J+'"></div>').appendTo(document.body).get(0);this._super(J,I)},updateCache:function(){this.database.load(this.project);var K=document.getElementById("jstore-"+this.project),L=K.XMLDocument,I,J=0;if(L&&L.documentElement&&L.documentElement.attributes){I=L.document! Element;for(;J<I.attributes.length;++J){this.data[I.attributes.item(J).nodeName]=k(I.attributes.item(J).nodeValue)}}this._super()},__set:function(I,J){this.database.setAttribute(I,x(J));this.database.save(this.project)},__remove:function(I){this.database.removeAttribute(I);this.database.save(this.project)}},function(){return n.ActiveXObject!==undefined})}(jQuery,window)); \ No newline at end of file diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/packed/json2.js --- a/static/scripts/packed/json2.js Fri Apr 09 13:02:15 2010 -0400 +++ b/static/scripts/packed/json2.js Fri Apr 09 18:09:54 2010 -0400 @@ -1,1 +1,1 @@ -var JSON=JSON||{};(function(){function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0! ).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=st! r(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial. length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}if(typeof JSON.stringify!=="function"){JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":value})}}if(typeof JSON.parse!=="function"){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test! (text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}}()); \ No newline at end of file +if(!this.JSON){this.JSON={}}(function(){function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.ch! arCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(valu! e,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}} v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}if(typeof JSON.stringify!=="function"){JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":value})}}if(typeof JSON.parse!=="function"){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-! 4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}}()); \ No newline at end of file diff -r a9402fc7ce1b -r 5536d57237a3 templates/display_base.mako --- a/templates/display_base.mako Fri Apr 09 13:02:15 2010 -0400 +++ b/templates/display_base.mako Fri Apr 09 18:09:54 2010 -0400 @@ -32,29 +32,25 @@ <%def name="javascripts()"> ${parent.javascripts()} - ${h.js( "jquery", "jquery.tipsy", "galaxy.base", "json2", "jquery.autocomplete", "jquery.jstore-all", "autocomplete_tagging" )} + ${h.js( "jquery", "jquery.tipsy", "galaxy.base", "json2", "class", "jquery.jstore", "jquery.autocomplete", "autocomplete_tagging" )} <script type="text/javascript"> - // + // Handle click on community tag. - // - function community_tag_click(tag_name, tag_value) - { + function community_tag_click(tag_name, tag_value) { <% controller_name = get_controller_name( item ) %> var href = '${h.url_for ( controller='/' + controller_name , action='list_published')}'; href = href + "?f-tags=" + tag_name; - if (tag_value != undefined && tag_value != "") + if (tag_value != undefined && tag_value != "") { href = href + ":" + tag_value; + } self.location = href; } - $(document).ready( function() - { + $(function() { // Set links to Galaxy screencasts to open in overlay. - $(this).find("a[href^='http://screencast.g2.bx.psu.edu/']").each( function() - { - $(this).click( function() - { + $(this).find("a[href^='http://screencast.g2.bx.psu.edu/']").each( function() { + $(this).click( function() { var href = $(this).attr('href'); show_in_overlay( { @@ -67,7 +63,8 @@ return false; }); }); - + // Init history boxes + init_history_items( $("div.historyItemWrapper") ); }); </script> </%def> @@ -76,14 +73,12 @@ ${parent.stylesheets()} ${h.css( "autocomplete_tagging", "embed_item" )} <style type="text/css"> - .page-body - { + .page-body { padding: 10px; ## float: left; ## width: 65%; } - .page-meta - { + .page-meta { float: right; width: 27%; padding: 0.5em; diff -r a9402fc7ce1b -r 5536d57237a3 templates/history/display.mako --- a/templates/history/display.mako Fri Apr 09 13:02:15 2010 -0400 +++ b/templates/history/display.mako Fri Apr 09 18:09:54 2010 -0400 @@ -1,207 +1,14 @@ <%inherit file="/display_base.mako"/> <%namespace file="/root/history_common.mako" import="render_dataset" /> +## Set vars so that there's no need to change the code below. +<% + history = published_item + datasets = published_item_data +%> + <%def name="javascripts()"> ${parent.javascripts()} - ${h.js( "jquery.jstore-all" )} - - ## Set vars so that there's no need to change the code below. - <% - history = published_item - datasets = published_item_data - %> - - <script type="text/javascript"> - $(function() { - // Load jStore for local storage - $.extend(jQuery.jStore.defaults, { project: 'galaxy', flash: '/static/jStore.Flash.html' }) - $.jStore.load(); // Auto-select best storage