This commit is contained in:
James Taylor
2009-08-19 17:51:46 -04:00
15 changed files with 1719 additions and 274 deletions
+11 -10
View File
@@ -3,6 +3,7 @@ Classes for generating HTML forms
"""
import logging,sys
from cgi import escape
log = logging.getLogger(__name__)
class BaseField(object):
@@ -28,7 +29,7 @@ class TextField(BaseField):
self.value = value or ""
def get_html( self, prefix="" ):
return '<input type="text" name="%s%s" size="%d" value="%s">' \
% ( prefix, self.name, self.size, self.value )
% ( prefix, self.name, self.size, escape(str(self.value), quote=True) )
def set_size(self, size):
self.size = int( size )
@@ -49,7 +50,7 @@ class TextArea(BaseField):
self.value = value or ""
def get_html( self, prefix="" ):
return '<textarea name="%s%s" rows="%d" cols="%d">%s</textarea>' \
% ( prefix, self.name, self.rows, self.cols, self.value )
% ( prefix, self.name, self.rows, self.cols, escape(str(self.value), quote=True) )
def set_size(self, rows, cols):
self.rows = rows
self.cols = cols
@@ -113,7 +114,7 @@ class HiddenField(BaseField):
self.name = name
self.value = value or ""
def get_html( self, prefix="" ):
return '<input type="hidden" name="%s%s" value="%s">' % ( prefix, self.name, self.value )
return '<input type="hidden" name="%s%s" value="%s">' % ( prefix, self.name, escape(str(self.value), quote=True) )
class SelectField(BaseField):
"""
@@ -190,9 +191,9 @@ class SelectField(BaseField):
if len(self.options) > 2 and ctr % 2 == 1:
style = " class=\"odd_row\""
if selected:
rval.append( '<div%s><input type="checkbox" name="%s%s" value="%s" checked>%s</div>' % ( style, prefix, self.name, value, text) )
rval.append( '<div%s><input type="checkbox" name="%s%s" value="%s" checked>%s</div>' % ( style, prefix, self.name, escape(str(value), quote=True), text) )
else:
rval.append( '<div%s><input type="checkbox" name="%s%s" value="%s">%s</div>' % ( style, prefix, self.name, value, text) )
rval.append( '<div%s><input type="checkbox" name="%s%s" value="%s">%s</div>' % ( style, prefix, self.name, escape(str(value), quote=True), text) )
ctr += 1
return "\n".join( rval )
def get_html_radio( self, prefix="" ):
@@ -204,7 +205,7 @@ class SelectField(BaseField):
style = " class=\"odd_row\""
if selected: selected_text = " checked"
else: selected_text = ""
rval.append( '<div%s><input type="radio" name="%s%s"%s value="%s"%s>%s</div>' % ( style, prefix, self.name, self.refresh_on_change_text, value, selected_text, text ) )
rval.append( '<div%s><input type="radio" name="%s%s"%s value="%s"%s>%s</div>' % ( style, prefix, self.name, self.refresh_on_change_text, escape(str(value), quote=True), selected_text, text ) )
ctr += 1
return "\n".join( rval )
def get_html_default( self, prefix="" ):
@@ -217,9 +218,9 @@ class SelectField(BaseField):
selected_text = " selected"
last_selected_value = value
else: selected_text = ""
rval.append( '<option value="%s"%s>%s</option>' % ( value, selected_text, text ) )
rval.append( '<option value="%s"%s>%s</option>' % ( escape(str(value), quote=True), selected_text, text ) )
if last_selected_value:
last_selected_value = ' last_selected_value="%s"' % last_selected_value
last_selected_value = ' last_selected_value="%s"' % escape(str(last_selected_value), quote=True)
rval.insert( 0, '<select name="%s%s"%s%s%s>' % ( prefix, self.name, multiple, self.refresh_on_change_text, last_selected_value ) )
rval.append( '</select>' )
return "\n".join( rval )
@@ -326,12 +327,12 @@ class DrillDownField( BaseField ):
if option['value'] in expanded_options:
default_state = 'expanded'
default_icon = '[-]'
html.append( '<li><span class="toolParameterExpandableCollapsable">%s</span><input type="%s" name="%s%s" value="%s"%s">%s' % ( default_icon, self.display, prefix, self.name, option['value'], selected, option['name']) )
html.append( '<li><span class="toolParameterExpandableCollapsable">%s</span><input type="%s" name="%s%s" value="%s"%s">%s' % ( default_icon, self.display, prefix, self.name, escape(str(option['value']), quote=True), selected, option['name']) )
html.append( '<ul class="toolParameterExpandableCollapsable" default_state="%s">' % default_state )
recurse_options( html, option['options'], expanded_options )
html.append( '</ul>')
else:
html.append( '<li><input type="%s" name="%s%s" value="%s"%s">%s' % ( self.display, prefix, self.name, option['value'], selected, option['name']) )
html.append( '<li><input type="%s" name="%s%s" value="%s"%s">%s' % ( self.display, prefix, self.name, escape(str(option['value']), quote=True), selected, option['name']) )
html.append( '</li>' )
rval = []
rval.append( '<div><ul class="toolParameterExpandableCollapsable">' )
+19
View File
@@ -0,0 +1,19 @@
<!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#version=8,0,0,0" 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>
BIN
View File
Binary file not shown.
@@ -359,6 +359,7 @@ function Workflow( canvas_container ) {
this.nodes = {};
this.name = null;
this.has_changes = false;
this.active_form_has_changes = false;
}
$.extend( Workflow.prototype, {
add_node : function( node ) {
@@ -438,6 +439,28 @@ $.extend( Workflow.prototype, {
});
});
},
enable_auto_save : function() {
// Implements auto-saving based on whether the inputs change. We consider
// "changed" to be when a field is accessed and not necessarily modified
// because of an issue where "onchange" is not triggered when activating
// another node, or saving the workflow.
outer_this = this;
$(".toolFormBody").find("input,textarea,select").each( function() {
$(this).focus( function() {
outer_this.active_form_has_changes = true;
});
});
},
check_changes_in_active_form : function() {
// If active form has changed, save it
if (this.active_form_has_changes) {
this.has_changes = true;
$(".toolFormBody").find("form").each( function() {
$(this).submit();
});
this.active_form_has_changes = false;
}
},
clear_active_node : function() {
if ( this.active_node ) {
this.active_node.make_inactive();
@@ -447,6 +470,7 @@ $.extend( Workflow.prototype, {
},
activate_node : function( node ) {
if ( this.active_node != node ) {
this.check_changes_in_active_form();
this.clear_active_node();
parent.show_form_for_tool( node.form_html, node );
node.make_active();
@@ -461,6 +485,7 @@ $.extend( Workflow.prototype, {
}
},
layout : function () {
this.check_changes_in_active_form();
// Prepare predecessor / successor tracking
var n_pred = {};
var successors = {};
@@ -502,7 +527,7 @@ $.extend( Workflow.prototype, {
var v = level_parents[k];
delete n_pred[v];
for ( var sk in successors[v] ) {
n_pred[ sucessors[v][sk] ] -= 1;
n_pred[ successors[v][sk] ] -= 1;
}
}
}
@@ -805,6 +830,10 @@ $.extend( CanvasManager.prototype, {
self.draw_overview();
});
/* Disable dragging for child element of the panel so that resizing can
only be done by dragging the borders */
$("#overview-border div").bind("drag", function(e) { });
},
update_viewport_overlay: function() {
var cc = this.cc,
+748
View File
@@ -0,0 +1,748 @@
/*!
* 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-explorer-flash-6/
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);
+476
View File
@@ -0,0 +1,476 @@
/*
http://www.JSON.org/json2.js
2009-06-29
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See http://www.JSON.org/js.html
This file creates a global JSON object containing two methods: stringify
and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or '&nbsp;'),
it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
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.
For example, this would serialize Dates as ISO strings.
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
};
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.
Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.
Example:
text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[key] + ')' : value;
});
// text is '["Date(---current time---)"]'
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.
Example:
// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.
myData = JSON.parse(text, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
var d;
if (typeof value === 'string' &&
value.slice(0, 5) === 'Date(' &&
value.slice(-1) === ')') {
d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
return value;
});
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 */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
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 || {};
(function () {
function f(n) {
// Format integers to have at least two digits.
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 = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
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) {
// Produce a string from holder[key].
var i, // The loop counter.
k, // The member key.
v, // The member value.
length,
mind = gap,
partial,
value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
if (!value) {
return 'null';
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0 ? '[]' :
gap ? '[\n' + gap +
partial.join(',\n' + gap) + '\n' +
mind + ']' :
'[' + partial.join(',') + ']';
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
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 {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0 ? '{}' :
gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
mind + '}' : '{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i;
gap = '';
indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === 'string') {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str('', {'': value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j;
function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
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);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
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, ''))) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')');
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function' ?
walk({'': j}, '') : j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError('JSON.parse');
};
}
}());
+61
View File
@@ -0,0 +1,61 @@
/*
JSONCookie: Uses JSON to allow the settings of multiple preferences in one cookie.
Kanwei Li, 2009
cookie = new JSONCookie("cookie_name"); // Pass in the name of the cookie
// Gets the value of a preference, returns optional second argument if pref not found
cookie.get("pref", "val_if_not_found");
cookie.set("pref", "val"); // Sets a value for the preference and saves cookie
cookie.unset("pref"); // Unsets the preference and saves cookie
cookie.clear() // Deletes the cookie
*/
function JSONCookie(name) {
this.cookie_name = name;
}
JSONCookie.prototype = {
json_data : function() {
cookie = $.cookie(this.cookie_name);
return cookie ? JSON.parse(cookie) : null;
},
save : function(data) {
$.cookie(this.cookie_name, JSON.stringify(data));
},
get : function(attr, else_val) {
data = this.json_data();
if (data && data[attr]) { return data[attr];
} else if (else_val) { return else_val;
} else { return null;
}
},
set : function(attr, val) {
data = this.json_data();
if (data) {
data[attr] = val;
} else {
data = { attr : val }
}
this.save(data);
},
unset : function(attr) {
data = this.json_data();
if (data) {
delete data[attr];
}
this.save(data);
},
clear : function() {
this.save(null);
}
};
File diff suppressed because one or more lines are too long
@@ -0,0 +1,41 @@
/*
* 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
*/
(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}})();
/*
* jStore Delegate Framework
* Copyright (c) 2009 Eric Garside (http://eric.garside.name)
*/
(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,{EngineOrder:[],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");return 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:function(){var b=this,d=this.includes.length,c=0;a.each(this.includes,function(){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);
/*
* jStore DOM Storage Engine
* Copyright (c) 2009 Eric Garside (http://eric.garside.name)
*/
(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);
/*
* 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(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.flash+'"></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.ShockwaveFlash.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")}
/*
* jStore Google Gears Storage Engine
* Copyright (c) 2009 Eric Garside (http://eric.garside.name)
*/
(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 TEXT 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);
/*
* jStore HTML5 Specification Storage Engine
* Copyright (c) 2009 Eric Garside (http://eric.garside.name)
*/
(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);
/**
* jStore IE Storage Engine
* Copyright (c) 2009 Eric Garside (http://eric.garside.name)
*/
(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.project+'"></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);
+1
View File
@@ -0,0 +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=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)}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")}}}());
+228 -205
View File
@@ -15,219 +15,242 @@
<meta http-equiv="Pragma" content="no-cache">
${h.css( "base", "history" )}
${h.js( "jquery", "jquery.cookie", "cookie_set" )}
${h.js( "jquery", "json2", "jquery.jstore-all" )}
<script type="text/javascript">
$( document ).ready( function() {
initShowHide();
setupHistoryItem( $("div.historyItemWrapper") );
// Collapse all
$("#top-links").append( "|&nbsp;" ).append( $("<a href='#'>${_('collapse all')}</a>").click( function() {
$( "div.historyItemBody:visible" ).each( function() {
if ( $.browser.mozilla )
{
$(this).find( "pre.peek" ).css( "overflow", "hidden" );
}
$(this).slideUp( "fast" );
})
var state = new CookieSet( "galaxy.history.expand_state" );
state.removeAll().save();
return false;
}));
$("#history-rename").click( function() {
var old_name = $("#history-name").text()
var t = $("<input type='text' value='" + old_name + "'></input>" );
t.blur( function() {
$(this).remove();
$("#history-name").show();
});
t.keyup( function( e ) {
if ( e.keyCode == 27 ) {
// Escape key
$(this).trigger( "blur" );
} else if ( e.keyCode == 13 ) {
// Enter key
new_value = this.value;
$(this).trigger( "blur" );
$.ajax({
url: "${h.url_for( controller='history', action='rename_async', id=history.id )}",
data: { "_": true, new_name: new_value },
error: function() { alert( "Rename failed" ) },
success: function() {
$("#history-name").text( new_value );
}
});
}
});
$("#history-name").hide();
$("#history-name-area").append( t );
t.focus();
return false;
});
// Updater
updater({
%for i, data in enumerate( reversed( datasets ) ):
%if data.visible and data.state not in [ "deleted", "empty", "error", "ok" ]:
%if i > 0:
,
%endif
"${data.id}": "${data.state}"
%endif
%endfor
$(function() {
// Load jStore for local storage
$.extend(jQuery.jStore.defaults, { project: 'galaxy', flash: '/static/jStore.Flash.html' })
$.jStore.load(); // Auto-select best storage
$.jStore.ready(function(engine) {
engine.ready(function() {
// Init stuff that requires the local storage to be running
initShowHide();
setupHistoryItem( $("div.historyItemWrapper") );
});
})
//' Functionized so AJAX'd datasets can call them
// Get shown/hidden state from cookie
function initShowHide() {
// $( "div.historyItemBody" ).hide();
// Load saved state and show as neccesary
var state = new CookieSet( "galaxy.history.expand_state" );
for ( id in state.store ) {
if ( id ) {
$( "#" + id + " div.historyItemBody" ).show();
}
}
// 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" );
})
}
delete state;
}
// Add show/hide link and delete link to a history item
function setupHistoryItem( query ) {
query.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") ) {
if ( $.browser.mozilla ) { peek.css( "overflow", "hidden" ) }
body.slideUp( "fast" );
## other instances of this could be editing the cookie, refetch
var state = new CookieSet( "galaxy.history.expand_state" );
state.remove( id ); state.save();
delete state;
}
else {
body.slideDown( "fast", function() {
if ( $.browser.mozilla ) { peek.css( "overflow", "auto" ); }
});
var state = new CookieSet( "galaxy.history.expand_state" );
state.add( id ); state.save();
delete state;
}
return false;
});
// Delete link
$(this).find( "div.historyItemButtons > .delete" ).each( function() {
var data_id = this.id.split( "-" )[1];
$(this).click( function() {
$( '#historyItem-' + data_id + "> div.historyItemTitleBar" ).addClass( "spinner" );
$.ajax({
url: "${h.url_for( action='delete_async', id='XXX' )}".replace( 'XXX', data_id ),
error: function() { alert( "Delete failed" ) },
success: function() {
%if show_deleted:
var to_update = {};
to_update[data_id] = "none";
updater( to_update );
%else:
$( "#historyItem-" + data_id ).fadeOut( "fast", function() {
$( "#historyItemContainer-" + data_id ).remove();
if ( $( "div.historyItemContainer" ).length < 1 ) {
$( "#emptyHistoryMessage" ).show();
}
});
%endif
}
});
return false;
});
});
// Undelete link
$(this).find( "a.historyItemUndelete" ).each( function() {
var data_id = this.id.split( "-" )[1];
$(this).click( function() {
$( '#historyItem-' + data_id + " > div.historyItemTitleBar" ).addClass( "spinner" );
$.ajax({
url: "${h.url_for( controller='dataset', action='undelete_async', id='XXX' )}".replace( 'XXX', data_id ),
error: function() { alert( "Undelete failed" ) },
success: function() {
var to_update = {};
to_update[data_id] = "none";
updater( to_update );
}
});
return false;
});
});
});
// Generate 'collapse all' link
$("#top-links").append( "|&nbsp;" ).append( $("<a href='#'>${_('collapse all')}</a>").click( function() {
$( "div.historyItemBody:visible" ).each( function() {
if ( $.browser.mozilla ) {
$(this).find( "pre.peek" ).css( "overflow", "hidden" );
}
$(this).slideUp( "fast" );
});
};
// Looks for changes in dataset state using an async request. Keeps
// calling itself (via setTimeout) until all datasets are in a terminal
// state.
var updater = function ( tracked_datasets ) {
// Check if there are any items left to track
var empty = true;
for ( i in tracked_datasets ) {
empty = false;
break;
}
if ( ! empty ) {
// console.log( "Updater running in 3 seconds" );
setTimeout( function() { updater_callback( tracked_datasets ) }, 3000 );
} else {
// console.log( "Updater finished" );
}
};
var updater_callback = function ( tracked_datasets ) {
// Build request data
var ids = []
var states = []
var force_history_refresh = false
$.each( tracked_datasets, function ( id, state ) {
ids.push( id );
states.push( state );
$.jStore.remove("history_expand_state");
}));
$("#history-rename").click( function() {
var old_name = $("#history-name").text()
var t = $("<input type='text' value='" + old_name + "'></input>" );
t.blur( function() {
$(this).remove();
$("#history-name").show();
});
// Make ajax call
$.ajax( {
type: "POST",
url: "${h.url_for( controller='root', action='history_item_updates' )}",
dataType: "json",
data: { ids: ids.join( "," ), states: states.join( "," ) },
success : function ( data ) {
$.each( data, function( id, val ) {
// Replace HTML
var container = $("#historyItemContainer-" + id);
container.html( val.html );
setupHistoryItem( container.children( ".historyItemWrapper" ) );
initShowHide();
// If new state was terminal, stop tracking
if (( val.state == "ok") || ( val.state == "error") || ( val.state == "empty") || ( val.state == "deleted" ) || ( val.state == "discarded" )) {
if ( val.force_history_refresh ){
force_history_refresh = true;
}
delete tracked_datasets[ parseInt(id) ];
} else {
tracked_datasets[ parseInt(id) ] = val.state;
t.keyup( function( e ) {
if ( e.keyCode == 27 ) {
// Escape key
$(this).trigger( "blur" );
} else if ( e.keyCode == 13 ) {
// Enter key
new_value = this.value;
$(this).trigger( "blur" );
$.ajax({
url: "${h.url_for( controller='history', action='rename_async', id=history.id )}",
data: { "_": true, new_name: new_value },
error: function() { alert( "Rename failed" ) },
success: function() {
$("#history-name").text( new_value );
}
});
if ( force_history_refresh ) {
parent.frames.galaxy_history.location.reload();
}
else {
// Keep going (if there are still any items to track)
updater( tracked_datasets );
}
},
error: function() {
// Just retry, like the old method, should try to be smarter
updater( tracked_datasets );
}
});
};
$("#history-name").hide();
$("#history-name-area").append( t );
t.focus();
return false;
});
// Updater
updater({
%for i, data in enumerate( reversed( datasets ) ):
%if data.visible and data.state not in [ "deleted", "empty", "error", "ok" ]:
%if i > 0:
,
%endif
"${data.id}": "${data.state}"
%endif
%endfor
});
});
// Functionized so AJAX'd datasets can call them
// Get shown/hidden state from cookie
function initShowHide() {
// Load saved state and show as neccesary
try {
var stored = $.jStore.store("history_expand_state");
if (stored) {
var st = JSON.parse(stored);
for (var id in st) {
$("#" + 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" );
})
}
}
// Add show/hide link and delete link to a history item
function setupHistoryItem( query ) {
query.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" );
// Save setting
var stored = $.jStore.store("history_expand_state")
var prefs = stored ? JSON.parse(stored) : null
if (prefs) {
delete prefs[id];
$.jStore.store("history_expand_state", JSON.stringify(prefs));
}
}
else {
// Showing stuff here
body.slideDown( "fast", function() {
if ( $.browser.mozilla ) { peek.css( "overflow", "auto" ); }
});
// Save setting
var stored = $.jStore.store("history_expand_state")
var prefs = stored ? JSON.parse(stored) : new Object;
prefs[id] = true;
$.jStore.store("history_expand_state", JSON.stringify(prefs));
}
return false;
});
// Delete link
$(this).find( "div.historyItemButtons > .delete" ).each( function() {
var data_id = this.id.split( "-" )[1];
$(this).click( function() {
$( '#historyItem-' + data_id + "> div.historyItemTitleBar" ).addClass( "spinner" );
$.ajax({
url: "${h.url_for( action='delete_async', id='XXX' )}".replace( 'XXX', data_id ),
error: function() { alert( "Delete failed" ) },
success: function() {
%if show_deleted:
var to_update = {};
to_update[data_id] = "none";
updater( to_update );
%else:
$( "#historyItem-" + data_id ).fadeOut( "fast", function() {
$( "#historyItemContainer-" + data_id ).remove();
if ( $( "div.historyItemContainer" ).length < 1 ) {
$( "#emptyHistoryMessage" ).show();
}
});
%endif
}
});
return false;
});
});
// Undelete link
$(this).find( "a.historyItemUndelete" ).each( function() {
var data_id = this.id.split( "-" )[1];
$(this).click( function() {
$( '#historyItem-' + data_id + " > div.historyItemTitleBar" ).addClass( "spinner" );
$.ajax({
url: "${h.url_for( controller='dataset', action='undelete_async', id='XXX' )}".replace( 'XXX', data_id ),
error: function() { alert( "Undelete failed" ) },
success: function() {
var to_update = {};
to_update[data_id] = "none";
updater( to_update );
}
});
return false;
});
});
});
};
// Looks for changes in dataset state using an async request. Keeps
// calling itself (via setTimeout) until all datasets are in a terminal
// state.
var updater = function ( tracked_datasets ) {
// Check if there are any items left to track
var empty = true;
for ( i in tracked_datasets ) {
empty = false;
break;
}
if ( ! empty ) {
// console.log( "Updater running in 3 seconds" );
setTimeout( function() { updater_callback( tracked_datasets ) }, 3000 );
} else {
// console.log( "Updater finished" );
}
};
var updater_callback = function ( tracked_datasets ) {
// Build request data
var ids = []
var states = []
var force_history_refresh = false
$.each( tracked_datasets, function ( id, state ) {
ids.push( id );
states.push( state );
});
// Make ajax call
$.ajax( {
type: "POST",
url: "${h.url_for( controller='root', action='history_item_updates' )}",
dataType: "json",
data: { ids: ids.join( "," ), states: states.join( "," ) },
success : function ( data ) {
$.each( data, function( id, val ) {
// Replace HTML
var container = $("#historyItemContainer-" + id);
container.html( val.html );
setupHistoryItem( container.children( ".historyItemWrapper" ) );
initShowHide();
// If new state was terminal, stop tracking
if (( val.state == "ok") || ( val.state == "error") || ( val.state == "empty") || ( val.state == "deleted" ) || ( val.state == "discarded" )) {
if ( val.force_history_refresh ){
force_history_refresh = true;
}
delete tracked_datasets[ parseInt(id) ];
} else {
tracked_datasets[ parseInt(id) ] = val.state;
}
});
if ( force_history_refresh ) {
parent.frames.galaxy_history.location.reload();
}
else {
// Keep going (if there are still any items to track)
updater( tracked_datasets );
}
},
error: function() {
// Just retry, like the old method, should try to be smarter
updater( tracked_datasets );
}
});
};
</script>
<style>
+89 -48
View File
@@ -31,6 +31,7 @@
<script type='text/javascript' src="${h.url_for('/static/scripts/jquery.event.hover.js')}"> </script>
<script type='text/javascript' src="${h.url_for('/static/scripts/jquery.form.js')}"> </script>
<script type='text/javascript' src="${h.url_for('/static/scripts/jquery.json.js')}"> </script>
<script type='text/javascript' src="${h.url_for('/static/scripts/jquery.jstore-all.js')}"> </script>
<script type='text/javascript' src="${h.url_for('/static/scripts/galaxy.base.js')}"> </script>
<script type='text/javascript' src="${h.url_for('/static/scripts/galaxy.workflow_editor.canvas.js')}"> </script>
@@ -47,6 +48,7 @@
canvas_manager = null;
// jQuery onReady
$( function() {
if ( window.lt_ie_7 ) {
show_modal(
"Browser not supported",
@@ -54,8 +56,14 @@
);
return;
}
// Load jStore for local storage
$.extend(jQuery.jStore.defaults, { project: 'galaxy', flash: '/static/jStore.Flash.html' })
$.jStore.load(); // Auto-select best storage
// Canvas overview management
canvas_manager = new CanvasManager( $("#canvas-viewport"), $("#overview") );
// Initialize workflow state
reset();
// Load the datatype info
@@ -121,17 +129,46 @@
canvas_manager.draw_overview();
});
/* Lets the viewport be toggled visible and invisible, adjusting the arrows accordingly */
$("#close-viewport").click( function() {
if ( $("#overview-border").css("right") == "0px" ) {
$("#overview-border").css("right", "20000px");
$("#close-viewport").css("background-position", "12px 0px");
$.jStore.ready(function(engine) {
engine.ready(function() {
// On load, set the size to the pref stored in local storage if it exists
overview_size = $.jStore.store("overview-size");
if (overview_size) {
$("#overview-border").css( {
width: overview_size,
height: overview_size
});
}
} else {
$("#overview-border").css("right", "0px");
$("#close-viewport").css("background-position", "0px 0px");
}
// Show viewport on load unless pref says it's off
$.jStore.store("overview-off") ? hide_overview() : show_overview()
});
});
// Stores the size of the overview into local storage when it's resized
$("#overview-border").bind( "dragend", function( e ) {
var op = $(this).offsetParent();
var opo = op.offset();
var new_size = Math.max( op.width() - ( e.offsetX - opo.left ),
op.height() - ( e.offsetY - opo.top ) );
$.jStore.store("overview-size", new_size + "px");
});
function show_overview() {
$.jStore.remove("overview-off");
$("#overview-border").css("right", "0px");
$("#close-viewport").css("background-position", "0px 0px");
}
function hide_overview() {
$.jStore.store("overview-off", true);
$("#overview-border").css("right", "20000px");
$("#close-viewport").css("background-position", "12px 0px");
}
// Lets the overview be toggled visible and invisible, adjusting the arrows accordingly
$("#close-viewport").click( function() {
$("#overview-border").css("right") == "0px" ? hide_overview() : show_overview();
});
// Unload handler
@@ -245,10 +282,6 @@
beforeSubmit: function( data ) {
data.push( { name: 'tool_state', value: node.tool_state } );
data.push( { name: '_', value: "true" } );
$("#tool-form-save-button").each( function() {
this.value = "Saving...";
this.disabled = true;
});
}
}).each( function() {
form = this;
@@ -275,6 +308,7 @@
var close_editor = function() {
<% next_url = h.url_for( controller='workflow', action='index' ) %>
workflow.check_changes_in_active_form();
if ( workflow && workflow.has_changes ) {
do_close = function() {
window.onbeforeunload = undefined;
@@ -297,39 +331,46 @@
var save_current_workflow = function ( success_callback ) {
show_modal( "Saving workflow", "progress" );
$.ajax( {
url: "${h.url_for( action='save_workflow' )}",
type: "POST",
data: {
id: "${trans.security.encode_id( workflow_id )}",
workflow_data: $.toJSON( workflow.to_simple() ),
"_": "true"
},
dataType: 'json',
success: function( data ) {
var body = $("<div></div>").text( data.message );
if ( data.errors ) {
body.addClass( "warningmark" )
var errlist = $( "<ul/>" );
$.each( data.errors, function( i, v ) {
$("<li></li>").text( v ).appendTo( errlist );
});
body.append( errlist );
} else {
body.addClass( "donemark" );
workflow.check_changes_in_active_form();
// We bind to ajaxStop because of auto-saving, since the form submission ajax
// call needs to be completed so that the new data is saved
$(document).bind('ajaxStop.save_workflow', function() {
$(document).unbind('ajaxStop.save_workflow');
$.ajax( {
url: "${h.url_for( action='save_workflow' )}",
type: "POST",
data: {
id: "${trans.security.encode_id( workflow_id )}",
workflow_data: function() { return $.toJSON( workflow.to_simple() ) },
"_": "true"
},
dataType: 'json',
success: function( data ) {
var body = $("<div></div>").text( data.message );
if ( data.errors ) {
body.addClass( "warningmark" )
var errlist = $( "<ul/>" );
$.each( data.errors, function( i, v ) {
$("<li></li>").text( v ).appendTo( errlist );
});
body.append( errlist );
} else {
body.addClass( "donemark" );
}
workflow.name = data.name;
workflow.has_changes = false;
workflow.stored = true;
if ( success_callback ) {
success_callback();
}
if ( data.errors ) {
show_modal( "Saving workflow", body, { "Ok" : hide_modal } );
} else {
hide_modal();
}
}
workflow.name = data.name;
workflow.has_changes = false;
workflow.stored = true;
if ( success_callback ) {
success_callback();
}
if ( data.errors ) {
show_modal( "Saving workflow", body, { "Ok" : hide_modal } );
} else {
hide_modal();
}
}
});
$(document).unbind('ajaxStop.save_workflow'); // IE7 needs it here
});
}
@@ -642,7 +683,7 @@
<div id="canvas-viewport" style="width: 100%; height: 100%; position: absolute; overflow: hidden; background: #EEEEEE; background: white url(${h.url_for('/static/images/light_gray_grid.gif')}) repeat;">
<div id="canvas-container" style="position: absolute; width: 100%; height: 100%;"></div>
</div>
<div id="overview-border" style="position: absolute; width: 150px; height: 150px; right: 0px; bottom: 0px; border-top: solid gray 1px; border-left: solid grey 1px; padding: 7px 0 0 7px; background: #EEEEEE no-repeat url(${h.url_for('/static/images/resizable.png')}); z-index: 20000; overflow: hidden; max-width: 300px; max-height: 300px; min-width: 50px; min-height: 50px">
<div id="overview-border" style="position: absolute; width: 150px; height: 150px; right: 20000px; bottom: 0px; border-top: solid gray 1px; border-left: solid grey 1px; padding: 7px 0 0 7px; background: #EEEEEE no-repeat url(${h.url_for('/static/images/resizable.png')}); z-index: 20000; overflow: hidden; max-width: 300px; max-height: 300px; min-width: 50px; min-height: 50px">
<div style="position: relative; overflow: hidden; width: 100%; height: 100%; border-top: solid gray 1px; border-left: solid grey 1px;">
<div id="overview" style="position: absolute;">
<canvas width="0" height="0" style="background: white; width: 100%; height: 100%;" id="overview-canvas"></canvas>
@@ -650,7 +691,7 @@
</div>
</div>
</div>
<div id="close-viewport" style="border-left: 1px solid #999; border-top: 1px solid #999; background: #ddd url(${h.url_for('/static/images/overview_arrows.png')}); position: absolute; right: 0px; bottom: 0px; width: 12px; height: 12px; z-index: 25000;"></div>
<div id="close-viewport" style="border-left: 1px solid #999; border-top: 1px solid #999; background: #ddd url(${h.url_for('/static/images/overview_arrows.png')}) 12px 0px; position: absolute; right: 0px; bottom: 0px; width: 12px; height: 12px; z-index: 25000;"></div>
</div>
</%def>
+6 -3
View File
@@ -15,7 +15,7 @@
${input.label}:
</label>
<div style="float: left; width: 250px; margin-right: 10px;">
<input type="${input.type}" name="${input.name}" value="${input.value}" size="40">
<input type="${input.type}" name="${input.name | h}" value="${input.value | h}" size="30">
</div>
%if input.error:
<div style="float: left; color: red; font-weight: bold; padding-top: 1px; padding-bottom: 3px;">
@@ -33,11 +33,14 @@
</div>
%endfor
<div class="form-row"><input type="submit" value="${form.submit_text}"></div>
%else:
<div class="form-row"><i>No options</i></div>
%endif
</table>
</form>
</div>
</div>
</div>
<script type="text/javascript">
workflow.enable_auto_save();
</script>
+7 -5
View File
@@ -93,7 +93,7 @@ from galaxy.util.expressions import ExpressionContext
<div style="clear: both"></div>
</div>
</%def>
<div class="toolForm">
<div class="toolFormTitle">Tool: ${tool.name}</div>
<div class="toolFormBody">
@@ -105,9 +105,11 @@ from galaxy.util.expressions import ExpressionContext
%endif
${do_inputs( inputs, values, errors, "" )}
%endfor
<div class="form-row">
<input type="submit" id="tool-form-save-button" value="Save"></input>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript">
workflow.enable_auto_save();
</script>
+1 -1
View File
@@ -74,7 +74,7 @@ See Galaxy Interval Operation Screencasts_ (right click to open this link in ano
**Syntax**
- **Maximum distance** is greatest distance in base pairs allowed between intervals that will be considered &quot;clustered&quot;. **Negative** values for distance are allowed, and are useful for clustering intervals that overlap.
- **Minimum intervals per cluster** allow a threshold to be set on the minimum number of intervals to be considered a cluster. Any area with less than this minimum will not be included in the ouput.
- **Minimum intervals per cluster** allow a threshold to be set on the minimum number of intervals to be considered a cluster. Any area with less than this minimum will not be included in the output.
- **Merge clusters into single intervals** outputs intervals that span the entire cluster.
- **Find cluster intervals; preserve comments and order** filters out non-cluster intervals while maintaining the original ordering and comments in the file.
- **Find cluster intervals; output grouped by clusters** filters out non-cluster intervals, but outputs the cluster intervals so that they are grouped together. Comments and original ordering in the file are lost.