[MERGE]
bzr revid: nicolas.vanhoren@openerp.com-20110407101319-5axkyl54kts7u7n4
|
@ -9,10 +9,7 @@ import openerpweb
|
|||
import openerpweb.ast
|
||||
import openerpweb.nonliterals
|
||||
|
||||
__all__ = ['Session', 'Menu', 'DataSet', 'DataRecord',
|
||||
'View', 'FormView', 'ListView', 'SearchView',
|
||||
'Action']
|
||||
|
||||
# Should move to openerpweb.Xml2Json
|
||||
class Xml2Json:
|
||||
# xml2json-direct
|
||||
# Simple and straightforward XML-to-JSON converter in Python
|
||||
|
@ -280,12 +277,9 @@ class DataSet(openerpweb.Controller):
|
|||
return {'fields': req.session.model(model).fields_get()}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def find(self, request, model, fields=False, offset=0, limit=False,
|
||||
domain=None, context=None, sort=None):
|
||||
return self.do_find(request, model, fields, offset, limit,
|
||||
domain, context, sort)
|
||||
def do_find(self, request, model, fields=False, offset=0, limit=False,
|
||||
domain=None, context=None, sort=None):
|
||||
def search_read(self, request, model, fields=False, offset=0, limit=False, domain=None, context=None, sort=None):
|
||||
return self.do_search_read(request, model, fields, offset, limit, domain, context, sort)
|
||||
def do_search_read(self, request, model, fields=False, offset=0, limit=False, domain=None, context=None, sort=None):
|
||||
""" Performs a search() followed by a read() (if needed) using the
|
||||
provided search criteria
|
||||
|
||||
|
@ -313,7 +307,6 @@ class DataSet(openerpweb.Controller):
|
|||
@openerpweb.jsonrequest
|
||||
def get(self, request, model, ids, fields=False):
|
||||
return self.do_get(request, model, ids, fields)
|
||||
|
||||
def do_get(self, request, model, ids, fields=False):
|
||||
""" Fetches and returns the records of the model ``model`` whose ids
|
||||
are in ``ids``.
|
||||
|
@ -336,11 +329,8 @@ class DataSet(openerpweb.Controller):
|
|||
record_map = dict((record['id'], record) for record in records)
|
||||
|
||||
return [record_map[id] for id in ids if record_map.get(id)]
|
||||
|
||||
class DataRecord(openerpweb.Controller):
|
||||
_cp_path = "/base/datarecord"
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
|
||||
def load(self, req, model, id, fields):
|
||||
m = req.session.model(model)
|
||||
value = {}
|
||||
|
@ -350,9 +340,15 @@ class DataRecord(openerpweb.Controller):
|
|||
return {'value': value}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def save(self, req, model, id, data):
|
||||
def save(self, req, model, id, data, context={}):
|
||||
m = req.session.model(model)
|
||||
r = m.write([id], data)
|
||||
r = m.write([id], data, context)
|
||||
return {'result': r}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def call(self, req, model, method, ids, args):
|
||||
m = req.session.model(model)
|
||||
r = getattr(m, method)(ids, *args)
|
||||
return {'result': r}
|
||||
|
||||
class View(openerpweb.Controller):
|
||||
|
@ -466,7 +462,6 @@ class FormView(View):
|
|||
fields_view = self.fields_view_get(req.session, model, view_id, 'form', toolbar=toolbar)
|
||||
return {'fields_view': fields_view}
|
||||
|
||||
|
||||
class ListView(View):
|
||||
_cp_path = "/base/listview"
|
||||
|
||||
|
@ -475,7 +470,6 @@ class ListView(View):
|
|||
fields_view = self.fields_view_get(req.session, model, view_id, 'tree', toolbar=toolbar)
|
||||
return {'fields_view': fields_view}
|
||||
|
||||
|
||||
class SearchView(View):
|
||||
_cp_path = "/base/searchview"
|
||||
|
||||
|
@ -484,7 +478,6 @@ class SearchView(View):
|
|||
fields_view = self.fields_view_get(req.session, model, view_id, 'search')
|
||||
return {'fields_view': fields_view}
|
||||
|
||||
|
||||
class Action(openerpweb.Controller):
|
||||
_cp_path = "/base/action"
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*!
|
||||
* jQuery JavaScript Library v1.5.1
|
||||
* jQuery JavaScript Library v1.5.2
|
||||
* http://jquery.com/
|
||||
*
|
||||
* Copyright 2011, John Resig
|
||||
|
@ -11,7 +11,7 @@
|
|||
* Copyright 2011, The Dojo Foundation
|
||||
* Released under the MIT, BSD, and GPL Licenses.
|
||||
*
|
||||
* Date: Wed Feb 23 13:55:29 2011 -0500
|
||||
* Date: Thu Mar 31 15:28:23 2011 -0400
|
||||
*/
|
||||
(function( window, undefined ) {
|
||||
|
||||
|
@ -69,15 +69,9 @@ var jQuery = function( selector, context ) {
|
|||
// For matching the engine and version of the browser
|
||||
browserMatch,
|
||||
|
||||
// Has the ready events already been bound?
|
||||
readyBound = false,
|
||||
|
||||
// The deferred used on DOM ready
|
||||
readyList,
|
||||
|
||||
// Promise methods
|
||||
promiseMethods = "then done fail isResolved isRejected promise".split( " " ),
|
||||
|
||||
// The ready event handler
|
||||
DOMContentLoaded,
|
||||
|
||||
|
@ -202,7 +196,7 @@ jQuery.fn = jQuery.prototype = {
|
|||
selector: "",
|
||||
|
||||
// The current version of jQuery being used
|
||||
jquery: "1.5.1",
|
||||
jquery: "1.5.2",
|
||||
|
||||
// The default length of a jQuery object is 0
|
||||
length: 0,
|
||||
|
@ -427,11 +421,11 @@ jQuery.extend({
|
|||
},
|
||||
|
||||
bindReady: function() {
|
||||
if ( readyBound ) {
|
||||
if ( readyList ) {
|
||||
return;
|
||||
}
|
||||
|
||||
readyBound = true;
|
||||
readyList = jQuery._Deferred();
|
||||
|
||||
// Catch cases where $(document).ready() is called after the
|
||||
// browser event has already occurred.
|
||||
|
@ -811,171 +805,6 @@ jQuery.extend({
|
|||
return (new Date()).getTime();
|
||||
},
|
||||
|
||||
// Create a simple deferred (one callbacks list)
|
||||
_Deferred: function() {
|
||||
var // callbacks list
|
||||
callbacks = [],
|
||||
// stored [ context , args ]
|
||||
fired,
|
||||
// to avoid firing when already doing so
|
||||
firing,
|
||||
// flag to know if the deferred has been cancelled
|
||||
cancelled,
|
||||
// the deferred itself
|
||||
deferred = {
|
||||
|
||||
// done( f1, f2, ...)
|
||||
done: function() {
|
||||
if ( !cancelled ) {
|
||||
var args = arguments,
|
||||
i,
|
||||
length,
|
||||
elem,
|
||||
type,
|
||||
_fired;
|
||||
if ( fired ) {
|
||||
_fired = fired;
|
||||
fired = 0;
|
||||
}
|
||||
for ( i = 0, length = args.length; i < length; i++ ) {
|
||||
elem = args[ i ];
|
||||
type = jQuery.type( elem );
|
||||
if ( type === "array" ) {
|
||||
deferred.done.apply( deferred, elem );
|
||||
} else if ( type === "function" ) {
|
||||
callbacks.push( elem );
|
||||
}
|
||||
}
|
||||
if ( _fired ) {
|
||||
deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// resolve with given context and args
|
||||
resolveWith: function( context, args ) {
|
||||
if ( !cancelled && !fired && !firing ) {
|
||||
firing = 1;
|
||||
try {
|
||||
while( callbacks[ 0 ] ) {
|
||||
callbacks.shift().apply( context, args );
|
||||
}
|
||||
}
|
||||
// We have to add a catch block for
|
||||
// IE prior to 8 or else the finally
|
||||
// block will never get executed
|
||||
// catch (e) {
|
||||
// throw e;
|
||||
// }
|
||||
finally {
|
||||
fired = [ context, args ];
|
||||
firing = 0;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// resolve with this as context and given arguments
|
||||
resolve: function() {
|
||||
deferred.resolveWith( jQuery.isFunction( this.promise ) ? this.promise() : this, arguments );
|
||||
return this;
|
||||
},
|
||||
|
||||
// Has this deferred been resolved?
|
||||
isResolved: function() {
|
||||
return !!( firing || fired );
|
||||
},
|
||||
|
||||
// Cancel
|
||||
cancel: function() {
|
||||
cancelled = 1;
|
||||
callbacks = [];
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
return deferred;
|
||||
},
|
||||
|
||||
// Full fledged deferred (two callbacks list)
|
||||
Deferred: function( func ) {
|
||||
var deferred = jQuery._Deferred(),
|
||||
failDeferred = jQuery._Deferred(),
|
||||
promise;
|
||||
// Add errorDeferred methods, then and promise
|
||||
jQuery.extend( deferred, {
|
||||
then: function( doneCallbacks, failCallbacks ) {
|
||||
deferred.done( doneCallbacks ).fail( failCallbacks );
|
||||
return this;
|
||||
},
|
||||
fail: failDeferred.done,
|
||||
rejectWith: failDeferred.resolveWith,
|
||||
reject: failDeferred.resolve,
|
||||
isRejected: failDeferred.isResolved,
|
||||
// Get a promise for this deferred
|
||||
// If obj is provided, the promise aspect is added to the object
|
||||
promise: function( obj ) {
|
||||
if ( obj == null ) {
|
||||
if ( promise ) {
|
||||
return promise;
|
||||
}
|
||||
promise = obj = {};
|
||||
}
|
||||
var i = promiseMethods.length;
|
||||
while( i-- ) {
|
||||
obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ];
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
} );
|
||||
// Make sure only one callback list will be used
|
||||
deferred.done( failDeferred.cancel ).fail( deferred.cancel );
|
||||
// Unexpose cancel
|
||||
delete deferred.cancel;
|
||||
// Call given func if any
|
||||
if ( func ) {
|
||||
func.call( deferred, deferred );
|
||||
}
|
||||
return deferred;
|
||||
},
|
||||
|
||||
// Deferred helper
|
||||
when: function( object ) {
|
||||
var lastIndex = arguments.length,
|
||||
deferred = lastIndex <= 1 && object && jQuery.isFunction( object.promise ) ?
|
||||
object :
|
||||
jQuery.Deferred(),
|
||||
promise = deferred.promise();
|
||||
|
||||
if ( lastIndex > 1 ) {
|
||||
var array = slice.call( arguments, 0 ),
|
||||
count = lastIndex,
|
||||
iCallback = function( index ) {
|
||||
return function( value ) {
|
||||
array[ index ] = arguments.length > 1 ? slice.call( arguments, 0 ) : value;
|
||||
if ( !( --count ) ) {
|
||||
deferred.resolveWith( promise, array );
|
||||
}
|
||||
};
|
||||
};
|
||||
while( ( lastIndex-- ) ) {
|
||||
object = array[ lastIndex ];
|
||||
if ( object && jQuery.isFunction( object.promise ) ) {
|
||||
object.promise().then( iCallback(lastIndex), deferred.reject );
|
||||
} else {
|
||||
--count;
|
||||
}
|
||||
}
|
||||
if ( !count ) {
|
||||
deferred.resolveWith( promise, array );
|
||||
}
|
||||
} else if ( deferred !== object ) {
|
||||
deferred.resolve( object );
|
||||
}
|
||||
return promise;
|
||||
},
|
||||
|
||||
// Use of jQuery.browser is frowned upon.
|
||||
// More details: http://docs.jquery.com/Utilities/jQuery.browser
|
||||
uaMatch: function( ua ) {
|
||||
|
@ -1014,9 +843,6 @@ jQuery.extend({
|
|||
browser: {}
|
||||
});
|
||||
|
||||
// Create readyList deferred
|
||||
readyList = jQuery._Deferred();
|
||||
|
||||
// Populate the class2type map
|
||||
jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
|
||||
class2type[ "[object " + name + "]" ] = name.toLowerCase();
|
||||
|
@ -1090,6 +916,178 @@ return jQuery;
|
|||
})();
|
||||
|
||||
|
||||
var // Promise methods
|
||||
promiseMethods = "then done fail isResolved isRejected promise".split( " " ),
|
||||
// Static reference to slice
|
||||
sliceDeferred = [].slice;
|
||||
|
||||
jQuery.extend({
|
||||
// Create a simple deferred (one callbacks list)
|
||||
_Deferred: function() {
|
||||
var // callbacks list
|
||||
callbacks = [],
|
||||
// stored [ context , args ]
|
||||
fired,
|
||||
// to avoid firing when already doing so
|
||||
firing,
|
||||
// flag to know if the deferred has been cancelled
|
||||
cancelled,
|
||||
// the deferred itself
|
||||
deferred = {
|
||||
|
||||
// done( f1, f2, ...)
|
||||
done: function() {
|
||||
if ( !cancelled ) {
|
||||
var args = arguments,
|
||||
i,
|
||||
length,
|
||||
elem,
|
||||
type,
|
||||
_fired;
|
||||
if ( fired ) {
|
||||
_fired = fired;
|
||||
fired = 0;
|
||||
}
|
||||
for ( i = 0, length = args.length; i < length; i++ ) {
|
||||
elem = args[ i ];
|
||||
type = jQuery.type( elem );
|
||||
if ( type === "array" ) {
|
||||
deferred.done.apply( deferred, elem );
|
||||
} else if ( type === "function" ) {
|
||||
callbacks.push( elem );
|
||||
}
|
||||
}
|
||||
if ( _fired ) {
|
||||
deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// resolve with given context and args
|
||||
resolveWith: function( context, args ) {
|
||||
if ( !cancelled && !fired && !firing ) {
|
||||
// make sure args are available (#8421)
|
||||
args = args || [];
|
||||
firing = 1;
|
||||
try {
|
||||
while( callbacks[ 0 ] ) {
|
||||
callbacks.shift().apply( context, args );
|
||||
}
|
||||
}
|
||||
finally {
|
||||
fired = [ context, args ];
|
||||
firing = 0;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// resolve with this as context and given arguments
|
||||
resolve: function() {
|
||||
deferred.resolveWith( this, arguments );
|
||||
return this;
|
||||
},
|
||||
|
||||
// Has this deferred been resolved?
|
||||
isResolved: function() {
|
||||
return !!( firing || fired );
|
||||
},
|
||||
|
||||
// Cancel
|
||||
cancel: function() {
|
||||
cancelled = 1;
|
||||
callbacks = [];
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
return deferred;
|
||||
},
|
||||
|
||||
// Full fledged deferred (two callbacks list)
|
||||
Deferred: function( func ) {
|
||||
var deferred = jQuery._Deferred(),
|
||||
failDeferred = jQuery._Deferred(),
|
||||
promise;
|
||||
// Add errorDeferred methods, then and promise
|
||||
jQuery.extend( deferred, {
|
||||
then: function( doneCallbacks, failCallbacks ) {
|
||||
deferred.done( doneCallbacks ).fail( failCallbacks );
|
||||
return this;
|
||||
},
|
||||
fail: failDeferred.done,
|
||||
rejectWith: failDeferred.resolveWith,
|
||||
reject: failDeferred.resolve,
|
||||
isRejected: failDeferred.isResolved,
|
||||
// Get a promise for this deferred
|
||||
// If obj is provided, the promise aspect is added to the object
|
||||
promise: function( obj ) {
|
||||
if ( obj == null ) {
|
||||
if ( promise ) {
|
||||
return promise;
|
||||
}
|
||||
promise = obj = {};
|
||||
}
|
||||
var i = promiseMethods.length;
|
||||
while( i-- ) {
|
||||
obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ];
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
} );
|
||||
// Make sure only one callback list will be used
|
||||
deferred.done( failDeferred.cancel ).fail( deferred.cancel );
|
||||
// Unexpose cancel
|
||||
delete deferred.cancel;
|
||||
// Call given func if any
|
||||
if ( func ) {
|
||||
func.call( deferred, deferred );
|
||||
}
|
||||
return deferred;
|
||||
},
|
||||
|
||||
// Deferred helper
|
||||
when: function( firstParam ) {
|
||||
var args = arguments,
|
||||
i = 0,
|
||||
length = args.length,
|
||||
count = length,
|
||||
deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
|
||||
firstParam :
|
||||
jQuery.Deferred();
|
||||
function resolveFunc( i ) {
|
||||
return function( value ) {
|
||||
args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
|
||||
if ( !( --count ) ) {
|
||||
// Strange bug in FF4:
|
||||
// Values changed onto the arguments object sometimes end up as undefined values
|
||||
// outside the $.when method. Cloning the object into a fresh array solves the issue
|
||||
deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) );
|
||||
}
|
||||
};
|
||||
}
|
||||
if ( length > 1 ) {
|
||||
for( ; i < length; i++ ) {
|
||||
if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) {
|
||||
args[ i ].promise().then( resolveFunc(i), deferred.reject );
|
||||
} else {
|
||||
--count;
|
||||
}
|
||||
}
|
||||
if ( !count ) {
|
||||
deferred.resolveWith( deferred, args );
|
||||
}
|
||||
} else if ( deferred !== firstParam ) {
|
||||
deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
|
||||
}
|
||||
return deferred.promise();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
(function() {
|
||||
|
||||
jQuery.support = {};
|
||||
|
@ -1157,7 +1155,8 @@ return jQuery;
|
|||
boxModel: null,
|
||||
inlineBlockNeedsLayout: false,
|
||||
shrinkWrapBlocks: false,
|
||||
reliableHiddenOffsets: true
|
||||
reliableHiddenOffsets: true,
|
||||
reliableMarginRight: true
|
||||
};
|
||||
|
||||
input.checked = true;
|
||||
|
@ -1175,15 +1174,15 @@ return jQuery;
|
|||
script = document.createElement("script"),
|
||||
id = "script" + jQuery.now();
|
||||
|
||||
// Make sure that the execution of code works by injecting a script
|
||||
// tag with appendChild/createTextNode
|
||||
// (IE doesn't support this, fails, and uses .text instead)
|
||||
try {
|
||||
script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
|
||||
} catch(e) {}
|
||||
|
||||
root.insertBefore( script, root.firstChild );
|
||||
|
||||
// Make sure that the execution of code works by injecting a script
|
||||
// tag with appendChild/createTextNode
|
||||
// (IE doesn't support this, fails, and uses .text instead)
|
||||
if ( window[ id ] ) {
|
||||
_scriptEval = true;
|
||||
delete window[ id ];
|
||||
|
@ -1192,8 +1191,6 @@ return jQuery;
|
|||
}
|
||||
|
||||
root.removeChild( script );
|
||||
// release memory in IE
|
||||
root = script = id = null;
|
||||
}
|
||||
|
||||
return _scriptEval;
|
||||
|
@ -1278,6 +1275,17 @@ return jQuery;
|
|||
jQuery.support.reliableHiddenOffsets = jQuery.support.reliableHiddenOffsets && tds[0].offsetHeight === 0;
|
||||
div.innerHTML = "";
|
||||
|
||||
// Check if div with explicit width and no margin-right incorrectly
|
||||
// gets computed margin-right based on width of container. For more
|
||||
// info see bug #3333
|
||||
// Fails in WebKit before Feb 2011 nightlies
|
||||
// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
|
||||
if ( document.defaultView && document.defaultView.getComputedStyle ) {
|
||||
div.style.width = "1px";
|
||||
div.style.marginRight = "0";
|
||||
jQuery.support.reliableMarginRight = ( parseInt(document.defaultView.getComputedStyle(div, null).marginRight, 10) || 0 ) === 0;
|
||||
}
|
||||
|
||||
body.removeChild( div ).style.display = "none";
|
||||
div = tds = null;
|
||||
});
|
||||
|
@ -1301,8 +1309,6 @@ return jQuery;
|
|||
el.setAttribute(eventName, "return;");
|
||||
isSupported = typeof el[eventName] === "function";
|
||||
}
|
||||
el = null;
|
||||
|
||||
return isSupported;
|
||||
};
|
||||
|
||||
|
@ -2194,10 +2200,10 @@ jQuery.event = {
|
|||
}
|
||||
|
||||
if ( !eventHandle ) {
|
||||
elemData.handle = eventHandle = function() {
|
||||
elemData.handle = eventHandle = function( e ) {
|
||||
// Handle the second event of a trigger and when
|
||||
// an event is called after a page has unloaded
|
||||
return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
|
||||
return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
|
||||
jQuery.event.handle.apply( eventHandle.elem, arguments ) :
|
||||
undefined;
|
||||
};
|
||||
|
@ -2504,7 +2510,7 @@ jQuery.event = {
|
|||
target[ "on" + targetType ] = null;
|
||||
}
|
||||
|
||||
jQuery.event.triggered = true;
|
||||
jQuery.event.triggered = event.type;
|
||||
target[ targetType ]();
|
||||
}
|
||||
|
||||
|
@ -2515,7 +2521,7 @@ jQuery.event = {
|
|||
target[ "on" + targetType ] = old;
|
||||
}
|
||||
|
||||
jQuery.event.triggered = false;
|
||||
jQuery.event.triggered = undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -2785,7 +2791,7 @@ var withinElement = function( event ) {
|
|||
|
||||
// Chrome does something similar, the parentNode property
|
||||
// can be accessed but is null.
|
||||
if ( parent !== document && !parent.parentNode ) {
|
||||
if ( parent && parent !== document && !parent.parentNode ) {
|
||||
return;
|
||||
}
|
||||
// Traverse up the tree
|
||||
|
@ -2992,19 +2998,33 @@ function trigger( type, elem, args ) {
|
|||
// Create "bubbling" focus and blur events
|
||||
if ( document.addEventListener ) {
|
||||
jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
|
||||
|
||||
// Attach a single capturing handler while someone wants focusin/focusout
|
||||
var attaches = 0;
|
||||
|
||||
jQuery.event.special[ fix ] = {
|
||||
setup: function() {
|
||||
this.addEventListener( orig, handler, true );
|
||||
if ( attaches++ === 0 ) {
|
||||
document.addEventListener( orig, handler, true );
|
||||
}
|
||||
},
|
||||
teardown: function() {
|
||||
this.removeEventListener( orig, handler, true );
|
||||
if ( --attaches === 0 ) {
|
||||
document.removeEventListener( orig, handler, true );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function handler( e ) {
|
||||
e = jQuery.event.fix( e );
|
||||
function handler( donor ) {
|
||||
// Donor event is always a native one; fix it and switch its type.
|
||||
// Let focusin/out handler cancel the donor focus/blur event.
|
||||
var e = jQuery.event.fix( donor );
|
||||
e.type = fix;
|
||||
return jQuery.event.handle.call( this, e );
|
||||
e.originalEvent = {};
|
||||
jQuery.event.trigger( e, null, e.target );
|
||||
if ( e.isDefaultPrevented() ) {
|
||||
donor.preventDefault();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -3918,10 +3938,12 @@ var Expr = Sizzle.selectors = {
|
|||
},
|
||||
|
||||
text: function( elem ) {
|
||||
var attr = elem.getAttribute( "type" ), type = elem.type;
|
||||
// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
|
||||
// use getAttribute instead to test this case
|
||||
return "text" === elem.getAttribute( 'type' );
|
||||
return "text" === type && ( attr === type || attr === null );
|
||||
},
|
||||
|
||||
radio: function( elem ) {
|
||||
return "radio" === elem.type;
|
||||
},
|
||||
|
@ -4496,19 +4518,23 @@ if ( document.querySelectorAll ) {
|
|||
|
||||
(function(){
|
||||
var html = document.documentElement,
|
||||
matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector,
|
||||
pseudoWorks = false;
|
||||
|
||||
try {
|
||||
// This should fail with an exception
|
||||
// Gecko does not error, returns false instead
|
||||
matches.call( document.documentElement, "[test!='']:sizzle" );
|
||||
|
||||
} catch( pseudoError ) {
|
||||
pseudoWorks = true;
|
||||
}
|
||||
matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
|
||||
|
||||
if ( matches ) {
|
||||
// Check to see if it's possible to do matchesSelector
|
||||
// on a disconnected node (IE 9 fails this)
|
||||
var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
|
||||
pseudoWorks = false;
|
||||
|
||||
try {
|
||||
// This should fail with an exception
|
||||
// Gecko does not error, returns false instead
|
||||
matches.call( document.documentElement, "[test!='']:sizzle" );
|
||||
|
||||
} catch( pseudoError ) {
|
||||
pseudoWorks = true;
|
||||
}
|
||||
|
||||
Sizzle.matchesSelector = function( node, expr ) {
|
||||
// Make sure that attribute selectors are quoted
|
||||
expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
|
||||
|
@ -4516,7 +4542,15 @@ if ( document.querySelectorAll ) {
|
|||
if ( !Sizzle.isXML( node ) ) {
|
||||
try {
|
||||
if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
|
||||
return matches.call( node, expr );
|
||||
var ret = matches.call( node, expr );
|
||||
|
||||
// IE 9's matchesSelector returns false on disconnected nodes
|
||||
if ( ret || !disconnectedMatch ||
|
||||
// As well, disconnected nodes are said to be in a document
|
||||
// fragment in IE 9, so check for that
|
||||
node.document && node.document.nodeType !== 11 ) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
@ -5260,7 +5294,9 @@ jQuery.fn.extend({
|
|||
}
|
||||
});
|
||||
} else {
|
||||
return this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value );
|
||||
return this.length ?
|
||||
this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
|
||||
this;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -5707,7 +5743,8 @@ function evalScript( i, elem ) {
|
|||
var ralpha = /alpha\([^)]*\)/i,
|
||||
ropacity = /opacity=([^)]*)/,
|
||||
rdashAlpha = /-([a-z])/ig,
|
||||
rupper = /([A-Z])/g,
|
||||
// fixed for IE9, see #8346
|
||||
rupper = /([A-Z]|^ms)/g,
|
||||
rnumpx = /^-?\d+(?:px)?$/i,
|
||||
rnum = /^-?\d/,
|
||||
|
||||
|
@ -5944,6 +5981,28 @@ if ( !jQuery.support.opacity ) {
|
|||
};
|
||||
}
|
||||
|
||||
jQuery(function() {
|
||||
// This hook cannot be added until DOM ready because the support test
|
||||
// for it is not run until after DOM ready
|
||||
if ( !jQuery.support.reliableMarginRight ) {
|
||||
jQuery.cssHooks.marginRight = {
|
||||
get: function( elem, computed ) {
|
||||
// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
|
||||
// Work around by temporarily setting element display to inline-block
|
||||
var ret;
|
||||
jQuery.swap( elem, { "display": "inline-block" }, function() {
|
||||
if ( computed ) {
|
||||
ret = curCSS( elem, "margin-right", "marginRight" );
|
||||
} else {
|
||||
ret = elem.style.marginRight;
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
if ( document.defaultView && document.defaultView.getComputedStyle ) {
|
||||
getComputedStyle = function( elem, newName, name ) {
|
||||
var ret, defaultView, computedStyle;
|
||||
|
@ -6048,7 +6107,7 @@ var r20 = /%20/g,
|
|||
rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
|
||||
rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
|
||||
// #7653, #8125, #8152: local protocol detection
|
||||
rlocalProtocol = /(?:^file|^widget|\-extension):$/,
|
||||
rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|widget):$/,
|
||||
rnoContent = /^(?:GET|HEAD)$/,
|
||||
rprotocol = /^\/\//,
|
||||
rquery = /\?/,
|
||||
|
@ -6060,7 +6119,7 @@ var r20 = /%20/g,
|
|||
rucHeadersFunc = function( _, $1, $2 ) {
|
||||
return $1 + $2.toUpperCase();
|
||||
},
|
||||
rurl = /^([\w\+\.\-]+:)\/\/([^\/?#:]*)(?::(\d+))?/,
|
||||
rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
|
||||
|
||||
// Keep a copy of the old load method
|
||||
_load = jQuery.fn.load,
|
||||
|
@ -6102,7 +6161,7 @@ try {
|
|||
}
|
||||
|
||||
// Segment location into parts
|
||||
ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() );
|
||||
ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
|
||||
|
||||
// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
|
||||
function addToPrefiltersOrTransports( structure ) {
|
||||
|
@ -6360,7 +6419,6 @@ jQuery.extend({
|
|||
cache: null,
|
||||
traditional: false,
|
||||
headers: {},
|
||||
crossDomain: null,
|
||||
*/
|
||||
|
||||
accepts: {
|
||||
|
@ -6645,7 +6703,7 @@ jQuery.extend({
|
|||
s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
|
||||
|
||||
// Determine if a cross-domain request is in order
|
||||
if ( !s.crossDomain ) {
|
||||
if ( s.crossDomain == null ) {
|
||||
parts = rurl.exec( s.url.toLowerCase() );
|
||||
s.crossDomain = !!( parts &&
|
||||
( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
|
||||
|
@ -7024,7 +7082,7 @@ function ajaxConvert( s, response ) {
|
|||
|
||||
|
||||
var jsc = jQuery.now(),
|
||||
jsre = /(\=)\?(&|$)|()\?\?()/i;
|
||||
jsre = /(\=)\?(&|$)|\?\?/i;
|
||||
|
||||
// Default jsonp settings
|
||||
jQuery.ajaxSetup({
|
||||
|
@ -7285,11 +7343,12 @@ if ( jQuery.support.ajax ) {
|
|||
xhr.overrideMimeType( s.mimeType );
|
||||
}
|
||||
|
||||
// Requested-With header
|
||||
// Not set for crossDomain requests with no content
|
||||
// (see why at http://trac.dojotoolkit.org/ticket/9486)
|
||||
// Won't change header if already provided
|
||||
if ( !( s.crossDomain && !s.hasContent ) && !headers["X-Requested-With"] ) {
|
||||
// X-Requested-With header
|
||||
// For cross-domain requests, seeing as conditions for a preflight are
|
||||
// akin to a jigsaw puzzle, we simply never set it to be sure.
|
||||
// (it can always be set on a per-request basis or even using ajaxSetup)
|
||||
// For same-domain requests, won't change header if already provided.
|
||||
if ( !s.crossDomain && !headers["X-Requested-With"] ) {
|
||||
headers[ "X-Requested-With" ] = "XMLHttpRequest";
|
||||
}
|
||||
|
||||
|
@ -7979,8 +8038,8 @@ if ( "getBoundingClientRect" in document.documentElement ) {
|
|||
win = getWindow(doc),
|
||||
clientTop = docElem.clientTop || body.clientTop || 0,
|
||||
clientLeft = docElem.clientLeft || body.clientLeft || 0,
|
||||
scrollTop = (win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop ),
|
||||
scrollLeft = (win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft),
|
||||
scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop,
|
||||
scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
|
||||
top = box.top + scrollTop - clientTop,
|
||||
left = box.left + scrollLeft - clientLeft;
|
||||
|
||||
|
@ -8093,7 +8152,6 @@ jQuery.offset = {
|
|||
this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);
|
||||
|
||||
body.removeChild( container );
|
||||
body = container = innerDiv = checkDiv = table = td = null;
|
||||
jQuery.offset.initialize = jQuery.noop;
|
||||
},
|
||||
|
||||
|
@ -8123,10 +8181,10 @@ jQuery.offset = {
|
|||
curOffset = curElem.offset(),
|
||||
curCSSTop = jQuery.css( elem, "top" ),
|
||||
curCSSLeft = jQuery.css( elem, "left" ),
|
||||
calculatePosition = (position === "absolute" && jQuery.inArray('auto', [curCSSTop, curCSSLeft]) > -1),
|
||||
calculatePosition = (position === "absolute" || position === "fixed") && jQuery.inArray('auto', [curCSSTop, curCSSLeft]) > -1,
|
||||
props = {}, curPosition = {}, curTop, curLeft;
|
||||
|
||||
// need to be able to calculate position if either top or left is auto and position is absolute
|
||||
// need to be able to calculate position if either top or left is auto and position is either absolute or fixed
|
||||
if ( calculatePosition ) {
|
||||
curPosition = curElem.position();
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="http://code.jquery.com/jquery-1.5.1.js"></script>
|
||||
<script src="http://code.jquery.com/jquery-1.5.2.js"></script>
|
||||
<link rel="stylesheet" href="http://code.jquery.com/qunit/git/qunit.css" type="text/css" media="screen"/>
|
||||
<script type="text/javascript" src="http://code.jquery.com/qunit/git/qunit.js"></script>
|
||||
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
// Underscore.strings
|
||||
// (c) 2010 Esa-Matti Suuronen <esa-matti aet suuronen dot org>
|
||||
// Underscore.strings is freely distributable under the terms of the MIT license.
|
||||
// Documentation: http://bitbucket.org/epeli/underscore.strings/
|
||||
// Some code is borrowed from MooTools and Alexandru Marasteanu.
|
||||
|
||||
// Version 1.0
|
||||
|
||||
|
||||
(function(){
|
||||
// ------------------------- Baseline setup ---------------------------------
|
||||
|
||||
// Establish the root object, "window" in the browser, or "global" on the server.
|
||||
var root = this;
|
||||
|
||||
var nativeTrim = String.prototype.trim;
|
||||
|
||||
function str_repeat(i, m) {
|
||||
for (var o = []; m > 0; o[--m] = i);
|
||||
return o.join('');
|
||||
}
|
||||
|
||||
function defaultToWhiteSpace(characters){
|
||||
if (characters) {
|
||||
return _s.escapeRegExp(characters);
|
||||
}
|
||||
return '\\s';
|
||||
}
|
||||
|
||||
var _s;
|
||||
_s = root._s = {
|
||||
|
||||
capitalize : function(str) {
|
||||
return str.charAt(0).toUpperCase() + str.substring(1).toLowerCase();
|
||||
},
|
||||
|
||||
join: function(sep) {
|
||||
// TODO: Could this be faster by converting
|
||||
// arguments to Array and using array.join(sep)?
|
||||
sep = String(sep);
|
||||
var str = "";
|
||||
for (var i=1; i < arguments.length; i += 1) {
|
||||
str += String(arguments[i]);
|
||||
if ( i !== arguments.length-1 ) {
|
||||
str += sep;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
},
|
||||
|
||||
escapeRegExp: function(str){
|
||||
// From MooTools core 1.2.4
|
||||
return str.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
|
||||
},
|
||||
|
||||
reverse: function(str){
|
||||
return Array.prototype.reverse.apply(str.split('')).join('');
|
||||
},
|
||||
|
||||
contains: function(str, needle){
|
||||
return str.indexOf(needle) !== -1;
|
||||
},
|
||||
|
||||
clean: function(str){
|
||||
return _s.strip(str.replace(/\s+/g, ' '));
|
||||
},
|
||||
|
||||
trim: function(str, characters){
|
||||
if (!characters && nativeTrim) {
|
||||
return nativeTrim.call(str);
|
||||
}
|
||||
characters = defaultToWhiteSpace(characters);
|
||||
return str.replace(new RegExp('\^[' + characters + ']+|[' + characters + ']+$', 'g'), '');
|
||||
},
|
||||
|
||||
|
||||
|
||||
ltrim: function(str, characters){
|
||||
characters = defaultToWhiteSpace(characters);
|
||||
return str.replace(new RegExp('\^[' + characters + ']+', 'g'), '');
|
||||
},
|
||||
|
||||
rtrim: function(str, characters){
|
||||
characters = defaultToWhiteSpace(characters);
|
||||
return str.replace(new RegExp('[' + characters + ']+$', 'g'), '');
|
||||
},
|
||||
|
||||
|
||||
startsWith: function(str, starts){
|
||||
return str.length >= starts.length && str.substring(0, starts.length) === starts;
|
||||
},
|
||||
|
||||
|
||||
endsWith: function(str, ends){
|
||||
return str.length >= ends.length && str.substring(str.length - ends.length) === ends;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Credits for this function goes to
|
||||
* http://www.diveintojavascript.com/projects/sprintf-for-javascript
|
||||
*
|
||||
* Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>
|
||||
* All rights reserved.
|
||||
* */
|
||||
sprintf: function(){
|
||||
|
||||
var i = 0, a, f = arguments[i++], o = [], m, p, c, x, s = '';
|
||||
while (f) {
|
||||
if (m = /^[^\x25]+/.exec(f)) {
|
||||
o.push(m[0]);
|
||||
}
|
||||
else if (m = /^\x25{2}/.exec(f)) {
|
||||
o.push('%');
|
||||
}
|
||||
else if (m = /^\x25(?:(\d+)\$)?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(f)) {
|
||||
if (((a = arguments[m[1] || i++]) == null) || (a == undefined)) {
|
||||
throw('Too few arguments.');
|
||||
}
|
||||
if (/[^s]/.test(m[7]) && (typeof(a) != 'number')) {
|
||||
throw('Expecting number but found ' + typeof(a));
|
||||
}
|
||||
switch (m[7]) {
|
||||
case 'b': a = a.toString(2); break;
|
||||
case 'c': a = String.fromCharCode(a); break;
|
||||
case 'd': a = parseInt(a); break;
|
||||
case 'e': a = m[6] ? a.toExponential(m[6]) : a.toExponential(); break;
|
||||
case 'f': a = m[6] ? parseFloat(a).toFixed(m[6]) : parseFloat(a); break;
|
||||
case 'o': a = a.toString(8); break;
|
||||
case 's': a = ((a = String(a)) && m[6] ? a.substring(0, m[6]) : a); break;
|
||||
case 'u': a = Math.abs(a); break;
|
||||
case 'x': a = a.toString(16); break;
|
||||
case 'X': a = a.toString(16).toUpperCase(); break;
|
||||
}
|
||||
a = (/[def]/.test(m[7]) && m[2] && a >= 0 ? '+'+ a : a);
|
||||
c = m[3] ? m[3] == '0' ? '0' : m[3].charAt(1) : ' ';
|
||||
x = m[5] - String(a).length - s.length;
|
||||
p = m[5] ? str_repeat(c, x) : '';
|
||||
o.push(s + (m[4] ? a + p : p + a));
|
||||
}
|
||||
else {
|
||||
throw('Huh ?!');
|
||||
}
|
||||
f = f.substring(m[0].length);
|
||||
}
|
||||
return o.join('');
|
||||
}
|
||||
}
|
||||
|
||||
// Some aliases
|
||||
root._s.strip = _s.trim;
|
||||
root._s.lstrip = _s.ltrim;
|
||||
root._s.rstrip = _s.rtrim;
|
||||
|
||||
|
||||
// Integrate with Underscore.js
|
||||
if (root._) {
|
||||
root._.mixin(root._s);
|
||||
}
|
||||
|
||||
}());
|
|
@ -7,8 +7,9 @@
|
|||
|
||||
<script type="text/javascript" src="/base/static/lib/LABjs/LAB.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/underscore/underscore.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/underscore/underscore.strings.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/qweb/qweb.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/jquery/jquery-1.5.1.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/jquery/jquery-1.5.2.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/jquery.ui/js/jquery-ui-1.8.9.custom.min.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/jquery.ui/js/jquery-ui-timepicker-addon.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/jquery.ui.notify/js/jquery.notify.js"></script>
|
||||
|
|
|
@ -54,6 +54,9 @@ body.openerp {
|
|||
z-index: 1001;
|
||||
display: none;
|
||||
}
|
||||
.openerp .oe_notification * {
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Login */
|
||||
.openerp .login {
|
||||
|
@ -440,6 +443,16 @@ body.openerp {
|
|||
border-radius: 3px;
|
||||
background: white;
|
||||
}
|
||||
.openerp input[type="text"], .openerp input[type="password"], .openerp select, .openerp .button {
|
||||
height: 22px;
|
||||
}
|
||||
.openerp .button {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.openerp .button span {
|
||||
position: relative;
|
||||
top: -3px;
|
||||
}
|
||||
.openerp input.field_date, .openerp input.field_datetime {
|
||||
background: #fff url('../img/ui/field_calendar.png') no-repeat right center;
|
||||
background-origin: content-box;
|
||||
|
|
|
@ -217,7 +217,7 @@ openerp.base.BasicController = Class.extend( /** @lends openerp.base.BasicContro
|
|||
}
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.Session = openerp.base.BasicController.extend( /** @lends openerp.base.Session# */{
|
||||
|
@ -468,9 +468,24 @@ openerp.base.Controller = openerp.base.BasicController.extend( /** @lends opener
|
|||
});
|
||||
|
||||
openerp.base.CrashManager = openerp.base.Controller.extend({
|
||||
// Controller to display exception and stacktrace and eventually report error trought maitenance contract
|
||||
// if should hook on Session.on_rpc_error: function(error) {
|
||||
// and display OPW etc...
|
||||
init: function(session, element_id) {
|
||||
this._super(session, element_id);
|
||||
this.session.on_rpc_error.add(this.on_rpc_error);
|
||||
},
|
||||
on_rpc_error: function(error) {
|
||||
var msg = error.message + "\n" + error.data.debug;
|
||||
this.display_error(msg);
|
||||
},
|
||||
display_error: function(message) {
|
||||
$('<pre></pre>').text(message).dialog({
|
||||
modal: true,
|
||||
buttons: {
|
||||
OK: function() {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.Database = openerp.base.Controller.extend({
|
||||
|
@ -503,8 +518,14 @@ openerp.base.Notification = openerp.base.Controller.extend({
|
|||
speed: 500
|
||||
});
|
||||
},
|
||||
add: function(title, text) {
|
||||
this.$element.notify("create", {
|
||||
'default': function(title, text) {
|
||||
this.$element.notify('create', {
|
||||
title: title,
|
||||
text: text
|
||||
});
|
||||
},
|
||||
alert: function(title, text) {
|
||||
this.$element.notify('create', 'oe_notification_alert', {
|
||||
title: title,
|
||||
text: text
|
||||
});
|
||||
|
@ -671,6 +692,7 @@ openerp.base.WebClient = openerp.base.Controller.extend({
|
|||
|
||||
this.session = new openerp.base.Session("oe_errors");
|
||||
this.loading = new openerp.base.Loading(this.session, "oe_loading");
|
||||
this.crashmanager = new openerp.base.CrashManager(this.session);
|
||||
|
||||
// Do you autorize this ?
|
||||
openerp.base.Controller.prototype.notification = new openerp.base.Notification(this.session, "oe_notification");
|
||||
|
@ -690,7 +712,7 @@ openerp.base.WebClient = openerp.base.Controller.extend({
|
|||
this.header.start();
|
||||
this.login.start();
|
||||
this.menu.start();
|
||||
this.notification.add("OpenERP Client", "The openerp client has been initialized.");
|
||||
this.notification['default']("OpenERP Client", "The openerp client has been initialized.");
|
||||
},
|
||||
on_logged: function() {
|
||||
this.action = new openerp.base.ActionManager(this.session, "oe_app");
|
||||
|
|
|
@ -29,35 +29,119 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
|
|||
init: function(session, model) {
|
||||
this._super(session);
|
||||
this.model = model;
|
||||
|
||||
this.ids = [];
|
||||
this.offset
|
||||
this.context = {};
|
||||
this.index = 0;
|
||||
this.count = 0;
|
||||
|
||||
this.sort = [];
|
||||
this.domain = [];
|
||||
this.context = {};
|
||||
},
|
||||
start: function() {
|
||||
},
|
||||
|
||||
previous: function () {
|
||||
this.index -= 1;
|
||||
if (this.index < 0) {
|
||||
this.index = this.count - 1;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
next: function () {
|
||||
this.index += 1;
|
||||
if (this.index >= this.count) {
|
||||
this.index = 0;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Fetch all the records selected by this DataSet, based on its domain
|
||||
* and context.
|
||||
*
|
||||
* Fires the on_ids event.
|
||||
*
|
||||
* TODO: return deferred
|
||||
* Read records.
|
||||
*/
|
||||
read_ids: function (ids, fields, callback) {
|
||||
var self = this;
|
||||
this.rpc('/base/dataset/get', {
|
||||
model: this.model,
|
||||
ids: ids,
|
||||
fields: fields
|
||||
}, callback);
|
||||
},
|
||||
/**
|
||||
* Read a slice of the records represented by this DataSet, based on its
|
||||
* domain and context.
|
||||
*
|
||||
* @param {Number} [offset=0] The index from which selected records should be returned
|
||||
* @param {Number} [limit=null] The maximum number of records to return
|
||||
* @returns itself
|
||||
*/
|
||||
fetch: function (fields, offset, limit, callback) {
|
||||
read_slice: function (fields, offset, limit, callback) {
|
||||
},
|
||||
/**
|
||||
* Read the indexed record.
|
||||
*/
|
||||
read_index: function (fields, callback) {
|
||||
if (_.isEmpty(this.ids)) {
|
||||
callback([]);
|
||||
} else {
|
||||
fields = fields || false;
|
||||
this.read_ids([this.ids[this.index]], fields, function(records) {
|
||||
callback(records[0]);
|
||||
});
|
||||
}
|
||||
},
|
||||
default_get: function() {
|
||||
},
|
||||
create: function() {
|
||||
},
|
||||
write: function (id, data, callback) {
|
||||
this.rpc('/base/dataset/save', {
|
||||
model: this.model,
|
||||
id: id,
|
||||
data: data,
|
||||
context: this.context
|
||||
}, callback);
|
||||
},
|
||||
unlink: function() {
|
||||
},
|
||||
call: function (method, ids, args, callback) {
|
||||
ids = ids || [];
|
||||
args = args || [];
|
||||
this.rpc('/base/dataset/call', {
|
||||
model: this.model,
|
||||
method: method,
|
||||
ids: ids,
|
||||
args: args
|
||||
}, callback);
|
||||
},
|
||||
});
|
||||
|
||||
openerp.base.DataSetStatic = openerp.base.DataSet.extend({
|
||||
init: function(session, model) {
|
||||
this._super(session, model);
|
||||
// all local records
|
||||
this.ids = [];
|
||||
this.count = 0;
|
||||
},
|
||||
read_slice: function (fields, offset, limit, callback) {
|
||||
this.read_ids(this.ids.slice(offset, offset + limit));
|
||||
},
|
||||
});
|
||||
|
||||
openerp.base.DataSetSearch = openerp.base.DataSet.extend({
|
||||
init: function(session, model) {
|
||||
this._super(session, model);
|
||||
this.domain = [];
|
||||
this.sort = [];
|
||||
this.offset = 0;
|
||||
// subset records[offset:offset+limit]
|
||||
// is it necessary ?
|
||||
this.ids = [];
|
||||
},
|
||||
read_slice: function (fields, offset, limit, callback) {
|
||||
var self = this;
|
||||
offset = offset || 0;
|
||||
this.rpc('/base/dataset/find', {
|
||||
// cached search, not sure it's a good idea
|
||||
if(this.offset <= offset) {
|
||||
var start = offset - this.offset;
|
||||
if(this.ids.length - start >= limit) {
|
||||
// TODO: check if this could work do only read if possible
|
||||
// return read_ids(ids.slice(start,start+limit),fields,callback)
|
||||
}
|
||||
}
|
||||
this.rpc('/base/dataset/search_read', {
|
||||
model: this.model,
|
||||
fields: fields,
|
||||
domain: this.domain,
|
||||
|
@ -74,55 +158,6 @@ openerp.base.DataSet = openerp.base.Controller.extend( /** @lends openerp.base.
|
|||
callback(records);
|
||||
});
|
||||
},
|
||||
fetch_ids: function (ids, fields, callback) {
|
||||
var self = this;
|
||||
this.rpc('/base/dataset/get', {
|
||||
model: this.model,
|
||||
ids: ids,
|
||||
fields: fields
|
||||
}, callback);
|
||||
},
|
||||
fetch_index: function (fields, callback) {
|
||||
if (_.isEmpty(this.ids)) {
|
||||
callback([]);
|
||||
} else {
|
||||
fields = fields || false;
|
||||
this.fetch_ids([this.ids[this.index]], fields, function(records) {
|
||||
callback(records[0]);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
write: function (id, data, callback) {
|
||||
this.rpc('/base/datarecord/save', {
|
||||
model: this.model,
|
||||
id: id,
|
||||
data: data
|
||||
}, callback);
|
||||
},
|
||||
/**
|
||||
* Activates the previous id in the active sequence. If there is no previous id, wraps around to the last one
|
||||
* @returns itself
|
||||
*/
|
||||
previous: function () {
|
||||
this.index -= 1;
|
||||
if (this.index < 0) {
|
||||
this.index = this.ids.length - 1;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Activates the next id in the active sequence. If there is no next id, wraps around to the first one
|
||||
* @returns itself
|
||||
*/
|
||||
next: function () {
|
||||
this.index += 1;
|
||||
if (this.index >= this.ids.length) {
|
||||
this.index = 0;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
|
|
@ -57,6 +57,15 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base
|
|||
this.view_manager.sidebar.set_toolbar(data.fields_view.toolbar);
|
||||
}
|
||||
},
|
||||
do_show: function () {
|
||||
// this should not append as start return a deferred resolved when fields_view is known
|
||||
if(this.fields_view && this.fields_view.fields)
|
||||
this.dataset.read_index(_.keys(this.fields_view.fields), this.on_record_loaded);
|
||||
this.$element.show();
|
||||
},
|
||||
do_hide: function () {
|
||||
this.$element.hide();
|
||||
},
|
||||
on_record_loaded: function(record) {
|
||||
if (record) {
|
||||
this.datarecord = record;
|
||||
|
@ -76,14 +85,88 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base
|
|||
w.process_attrs();
|
||||
w.update_dom();
|
||||
}
|
||||
if (widget) {
|
||||
// TODO: check if and trigger
|
||||
// if (onchange for this field) {
|
||||
// this.ready = false;
|
||||
// rpc - process.callback ( this.ready = true; )
|
||||
// }
|
||||
if (widget && widget.node.attrs.on_change) {
|
||||
this.do_onchange(widget);
|
||||
}
|
||||
},
|
||||
on_pager_action: function(action) {
|
||||
switch (action) {
|
||||
case 'first':
|
||||
this.dataset.index = 0;
|
||||
break;
|
||||
case 'previous':
|
||||
this.dataset.previous();
|
||||
break;
|
||||
case 'next':
|
||||
this.dataset.next();
|
||||
break;
|
||||
case 'last':
|
||||
this.dataset.index = this.dataset.ids.length - 1;
|
||||
break;
|
||||
}
|
||||
this.dataset.read_index(_.keys(this.fields_view.fields), this.on_record_loaded);
|
||||
},
|
||||
do_update_pager: function() {
|
||||
var $pager = this.$element.find('div.oe_form_pager');
|
||||
$pager.find("button[data-pager-action='first'], button[data-pager-action='previous']").attr('disabled', this.dataset.index == 0);
|
||||
$pager.find("button[data-pager-action='next'], button[data-pager-action='last']").attr('disabled', this.dataset.index == this.dataset.ids.length - 1);
|
||||
this.$element.find('span.oe_pager_index').html(this.dataset.index + 1);
|
||||
this.$element.find('span.oe_pager_count').html(this.dataset.count);
|
||||
},
|
||||
do_onchange: function(widget) {
|
||||
var self = this;
|
||||
this.ready = false;
|
||||
var onchange = _.trim(widget.node.attrs.on_change);
|
||||
var call = onchange.match(/^\s?(.*?)\((.*?)\)\s?$/);
|
||||
if (call) {
|
||||
var method = call[1], args = [];
|
||||
_.each(call[2].split(','), function(a) {
|
||||
var field = _.trim(a);
|
||||
if (self.fields[field]) {
|
||||
args.push(self.fields[field].value);
|
||||
} else {
|
||||
args.push(false);
|
||||
this.log("warning : on_change can't find field " + field, onchange);
|
||||
}
|
||||
});
|
||||
this.dataset.call(method, [this.datarecord.id], args, this.on_processed_onchange);
|
||||
} else {
|
||||
this.log("Wrong on_change format", on_change);
|
||||
}
|
||||
},
|
||||
on_processed_onchange: function(response) {
|
||||
console.log("onchange result :", response);
|
||||
var result = response.result;
|
||||
if (result.value) {
|
||||
for (var f in result.value) {
|
||||
var field = this.fields[f];
|
||||
if (field) {
|
||||
var value = result.value[f];
|
||||
if (field.value != value) {
|
||||
field.set_value(value);
|
||||
// TODO: Recursive on_change
|
||||
// this.on_form_changed(field);
|
||||
}
|
||||
} else {
|
||||
this.log("warning : on_processed_onchange can't find field " + field, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result.warning) {
|
||||
$(QWeb.render("DialogWarning", result.warning)).dialog({
|
||||
modal: true,
|
||||
buttons: {
|
||||
Ok: function() {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (result.domain) {
|
||||
// Will be removed ?
|
||||
}
|
||||
this.ready = true;
|
||||
},
|
||||
do_save: function() {
|
||||
if (!this.ready) {
|
||||
return false;
|
||||
|
@ -110,50 +193,26 @@ openerp.base.FormView = openerp.base.Controller.extend( /** @lends openerp.base
|
|||
this.switch_readonly();
|
||||
}
|
||||
},
|
||||
do_show: function () {
|
||||
this.dataset.fetch_index(this.fields_view.fields, this.on_record_loaded);
|
||||
this.$element.show();
|
||||
},
|
||||
do_hide: function () {
|
||||
this.$element.hide();
|
||||
},
|
||||
do_update_pager: function() {
|
||||
var $pager = this.$element.find('div.oe_form_pager');
|
||||
$pager.find("button[data-pager-action='first'], button[data-pager-action='previous']").attr('disabled', this.dataset.index == 0);
|
||||
$pager.find("button[data-pager-action='next'], button[data-pager-action='last']").attr('disabled', this.dataset.index == this.dataset.ids.length - 1);
|
||||
this.$element.find('span.oe_pager_index').html(this.dataset.index + 1);
|
||||
this.$element.find('span.oe_pager_count').html(this.dataset.count);
|
||||
},
|
||||
on_pager_action: function(action) {
|
||||
switch (action) {
|
||||
case 'first':
|
||||
this.dataset.index = 0;
|
||||
break;
|
||||
case 'previous':
|
||||
this.dataset.previous();
|
||||
break;
|
||||
case 'next':
|
||||
this.dataset.next();
|
||||
break;
|
||||
case 'last':
|
||||
this.dataset.index = this.dataset.ids.length - 1;
|
||||
break;
|
||||
}
|
||||
this.dataset.fetch_index(this.fields_view.fields, this.on_record_loaded);
|
||||
},
|
||||
switch_readonly: function() {
|
||||
},
|
||||
switch_editable: function() {
|
||||
},
|
||||
on_invalid: function() {
|
||||
console.info("Form invalid");
|
||||
var msg = "<ul>";
|
||||
_.each(this.fields, function(f) {
|
||||
if (f.invalid) {
|
||||
msg += "<li>" + f.string + "</li>";
|
||||
}
|
||||
});
|
||||
msg += "</ul>";
|
||||
this.notification.alert("The following fields are invalid :", msg);
|
||||
},
|
||||
on_saved: function(r) {
|
||||
if (!r.result) {
|
||||
this.log("Record was not saved");
|
||||
} else {
|
||||
// Check response for exceptions, display error
|
||||
this.notification.add("Record saved", "The record #" + this.datarecord.id + " has been saved.");
|
||||
this.notification['default']("Record saved", "The record #" + this.datarecord.id + " has been saved.");
|
||||
}
|
||||
},
|
||||
do_search: function (domains, contexts, groupbys) {
|
||||
|
@ -403,6 +462,7 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({
|
|||
},
|
||||
set_value: function(value) {
|
||||
this.value = value;
|
||||
this.invalid = false;
|
||||
},
|
||||
get_value: function() {
|
||||
return this.value;
|
||||
|
@ -414,7 +474,6 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({
|
|||
this.$element.toggleClass('invalid', this.invalid);
|
||||
},
|
||||
on_ui_change: function() {
|
||||
this.view.on_form_changed(this);
|
||||
this.touched = true;
|
||||
}
|
||||
});
|
||||
|
@ -438,9 +497,10 @@ openerp.base.form.FieldChar = openerp.base.form.Field.extend({
|
|||
this.$element.find('input').attr('disabled', this.readonly);
|
||||
},
|
||||
on_ui_change: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.value = this.$element.find('input').val();
|
||||
this.invalid = this.required && this.value == "";
|
||||
this._super.apply(this, arguments);
|
||||
this.view.on_form_changed(this);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -457,9 +517,10 @@ openerp.base.form.FieldFloat = openerp.base.form.FieldChar.extend({
|
|||
this.$element.find('input').val(value);
|
||||
},
|
||||
on_ui_change: function() {
|
||||
this.value = parseFloat(this.$element.find('input').val()); // TODO: do it well
|
||||
this.invalid = this.required && this.value == "";
|
||||
this._super.apply(this, arguments);
|
||||
this.value = this.$element.find('input').val().replace(/,/g, '.');
|
||||
this.invalid = (this.required && this.value == "") || !this.value.match(/^\d+(\.\d+)?$/) ;
|
||||
this.view.on_form_changed(this);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -480,9 +541,10 @@ openerp.base.form.FieldDate = openerp.base.form.FieldChar.extend({
|
|||
this.$element.find('input').val(show_value);
|
||||
},
|
||||
on_ui_change: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.value = this.$element.find('input').val();
|
||||
this.invalid = this.required && this.value == "";
|
||||
this._super.apply(this, arguments);
|
||||
this.view.on_form_changed(this);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -504,9 +566,10 @@ openerp.base.form.FieldDatetime = openerp.base.form.FieldChar.extend({
|
|||
this.$element.find('input').val(show_value);
|
||||
},
|
||||
on_ui_change: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.value = this.$element.find('input').val();
|
||||
this.invalid = this.required && this.value == "";
|
||||
this._super.apply(this, arguments);
|
||||
this.view.on_form_changed(this);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -529,9 +592,10 @@ openerp.base.form.FieldText = openerp.base.form.Field.extend({
|
|||
this.$element.find('textarea').attr('disabled', this.readonly);
|
||||
},
|
||||
on_ui_change: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.value = this.$element.find('textarea').val();
|
||||
this.invalid = this.required && this.value == "";
|
||||
this._super.apply(this, arguments);
|
||||
this.view.on_form_changed(this);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -544,7 +608,7 @@ openerp.base.form.FieldBoolean = openerp.base.form.Field.extend({
|
|||
var self = this;
|
||||
this._super.apply(this, arguments);
|
||||
this.$element.find('input').click(function() {
|
||||
if ($(this)[0].checked != this.value) {
|
||||
if ($(this).is(':checked') != self.value) {
|
||||
self.on_ui_change();
|
||||
}
|
||||
});
|
||||
|
@ -558,9 +622,10 @@ openerp.base.form.FieldBoolean = openerp.base.form.Field.extend({
|
|||
this.$element.find('textarea').attr('disabled', this.readonly);
|
||||
},
|
||||
on_ui_change: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.value = this.$element.find('input').is(':checked');
|
||||
this.invalid = this.required && !this.value;
|
||||
this._super.apply(this, arguments);
|
||||
this.view.on_form_changed(this);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -590,9 +655,10 @@ openerp.base.form.FieldSelection = openerp.base.form.Field.extend({
|
|||
this.$element.find('select').attr('disabled', this.readonly);
|
||||
},
|
||||
on_ui_change: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.value = this.$element.find('select').val();
|
||||
this.invalid = this.required && this.value == "";
|
||||
this._super.apply(this, arguments);
|
||||
this.view.on_form_changed(this);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -612,30 +678,44 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
|
|||
}
|
||||
});
|
||||
|
||||
openerp.base.form.FieldOne2ManyDatasSet = openerp.base.DataSetStatic.extend({
|
||||
start: function() {
|
||||
},
|
||||
write: function (id, data, callback) {
|
||||
this._super(id, data, callback);
|
||||
},
|
||||
write: function (id, data, callback) {
|
||||
this._super(id, data, callback);
|
||||
},
|
||||
unlink: function() {
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.form.FieldOne2ManyViewManager = openerp.base.ViewManager.extend({
|
||||
init: function(session, element_id, dataset, views) {
|
||||
this._super(session, element_id, dataset, views);
|
||||
},
|
||||
});
|
||||
|
||||
openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({
|
||||
init: function(view, node) {
|
||||
this._super(view, node);
|
||||
this.template = "FieldOne2Many";
|
||||
this.viewmanager = null;
|
||||
this.operations = [];
|
||||
|
||||
},
|
||||
start: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.log("o2m.start");
|
||||
this.viewmanager = new openerp.base.ViewManager(this.view.session, this.element_id);
|
||||
this.viewmanager.searchable = false;
|
||||
var action = {
|
||||
res_model: this.field.relation,
|
||||
views: [ [false,"list"], ],
|
||||
};
|
||||
this.viewmanager.do_action_window(action);
|
||||
|
||||
var views = [ [false,"list"], [false,"form"] ];
|
||||
this.dataset = new openerp.base.form.FieldOne2ManyDatasSet(this.session, this.field.relation);
|
||||
this.viewmanager = new openerp.base.form.FieldOne2ManyViewManager(this.view.session, this.element_id, this.dataset, views);
|
||||
this.viewmanager.start();
|
||||
},
|
||||
set_value: function(value) {
|
||||
this.value = value;
|
||||
this.log("o2m.set_value",value);
|
||||
this.viewmanager.dataset.ids = value;
|
||||
this.viewmanager.dataset.ids.count = value.length;
|
||||
this.viewmanager.views.list.controller.do_update();
|
||||
},
|
||||
get_value: function(value) {
|
||||
|
@ -647,7 +727,6 @@ openerp.base.form.FieldOne2Many = openerp.base.form.Field.extend({
|
|||
this.$element.toggleClass('required', this.required);
|
||||
},
|
||||
on_ui_change: function() {
|
||||
this.view.on_form_changed(this);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -95,12 +95,12 @@ openerp.base.ListView = openerp.base.Controller.extend({
|
|||
// TODO: handle non-empty results.group_by with read_group
|
||||
self.dataset.context = results.context;
|
||||
self.dataset.domain = results.domain;
|
||||
self.dataset.fetch(self.dataset.fields, 0, self.limit, self.do_fill_table);
|
||||
self.dataset.read_slice(self.dataset.fields, 0, self.limit, self.do_fill_table);
|
||||
});
|
||||
},
|
||||
do_update: function () {
|
||||
var self = this;
|
||||
self.dataset.fetch(self.dataset.fields, 0, self.limit, self.do_fill_table);
|
||||
self.dataset.read_ids(self.dataset.ids, self.dataset.fields, self.do_fill_table);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -20,8 +20,7 @@ openerp.base.ActionManager = openerp.base.Controller.extend({
|
|||
if (this.viewmanager) {
|
||||
this.viewmanager.stop();
|
||||
}
|
||||
this.viewmanager = new openerp.base.ViewManager(this.session,this.element_id, true);
|
||||
this.viewmanager.do_action_window(action);
|
||||
this.viewmanager = new openerp.base.ViewManagerAction(this.session,this.element_id, action, true);
|
||||
this.viewmanager.start();
|
||||
}
|
||||
}
|
||||
|
@ -33,63 +32,32 @@ openerp.base.ActionManager = openerp.base.Controller.extend({
|
|||
openerp.base.views = new openerp.base.Registry();
|
||||
|
||||
openerp.base.ViewManager = openerp.base.Controller.extend({
|
||||
init: function(session, element_id, has_sidebar) {
|
||||
init: function(session, element_id, dataset, views) {
|
||||
this._super(session, element_id);
|
||||
this.action = null;
|
||||
this.dataset = null;
|
||||
this.model = dataset.model;
|
||||
this.dataset = dataset;
|
||||
this.searchview = null;
|
||||
this.active_view = null;
|
||||
this.views_src = views;
|
||||
this.views = {};
|
||||
if (has_sidebar)
|
||||
this.sidebar = new openerp.base.Sidebar(null, this);
|
||||
else
|
||||
this.sidebar = null;
|
||||
},
|
||||
start: function() {
|
||||
if (this.sidebar) {
|
||||
this.$element.find('.view-manager-main-sidebar').html(this.sidebar.render());
|
||||
this.sidebar.start();
|
||||
}
|
||||
},
|
||||
stop: function() {
|
||||
// should be replaced by automatic destruction implemented in BaseWidget
|
||||
if (this.sidebar) {
|
||||
this.sidebar.stop();
|
||||
}
|
||||
this._super();
|
||||
},
|
||||
do_action_window: function(action) {
|
||||
var self = this;
|
||||
this.action = action;
|
||||
|
||||
// switch to the first one in sequence
|
||||
var inital_view_loaded = this.setup_initial_view(action.res_model,action.views);
|
||||
|
||||
var searchview_loaded = this.setup_search_view(action);
|
||||
|
||||
if (action['auto_search']) {
|
||||
$.when(searchview_loaded, inital_view_loaded)
|
||||
.then(this.searchview.do_search);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @returns {jQuery.Deferred} initial view loading promise
|
||||
*/
|
||||
setup_initial_view: function(model,views) {
|
||||
start: function() {
|
||||
var self = this;
|
||||
this.dataset = new openerp.base.DataSet(this.session, model);
|
||||
this.dataset.start();
|
||||
|
||||
this.$element.html(QWeb.render("ViewManager", {"prefix": this.element_id, views: views}));
|
||||
|
||||
this.$element.html(QWeb.render("ViewManager", {"prefix": this.element_id, views: this.views_src}));
|
||||
this.$element.find('.oe_vm_switch button').click(function() {
|
||||
self.on_mode_switch($(this).data('view-type'));
|
||||
});
|
||||
_.each(views, function(view) {
|
||||
_.each(this.views_src, function(view) {
|
||||
self.views[view[1]] = { view_id: view[0], controller: null };
|
||||
});
|
||||
|
||||
return this.on_mode_switch(views[0][1]);
|
||||
// switch to the first one in sequence
|
||||
return this.on_mode_switch(this.views_src[0][1]);
|
||||
},
|
||||
stop: function() {
|
||||
},
|
||||
/**
|
||||
* Asks the view manager to switch visualization mode.
|
||||
|
@ -103,8 +71,8 @@ openerp.base.ViewManager = openerp.base.Controller.extend({
|
|||
var view = this.views[view_type];
|
||||
if (!view.controller) {
|
||||
// Lazy loading of views
|
||||
var controller = new (openerp.base.views.get_object(view_type))(
|
||||
this, this.session, this.element_id + "_view_" + view_type, this.dataset, view.view_id);
|
||||
var controllerclass = openerp.base.views.get_object(view_type);
|
||||
var controller = new controllerclass( this, this.session, this.element_id + "_view_" + view_type, this.dataset, view.view_id);
|
||||
view_promise = controller.start();
|
||||
this.views[view_type].controller = controller;
|
||||
}
|
||||
|
@ -133,37 +101,18 @@ openerp.base.ViewManager = openerp.base.Controller.extend({
|
|||
}
|
||||
return view_promise;
|
||||
},
|
||||
/**
|
||||
* Extract search view defaults from the current action's context.
|
||||
*
|
||||
* These defaults are of the form {search_default_*: value}
|
||||
*
|
||||
* @returns {Object} a clean defaults mapping of {field_name: value}
|
||||
*/
|
||||
search_defaults: function () {
|
||||
var defaults = {};
|
||||
_.each(this.action.context, function (value, key) {
|
||||
var match = /^search_default_(.*)$/.exec(key);
|
||||
if (match) {
|
||||
defaults[match[1]] = value;
|
||||
}
|
||||
});
|
||||
return defaults;
|
||||
},
|
||||
/**
|
||||
* Sets up the current viewmanager's search view.
|
||||
*
|
||||
* @param action the action being executed
|
||||
* @param view_id the view to use or false for a default one
|
||||
* @returns {jQuery.Deferred} search view startup deferred
|
||||
*/
|
||||
setup_search_view:function (action) {
|
||||
setup_search_view: function(view_id, search_defaults) {
|
||||
var self = this;
|
||||
if (this.searchview) {
|
||||
this.searchview.stop();
|
||||
}
|
||||
var view_id = action.search_view_id ? action.search_view_id[0] || false : false;
|
||||
|
||||
this.searchview = new openerp.base.SearchView(this, this.session, this.element_id + "_search", this.dataset, view_id, this.search_defaults());
|
||||
this.searchview = new openerp.base.SearchView(this, this.session, this.element_id + "_search", this.dataset, view_id, search_defaults);
|
||||
this.searchview.on_search.add(function() {
|
||||
self.views[self.active_view].controller.do_search.apply(self, arguments);
|
||||
});
|
||||
|
@ -182,12 +131,49 @@ openerp.base.ViewManager = openerp.base.Controller.extend({
|
|||
}
|
||||
});
|
||||
|
||||
openerp.base.ViewManagerRoot = openerp.base.ViewManager.extend({
|
||||
// Extends view manager
|
||||
});
|
||||
openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({
|
||||
init: function(session, element_id, action, sidebar) {
|
||||
var dataset = new openerp.base.DataSetSearch(session, action.res_model);
|
||||
this._super(session, element_id, dataset, action.views);
|
||||
this.action = action;
|
||||
this.sidebar = sidebar;
|
||||
if (sidebar)
|
||||
this.sidebar = new openerp.base.Sidebar(null, this);
|
||||
},
|
||||
start: function() {
|
||||
var self = this;
|
||||
var inital_view_loaded = this._super();
|
||||
|
||||
openerp.base.ViewManagerUsedAsAMany2One = openerp.base.ViewManager.extend({
|
||||
// Extends view manager
|
||||
// init sidebar
|
||||
if (this.sidebar) {
|
||||
this.$element.find('.view-manager-main-sidebar').html(this.sidebar.render());
|
||||
this.sidebar.start();
|
||||
}
|
||||
|
||||
// init search view
|
||||
var view_id = this.action.search_view_id ? this.action.search_view_id[0] || false : false;
|
||||
var search_defaults = {};
|
||||
_.each(this.action.context, function (value, key) {
|
||||
var match = /^search_default_(.*)$/.exec(key);
|
||||
if (match) {
|
||||
search_defaults[match[1]] = value;
|
||||
}
|
||||
});
|
||||
var searchview_loaded = this.setup_search_view(view_id,search_defaults);
|
||||
|
||||
// schedule auto_search
|
||||
if (this.action['auto_search']) {
|
||||
$.when(searchview_loaded, inital_view_loaded)
|
||||
.then(this.searchview.do_search);
|
||||
}
|
||||
},
|
||||
stop: function() {
|
||||
// should be replaced by automatic destruction implemented in BaseWidget
|
||||
if (this.sidebar) {
|
||||
this.sidebar.stop();
|
||||
}
|
||||
this._super();
|
||||
},
|
||||
});
|
||||
|
||||
openerp.base.BaseWidget = openerp.base.Controller.extend({
|
||||
|
@ -326,15 +312,14 @@ openerp.base.handle_action = function(session, action) {
|
|||
dialog.dialog({
|
||||
title: action.name
|
||||
});
|
||||
var viewmanager = new openerp.base.ViewManager(session,element_id, false);
|
||||
viewmanager.do_action_window(action);
|
||||
debugger;
|
||||
var viewmanager = new openerp.base.ViewManagerAction(session,element_id, action, false);
|
||||
viewmanager.start();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
openerp.base.views.add('calendar', 'openerp.base.CalendarView');
|
||||
|
||||
openerp.base.CalendarView = openerp.base.Controller.extend({
|
||||
start: function () {
|
||||
this._super();
|
||||
|
|
|
@ -10,6 +10,12 @@
|
|||
<h1>#{title}</h1>
|
||||
<p>#{text}</p>
|
||||
</div>
|
||||
<div id="oe_notification_alert" class="ui-state-error">
|
||||
<a class="ui-notify-cross ui-notify-close" href="#">x</a>
|
||||
<span style="float:left; margin:2px 5px 0 0;" class="ui-icon ui-icon-alert"></span>
|
||||
<h1>#{title}</h1>
|
||||
<p>#{text}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="oe_login" class="login"></div>
|
||||
<div style="position: absolute; right: 2px; top: 38px;">
|
||||
|
@ -191,7 +197,7 @@
|
|||
<t t-raw="console.log('Unhandled widget', widget)"/>
|
||||
</t>
|
||||
<t t-name="WidgetFrame">
|
||||
<table border="0" width="100%" cellpadding="2" cellspacing="2">
|
||||
<table border="0" width="100%" cellpadding="2" cellspacing="2" class="oe_frame">
|
||||
<tr t-foreach="widget.table" t-as="row">
|
||||
<t t-foreach="row" t-as="td">
|
||||
<td t-att-colspan="td.colspan gt 1 ? td.colspan : undefined"
|
||||
|
@ -199,6 +205,7 @@
|
|||
t-att-nowrap="td.is_field_label ? 'true' : undefined"
|
||||
t-att-valign="td.table ? 'top' : undefined"
|
||||
t-att-id="td.element_id"
|
||||
t-att-class="'container_' + td.type"
|
||||
>
|
||||
<t t-raw="td.render()"/>
|
||||
</td>
|
||||
|
@ -226,7 +233,7 @@
|
|||
</div>
|
||||
</t>
|
||||
<t t-name="WidgetLabel">
|
||||
<label t-att-for="widget.element_id" t-att-title="widget.help" style="display: block; text-align: right;"
|
||||
<label t-att-for="widget.element_id + '_field'" t-att-title="widget.help" style="display: block; text-align: right;"
|
||||
t-att-ondblclick="'console.log(\'' + widget.element_id + '\', openerp.screen.' + widget.element_id + ')'">
|
||||
<t t-esc="widget.string"/>
|
||||
<span t-if="widget.help">?</span>
|
||||
|
@ -236,38 +243,50 @@
|
|||
<t t-name="FieldChar">
|
||||
<input type="text"
|
||||
t-att-name="widget.name"
|
||||
t-att-id="widget.element_id + '_field'"
|
||||
t-att-class="'field_' + widget.type" style="width: 100%"
|
||||
/>
|
||||
</t>
|
||||
<t t-name="FieldText">
|
||||
<textarea rows="6" style="width: 100%;"
|
||||
t-att-name="widget.name"
|
||||
t-att-id="widget.element_id + '_field'"
|
||||
t-att-class="'field_' + widget.type"
|
||||
></textarea>
|
||||
</t>
|
||||
<t t-name="FieldDate">
|
||||
<input type="text" style="width: 100%"
|
||||
t-att-name="widget.name"
|
||||
t-att-id="widget.element_id + '_field'"
|
||||
t-att-class="'field_' + widget.type"
|
||||
/>
|
||||
</t>
|
||||
<t t-name="FieldDatetime">
|
||||
<input type="text" style="width: 100%"
|
||||
t-att-name="widget.name"
|
||||
t-att-id="widget.element_id + '_field'"
|
||||
t-att-class="'field_' + widget.type"
|
||||
/>
|
||||
</t>
|
||||
<t t-name="FieldSelection">
|
||||
<select t-att-name="widget.name" t-att-id="widget.element_id" t-att-class="'field_' + widget.type" style="width: 100%">
|
||||
<t t-foreach="widget.field.selection" t-as="options">
|
||||
<option t-att-value="options[0]">
|
||||
<t t-esc="options[1]"/>
|
||||
</option>
|
||||
</t>
|
||||
<select
|
||||
t-att-name="widget.name"
|
||||
t-att-id="widget.element_id + '_field'"
|
||||
t-att-class="'field_' + widget.type"
|
||||
style="width: 100%">
|
||||
<t t-foreach="widget.field.selection" t-as="options">
|
||||
<option t-att-value="options[0]">
|
||||
<t t-esc="options[1]"/>
|
||||
</option>
|
||||
</t>
|
||||
</select>
|
||||
</t>
|
||||
<t t-name="FieldMany2One">
|
||||
<input type="text" t-att-name="widget.name" t-att-id="widget.element_id" t-att-class="'field_' + widget.type" style="width: 100%;"/>
|
||||
<input type="text"
|
||||
t-att-name="widget.name"
|
||||
t-att-id="widget.element_id + '_field'"
|
||||
t-att-class="'field_' + widget.type"
|
||||
style="width: 100%;"/>
|
||||
</t>
|
||||
<t t-name="FieldOne2Many">
|
||||
<div t-att-id="widget.element_id">
|
||||
|
@ -283,12 +302,18 @@
|
|||
<input type="text" t-att-name="widget.name" t-att-id="widget.element_id" t-att-class="'field_' + widget.type" style="width: 100%" placeholder="Widget Reference"/>
|
||||
</t>
|
||||
<t t-name="FieldBoolean">
|
||||
<input type="checkbox" t-att-name="widget.name" t-att-id="widget.element_id" t-att-class="'field_' + widget.type"/>
|
||||
<input type="checkbox"
|
||||
t-att-name="widget.name"
|
||||
t-att-id="widget.element_id + '_field'"
|
||||
t-att-class="'field_' + widget.type"/>
|
||||
</t>
|
||||
<t t-name="WidgetButton">
|
||||
<button type="button" t-att-id="widget.element_id" t-att-title="widget.help" style="width: 100%" class="button">
|
||||
<button type="button"
|
||||
t-att-id="widget.element_id + '_button'"
|
||||
t-att-title="widget.help"
|
||||
style="width: 100%" class="button">
|
||||
<img t-if="widget.node.attrs.icon" t-att-src="'/base/static/src/img/icons/' + widget.node.attrs.icon + '.png'" width="16" height="16"/>
|
||||
<t t-esc="widget.string"/>
|
||||
<span t-if="widget.string"><t t-esc="widget.string"/></span>
|
||||
</button>
|
||||
</t>
|
||||
<t t-name="SearchView">
|
||||
|
@ -463,4 +488,12 @@
|
|||
</div>
|
||||
</t>
|
||||
</t>
|
||||
<t t-name="DialogWarning">
|
||||
<div id="dialog-message" t-att-title="title">
|
||||
<p>
|
||||
<span class="ui-icon ui-icon-circle-check" style="float:left; margin:0 7px 50px 0;"></span>
|
||||
<t t-esc="message"/>
|
||||
</p>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
|
|
|
@ -1,345 +0,0 @@
|
|||
/**
|
||||
* @function
|
||||
* Defines a module scope (which lasts until the next call to module).
|
||||
*
|
||||
* This module scopes implies setup and teardown callbacks running for each test.
|
||||
*
|
||||
* @param {String} name the name of the module
|
||||
* @param {Object} [lifecycle] callbacks to run before and after each test of the module
|
||||
* @param {Function} lifecycle.setup function running before each test of this module
|
||||
* @param {Function} lifecycle.teardown function running after each test of this module
|
||||
*/
|
||||
var module;
|
||||
/**
|
||||
* @function
|
||||
* Defines a given test to run. Runs all the assertions present in the test
|
||||
*
|
||||
* @param {String} name the name of the test
|
||||
* @param {Number} [expected] number of assertions expected to run in this test (useful for asynchronous tests)
|
||||
* @param {Function} test the testing code to run, holding a sequence of assertions (at least one)
|
||||
*/
|
||||
var test;
|
||||
/**
|
||||
* @function
|
||||
* Defines an asynchronous test: equivalent to calling stop() at the start of
|
||||
* a normal test().
|
||||
*
|
||||
* The test code needs to restart the test runner via start()
|
||||
*
|
||||
* @param {String} name the name of the test
|
||||
* @param {Number} [expected] number of assertions expected to run in this test (useful for asynchronous tests)
|
||||
* @param {Function} test the testing code to run, holding a sequence of assertions (at least one)
|
||||
*/
|
||||
var asyncTest;
|
||||
/**
|
||||
* @function
|
||||
* The most basic boolean assertion (~assertTrue or assert).
|
||||
*
|
||||
* Passes if its argument is truthy
|
||||
*
|
||||
* @param {Boolean} state an arbitrary expression, evaluated in a boolean context
|
||||
* @param {String} [message] the message to output with the assertion result
|
||||
*/
|
||||
var ok;
|
||||
/**
|
||||
* @function
|
||||
* Equality assertion (~assertEqual)
|
||||
*
|
||||
* Passes if both arguments are equal (via <code>==</code>)
|
||||
*
|
||||
* @param {Object} actual the object to check for correctness (processing result)
|
||||
* @param {Object} expected the object to check against
|
||||
* @param {String} [message] message output with the assertion result
|
||||
*/
|
||||
var equal;
|
||||
/**
|
||||
* @function
|
||||
* Inequality assertion (~assertNotEqual)
|
||||
*
|
||||
* Passes if the arguments are different (via <code>!=</code>)
|
||||
*
|
||||
* @param {Object} actual the object to check for correctness (processing result)
|
||||
* @param {Object} expected the object to check against
|
||||
* @param {String} [message] message output with the assertion result
|
||||
*/
|
||||
var notEqual;
|
||||
/**
|
||||
* @function
|
||||
* Recursive equality assertion.
|
||||
*
|
||||
* Works on primitive types using <code>===</code> and traversing through
|
||||
* Objects and Arrays as well checking their components
|
||||
*
|
||||
* @param {Object} actual the object to check for correctness (processing result)
|
||||
* @param {Object} expected the object to check against
|
||||
* @param {String} [message] message output with the assertion result
|
||||
*/
|
||||
var deepEqual;
|
||||
/**
|
||||
* @function
|
||||
* Recursive inequality assertion.
|
||||
*
|
||||
* Works on primitive types using <code>!==</code> and traversing through
|
||||
* Objects and Arrays as well checking their components
|
||||
*
|
||||
* @param {Object} actual the object to check for correctness (processing result)
|
||||
* @param {Object} expected the object to check against
|
||||
* @param {String} [message] message output with the assertion result
|
||||
*/
|
||||
var notDeepEqual;
|
||||
/**
|
||||
* @function
|
||||
* Strict equality assertion (~assertEqual)
|
||||
*
|
||||
* Passes if both arguments are identical (via <code>===</code>)
|
||||
*
|
||||
* @param {Object} actual the object to check for correctness (processing result)
|
||||
* @param {Object} expected the object to check against
|
||||
* @param {String} [message] message output with the assertion result
|
||||
*/
|
||||
var strictEqual;
|
||||
/**
|
||||
* @function
|
||||
* Strict inequality assertion (~assertNotEqual)
|
||||
*
|
||||
* Passes if both arguments are identical (via <code>!==</code>)
|
||||
*
|
||||
* @param {Object} actual the object to check for correctness (processing result)
|
||||
* @param {Object} expected the object to check against
|
||||
* @param {String} [message] message output with the assertion result
|
||||
*/
|
||||
var notStrictEqual;
|
||||
/**
|
||||
* @function
|
||||
* Passes if the provided block raised an exception.
|
||||
*
|
||||
* The <code>expect</code> argument can be provided to perform further assertion checks on the exception itself:
|
||||
* * If it's a <code>RegExp</code> test the exception against the regexp (message?)
|
||||
* * If it's a constructor, check if the exception is an instance of it
|
||||
* * If it's an other type of function, call it with the exception as first parameter
|
||||
* - If the function returns true, the assertion validates
|
||||
* - Otherwise it fails
|
||||
*
|
||||
* @param {Function} block function which should raise an exception when called
|
||||
* @param {Object} [expect] a RegExp, a constructor or a Function
|
||||
* @param {String} [message] message output with the assertion result
|
||||
*/
|
||||
var raises;
|
||||
/**
|
||||
* @function
|
||||
* Starts running the test runner again from the point where it was
|
||||
* <code>stop</code>ped.
|
||||
*
|
||||
* Used to resume testing after a callback.
|
||||
*/
|
||||
var start;
|
||||
/**
|
||||
* @function
|
||||
* Stops the test runner in order to wait for an asynchronous test to run
|
||||
*
|
||||
* @param {Number} [timeout] fails the test after the timeout triggers, only for debugging tests
|
||||
*/
|
||||
var stop;
|
||||
|
||||
var Session = function () {
|
||||
return {
|
||||
rpc: function (_url, params, on_success) {
|
||||
setTimeout(on_success);
|
||||
}
|
||||
};
|
||||
};
|
||||
$(document).ready(function () {
|
||||
var openerp;
|
||||
module("ids_callback", {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init(true);
|
||||
window.openerp.base.chrome(openerp);
|
||||
window.openerp.base.data(openerp);
|
||||
}
|
||||
});
|
||||
asyncTest("Baseline event attributes", 6, function () {
|
||||
var dataset = new openerp.base.DataSet(
|
||||
new Session());
|
||||
dataset.on_fetch.add(function (records, event) {
|
||||
deepEqual(records, [], 'No records returned');
|
||||
equal(event.offset, 0, 'No offset set in call');
|
||||
equal(event.limit, null, 'No limit set in call');
|
||||
deepEqual(event.domain, [], 'No domain on the dataset');
|
||||
deepEqual(event.context, {}, 'No context on the dataset');
|
||||
deepEqual(event.sort, [], 'The dataset is not sorted');
|
||||
start();
|
||||
});
|
||||
dataset.fetch();
|
||||
});
|
||||
asyncTest("Offset and limit", 2, function () {
|
||||
var dataset = new openerp.base.DataSet(
|
||||
new Session());
|
||||
dataset.on_fetch.add(function (records, event) {
|
||||
equal(event.offset, 20);
|
||||
equal(event.limit, 42);
|
||||
start();
|
||||
});
|
||||
dataset.fetch({
|
||||
name : { type : 'char' }
|
||||
}, 20, 42);
|
||||
});
|
||||
asyncTest("Domain and context propagation", 3, function () {
|
||||
var dataset = new openerp.base.DataSet(
|
||||
new Session());
|
||||
var domain_value = [['foo', '=', 'bar']];
|
||||
var context_value= {active_id:3, active_ids:42};
|
||||
var sort_value = ['foo'];
|
||||
dataset.on_fetch.add(function (records, event) {
|
||||
deepEqual(event.domain, domain_value);
|
||||
deepEqual(event.context, context_value);
|
||||
deepEqual(event.sort, sort_value);
|
||||
start();
|
||||
});
|
||||
dataset.set({
|
||||
domain: domain_value,
|
||||
context: context_value,
|
||||
sort: sort_value
|
||||
});
|
||||
dataset.fetch();
|
||||
});
|
||||
|
||||
var dataset;
|
||||
module("set", {
|
||||
setup: function () {
|
||||
var openerp = window.openerp.init(true);
|
||||
window.openerp.base.chrome(openerp);
|
||||
window.openerp.base.data(openerp);
|
||||
dataset = new openerp.base.DataSet();
|
||||
}
|
||||
});
|
||||
test('Basic properties setting', function () {
|
||||
var domain_value = [['foo', '=', 'bar']];
|
||||
var result = dataset.set({
|
||||
domain: domain_value
|
||||
});
|
||||
ok(dataset === result);
|
||||
deepEqual(domain_value, dataset._domain);
|
||||
});
|
||||
test("Ensure changes don't stick", function () {
|
||||
var domain = [['foo', '=', 'bar']];
|
||||
dataset.set({
|
||||
domain: domain
|
||||
});
|
||||
domain.pop();
|
||||
deepEqual([['foo', '=', 'bar']], dataset._domain);
|
||||
});
|
||||
|
||||
module('ids_activation', {
|
||||
setup: function () {
|
||||
var openerp = window.openerp.init(true);
|
||||
window.openerp.base.chrome(openerp);
|
||||
window.openerp.base.data(openerp);
|
||||
dataset = new openerp.base.DataSet();
|
||||
}
|
||||
});
|
||||
test('activate id', function () {
|
||||
dataset.activate(1);
|
||||
deepEqual(dataset.get_active_ids(), [1]);
|
||||
equal(dataset.get_active_id(), 1);
|
||||
});
|
||||
test('set active_ids', function () {
|
||||
dataset.select([1, 2, 3]);
|
||||
deepEqual(dataset.get_active_ids(), [1, 2, 3],
|
||||
"selecting an ids range");
|
||||
equal(dataset.get_active_id(), 1);
|
||||
});
|
||||
test('activate incorrect id', function () {
|
||||
dataset.select([1, 2, 3]);
|
||||
raises(function () { dataset.activate(42); },
|
||||
"Activating an id not present in the selection is an error");
|
||||
});
|
||||
test('reset active id on set active ids', function () {
|
||||
dataset.select([1, 2, 3]).activate(3).select([1, 2, 3]);
|
||||
equal(dataset.get_active_id(), 1,
|
||||
"selecting an ids range resets the active id");
|
||||
});
|
||||
|
||||
module('active_id_iteration', {
|
||||
setup: function () {
|
||||
var openerp = window.openerp.init(true);
|
||||
window.openerp.base.chrome(openerp);
|
||||
window.openerp.base.data(openerp);
|
||||
dataset = new openerp.base.DataSet();
|
||||
dataset.select([1, 2, 3]);
|
||||
}
|
||||
});
|
||||
test('step forward', function () {
|
||||
dataset.activate(1);
|
||||
dataset.next();
|
||||
equal(dataset.get_active_id(), 2);
|
||||
});
|
||||
test('wraparound forward', function () {
|
||||
dataset.activate(3);
|
||||
dataset.next();
|
||||
equal(dataset.get_active_id(), 1);
|
||||
});
|
||||
test('step back', function () {
|
||||
dataset.activate(3);
|
||||
dataset.prev();
|
||||
equal(dataset.get_active_id(), 2);
|
||||
});
|
||||
test('wraparound back', function () {
|
||||
dataset.activate(1);
|
||||
dataset.prev();
|
||||
equal(dataset.get_active_id(), 3);
|
||||
});
|
||||
|
||||
var ResponseAssertSession = function (response_ids) {
|
||||
return {
|
||||
rpc: function (url, params, on_success) {
|
||||
equal(url, '/base/dataset/get');
|
||||
deepEqual(params.ids, response_ids);
|
||||
_.delay(on_success, 0, _.map(
|
||||
params.ids, function (id) {
|
||||
return {id: id, sequence: id, name: 'foo'+id};
|
||||
}
|
||||
));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module('active_ids', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init(true);
|
||||
window.openerp.base.chrome(openerp);
|
||||
window.openerp.base.data(openerp);
|
||||
}
|
||||
});
|
||||
asyncTest('Get pre-set active_ids', 6, function () {
|
||||
var dataset = new openerp.base.DataSet(
|
||||
new ResponseAssertSession([1, 2, 3]));
|
||||
dataset.select([1, 2, 3]);
|
||||
dataset.on_active_ids.add(function (data_records) {
|
||||
equal(data_records.length, 3);
|
||||
equal(data_records[0].values.id, 1);
|
||||
equal(data_records[1].values.id, 2);
|
||||
equal(data_records[2].values.id, 3);
|
||||
start();
|
||||
});
|
||||
dataset.active_ids();
|
||||
});
|
||||
|
||||
module('active_id', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init(true);
|
||||
window.openerp.base.chrome(openerp);
|
||||
window.openerp.base.data(openerp);
|
||||
}
|
||||
});
|
||||
test('Get pre-set active_id', 3, function () {
|
||||
var dataset = new openerp.base.DataSet(
|
||||
new ResponseAssertSession([42]));
|
||||
stop(500);
|
||||
dataset.select([1, 2, 3, 42]).activate(42);
|
||||
dataset.on_active_id.add(function (data_record) {
|
||||
equal(data_record.values.id, 42);
|
||||
start();
|
||||
});
|
||||
dataset.active_id();
|
||||
});
|
||||
});
|
|
@ -11,7 +11,7 @@
|
|||
<script src="/base/static/lib/underscore/underscore.js" type="text/javascript"></script>
|
||||
|
||||
<!-- jquery -->
|
||||
<script src="/base/static/lib/jquery/jquery-1.5.1.js"></script>
|
||||
<script src="/base/static/lib/jquery/jquery-1.5.2.js"></script>
|
||||
<script src="/base/static/lib/jquery.ui/js/jquery-ui-1.8.9.custom.min.js"></script>
|
||||
|
||||
<script src="/base/static/lib/qweb/qweb.js"></script>
|
||||
|
@ -33,7 +33,6 @@
|
|||
<ol id="qunit-tests"></ol>
|
||||
<div id="qunit-fixture"></div>
|
||||
</body>
|
||||
<script type="text/javascript" src="/base/static/test/dataset.js"></script>
|
||||
<script type="text/javascript" src="/base/static/test/registry.js"></script>
|
||||
<script type="text/javascript" src="/base/static/test/search-date.js"></script>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
import controllers
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"name": "Web Chat",
|
||||
"version": "2.0",
|
||||
"depends": [],
|
||||
"js": ["static/src/web_chat.js"],
|
||||
"css": [],
|
||||
'active': True,
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
import main
|
|
@ -0,0 +1,165 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import sys, time
|
||||
|
||||
import simplejson
|
||||
|
||||
import openerpweb
|
||||
|
||||
#----------------------------------------------------------
|
||||
# OpenERP Web ajaxim Controllers
|
||||
#----------------------------------------------------------
|
||||
class PollServerMessageQueue(object):
|
||||
def __init__(self):
|
||||
# message queue
|
||||
self.l = []
|
||||
# online users
|
||||
self.users = {}
|
||||
# should contains: {
|
||||
# 'user1234' : { s:1, m:"status message", timestamp: last_contact_timestamp }
|
||||
# }
|
||||
def userlist():
|
||||
# return user list
|
||||
pass
|
||||
|
||||
def write(self, m_type, m_sender, m_recipent, m_message, m_group):
|
||||
# appends messages to l
|
||||
# when status message uupdate users
|
||||
pass
|
||||
def read(self, recpient, timestamp):
|
||||
# return matching message
|
||||
pass
|
||||
def gc():
|
||||
# remove message older than 300s from self.l
|
||||
# remove dead users from self.users
|
||||
pass
|
||||
|
||||
class PollServer(openerpweb.Controller):
|
||||
_cp_path = "/web_chat/pollserver"
|
||||
|
||||
@openerpweb.httprequest
|
||||
def login(self, req, **kw):
|
||||
"""
|
||||
--> POST http://ajaxim.com/wp-content/plugins/im/ajaxim.php/login
|
||||
Form Data
|
||||
username:""
|
||||
password:"d41d8cd98f00b204e9800998ecf8427e"
|
||||
<-- 200 OK
|
||||
Content-Type:text/html
|
||||
|
||||
{
|
||||
"r":"logged in",
|
||||
"u":"Guest130213866190.85",
|
||||
"s":"f9e1811536f19ad5b9e00376f9ff1532",
|
||||
"f":[
|
||||
{"u":"Guest130205108745.47","s":{"s":1,"m":""},"g":"Users"},
|
||||
{"u":"Guest130209838956.76","s":{"s":1,"m":""},"g":"Users"},
|
||||
]
|
||||
}
|
||||
"""
|
||||
mq = req.applicationsession.setdefault("web_chat",PollServerMessageQueue())
|
||||
print "chat login",kw
|
||||
# r = 'loggued in'
|
||||
#u = generate random.randint(0,2**32)
|
||||
#s = cherrypy cookie id
|
||||
#f = mq.userlist()
|
||||
return """
|
||||
{
|
||||
"r":"logged in",
|
||||
"u":"Guest130213866190.85",
|
||||
"s":"f9e1811536f19ad5b9e00376f9ff1532",
|
||||
"f":[
|
||||
{"u":"Guest130205108745.47","s":{"s":1,"m":""},"g":"Users"},
|
||||
{"u":"Guest130209838956.76","s":{"s":1,"m":""},"g":"Users"},
|
||||
]
|
||||
}
|
||||
"""
|
||||
|
||||
@openerpweb.httprequest
|
||||
def logout(self, req):
|
||||
"""
|
||||
--> GET http://im.ajaxim.com/logout
|
||||
{ "r":"logged out" }
|
||||
"""
|
||||
|
||||
@openerpweb.httprequest
|
||||
def poll(self, req, **kw):
|
||||
"""
|
||||
--> GET http://im.ajaxim.com/poll?callback=jsonp1302138663582&_1302138663582=
|
||||
<-- 200 OK
|
||||
Content-Type:text/html
|
||||
|
||||
noop:
|
||||
jsonp1302138663582([]);
|
||||
|
||||
roster user online:
|
||||
jsonp1302140366243([{"t":"s","s":"Guest130214038974.31","r":"all","m":"1:","g":"Users"}]);
|
||||
|
||||
roster user left:
|
||||
jsonp1302140441577([{"t":"s","s":"Guest130214038974.31","r":"","m":"0:"}]);
|
||||
|
||||
receive message:
|
||||
jsonp1302140191599([{"t":"m","s":"Guest130214008855.5","r":"Guest130214013134.26","m":"fuck"}]);
|
||||
|
||||
('t' => $msg->type, 's' => $msg->from, 'r' => $msg->to, 'm' => $msg->message )
|
||||
mag type s or m
|
||||
echo '<script type="text/javascript">parent.AjaxIM.incoming('. json_encode($this->_pollParseMessages($messages)) . ');</script>'
|
||||
|
||||
|
||||
"""
|
||||
# for i in range(60):
|
||||
#r = mq.read(username,timestamp)
|
||||
# if messages
|
||||
# return r
|
||||
# if no message sleep 2s and retry
|
||||
# sleep 2
|
||||
# else
|
||||
# return emptylist
|
||||
print "chat poll",kw
|
||||
time.sleep(2)
|
||||
# it's http://localhost:8002/web_chat/pollserver/poll?method=long?callback=jsonp1302147330483&_1302147330483=
|
||||
return '%s([{"t":"m","s":"Guest130214008855.5","r":"Guest130214013134.26","m":"fuck"}]);'%kw.get('callback','')
|
||||
return None
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def send(self, req, **kw):
|
||||
"""
|
||||
--> GET http://im.ajaxim.com/send?callback=jsonp1302139980022&to=Guest130205108745.47&message=test&_1302139980022=
|
||||
callback: jsonp1302139980022
|
||||
to: Guest130205108745.47
|
||||
message: test
|
||||
_1302139980022:
|
||||
|
||||
<-- 200 OK
|
||||
Content-Type:text/html
|
||||
|
||||
return array('r' => 'sent');
|
||||
return array('r' => 'error', 'e' => 'no session found');
|
||||
return array('r' => 'error', 'e' => 'no_recipient');
|
||||
return array('r' => 'error', 'e' => 'send error');
|
||||
|
||||
"""
|
||||
print "chat send",kw
|
||||
# mq.write()
|
||||
return {"action": actions}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def status(self, req, **kw):
|
||||
"""
|
||||
--> GET status call
|
||||
const Offline = 0;
|
||||
const Available = 1;
|
||||
const Away = 2;
|
||||
const Invisible = 3;
|
||||
|
||||
<-- 200 OK
|
||||
Content-Type:text/html
|
||||
|
||||
return array('r' => 'status set');
|
||||
return array('r' => 'error', 'e' => 'no session found');
|
||||
return array('r' => 'error', 'e' => 'status error');
|
||||
"""
|
||||
print "chat status",kw
|
||||
# mq.write()
|
||||
return {"action": actions}
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
import im
|
||||
from server import main # import the server library
|
||||
|
||||
im = Webchat_IM()
|
||||
action = preg_replace('/^' . preg_quote($_SERVER['SCRIPT_NAME'], '/') . '\/(.+?)(\?.+)?$/', '\1', $_SERVER['REQUEST_URI']);
|
||||
|
||||
if(substr(action, 0, 1) != '_' && method_exists(im, action))
|
||||
if(action == 'poll') {
|
||||
if($_GET['method'] == 'comet') {
|
||||
im->poll('comet');
|
||||
} else {
|
||||
print $_GET['callback'] . '(' . json_encode(im->poll($_GET['method'])) . ')';
|
||||
}
|
||||
} else {
|
||||
execute = call_user_func_array(array(im, action), $_POST);
|
||||
if(execute)
|
||||
print json_encode(execute !== false ? execute : array('e'=>'wrong args'));
|
||||
}
|
||||
else
|
||||
print json_encode(array('e'=>'no method'));
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
import openerpweb
|
||||
|
||||
class IM(openerpweb.Controller):
|
||||
def __init__(self):
|
||||
super(IM, self).__init__()
|
||||
return;
|
||||
|
||||
def chat_login(self, username, password):
|
||||
return dict()
|
||||
|
||||
def chat_logout(self):
|
||||
return dict()
|
||||
|
||||
def send(self):
|
||||
return dict()
|
||||
|
||||
def status(self, status, message):
|
||||
return dict()
|
||||
|
||||
def poll(self, method):
|
||||
return dict()
|
|
@ -0,0 +1,61 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import simplejson
|
||||
import openerpweb
|
||||
|
||||
from web_chat.controllers import im
|
||||
|
||||
__all__ = ['Webchat_IM']
|
||||
|
||||
chat_config_options = {'IM_LIBRARY': 'main', # The IM server library.
|
||||
'COOKIE_NAME': 'ajaxim_session', # Session cookie used by Ajax IM
|
||||
'COOKIE_PERIOD': 365 # Cookie period, in days
|
||||
}
|
||||
|
||||
nodejs_memcache_server = ['localhost:11211']
|
||||
|
||||
class Webchat_IM(im.IM):
|
||||
|
||||
_cp_path = "/webchat/webchatim"
|
||||
|
||||
def __init__(self):
|
||||
super(Webchat_IM, self).__init__()
|
||||
|
||||
return;
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def index(self, req, username="admin", password="admin"):
|
||||
|
||||
if req._login:
|
||||
self.username = req._login
|
||||
self.uid = req._uid
|
||||
self.db = req._db
|
||||
|
||||
return;
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def chat_login(self, req, username="admin", password="admin"):
|
||||
# TODO: use db and uid for unique identification.
|
||||
|
||||
self.auth = [['admin', 'a'], ['demo', 'demo']]
|
||||
|
||||
self.user_pass = []
|
||||
self.user_session = None
|
||||
|
||||
if username and password:
|
||||
self.user_pass = [username, password]
|
||||
|
||||
if self.user_pass in self.auth:
|
||||
self.user_session = username + '_' + str(req.session_id)
|
||||
|
||||
data = {'username': username, 'user_id': username, 'user_session': self.user_session,
|
||||
'friends': {'u': 'demo', 'g': 'Friends', 's': '1'} # {'u': 'username', 'g': 'group', 's': 'status'}
|
||||
}
|
||||
|
||||
# Get the list of friends from memcache.
|
||||
|
||||
return dict(r='logged in', s=self.user_session, f=data['friends'])
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def chat_logout(self):
|
||||
return dict(r='Logged out')
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2005 - 2010 Joshua Gross, http://ajaxim.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -0,0 +1,79 @@
|
|||
// Automatically load dependencies, in order, if they aren't already loaded.
|
||||
// Each array is: [filename, deptest] where deptest is the function to
|
||||
// test for the dependency.
|
||||
var AjaxIM, AjaxIMLoadedFunction;
|
||||
(function() {
|
||||
AjaxIM = {};
|
||||
AjaxIM.loaded = function(f) {
|
||||
AjaxIMLoadedFunction = f;
|
||||
};
|
||||
|
||||
var tagsrc =
|
||||
(thistag = document.getElementsByTagName('script'))[thistag.length-1].src;
|
||||
var jsfolder = tagsrc.replace(/im.load.js([?].+)?/, '');
|
||||
var imfolder = jsfolder.replace(/js\/$/, '');
|
||||
|
||||
var nodehost = '';
|
||||
|
||||
var dependencies = [
|
||||
['jquery-1.3.2.js', function() { return (typeof window['jQuery'] != 'undefined'); }],
|
||||
['jquery.jsonp-1.1.0.js', function() { return (typeof jQuery['jsonp'] != 'undefined'); }],
|
||||
['jquery.jstore-all-min.js', function() { return (typeof jQuery['jstore'] != 'undefined'); }],
|
||||
['jquery.md5.js', function() { return (typeof jQuery['md5'] != 'undefined'); }],
|
||||
['im.js', function() { return (typeof window['AjaxIM'] != 'object'); }]
|
||||
];
|
||||
|
||||
var head = document.getElementsByTagName('head')[0];
|
||||
|
||||
(loadDep = function(depPos) {
|
||||
if(depPos >= dependencies.length) { init(); return; }
|
||||
var dep = dependencies[depPos];
|
||||
|
||||
if(!dep[1]()) {
|
||||
var newdep = document.createElement('script');
|
||||
newdep.type = 'text/javascript';
|
||||
newdep.src = jsfolder + dep[0];
|
||||
|
||||
var nextdep = function() { loadDep(depPos + 1); };
|
||||
newdep.onload = nextdep;
|
||||
newdep.onreadystatechange = nextdep;
|
||||
|
||||
head.appendChild(newdep);
|
||||
} else loadDep(depPos + 1);
|
||||
})(0);
|
||||
|
||||
var init = function() {
|
||||
if(tagsrc.match(/[?]php$/)) {
|
||||
AjaxIM.init({
|
||||
pollServer: imfolder + 'ajaxim.php',
|
||||
theme: imfolder + 'themes/default',
|
||||
flashStorage: jsfolder + 'jStore.Flash.html'
|
||||
});
|
||||
} else if(tagsrc.match(/[?]node$/)) {
|
||||
AjaxIM.init({
|
||||
pollServer: imfolder + 'ajaxim.php',
|
||||
theme: imfolder + 'themes/default',
|
||||
flashStorage: jsfolder + 'jStore.Flash.html'
|
||||
}, {
|
||||
poll: 'http://' + nodehost + '/poll',
|
||||
send: 'http://' + nodehost + '/send',
|
||||
status: 'http://' + nodehost + '/status',
|
||||
resume: 'http://' + nodehost + '/resume'
|
||||
});
|
||||
} else if(tagsrc.match(/[?]guest$/)) {
|
||||
AjaxIM.init({
|
||||
pollServer: imfolder + 'ajaxim.php',
|
||||
theme: imfolder + 'themes/default',
|
||||
flashStorage: jsfolder + 'jStore.Flash.html'
|
||||
}, {
|
||||
poll: 'http://' + nodehost + '/poll',
|
||||
send: 'http://' + nodehost + '/send',
|
||||
status: 'http://' + nodehost + '/status',
|
||||
resume: 'http://' + nodehost + '/resume'
|
||||
});
|
||||
AjaxIM.client.login();
|
||||
}
|
||||
|
||||
AjaxIM.loaded();
|
||||
};
|
||||
})();
|
|
@ -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>
|
|
@ -0,0 +1,269 @@
|
|||
/*
|
||||
* jQuery JSONP Core Plugin 1.1.0 (2009-10-06)
|
||||
*
|
||||
* http://code.google.com/p/jquery-jsonp/
|
||||
*
|
||||
* Copyright (c) 2009 Julian Aubourg
|
||||
*
|
||||
* This document is licensed as free software under the terms of the
|
||||
* MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
(function($){
|
||||
|
||||
// ###################### UTILITIES ##
|
||||
// Test a value is neither undefined nor null
|
||||
var defined = function(v) {
|
||||
return v!==undefined && v!==null;
|
||||
},
|
||||
// Call if defined
|
||||
callIfDefined = function(method,object,parameters) {
|
||||
defined(method) && method.apply(object,parameters);
|
||||
},
|
||||
// Let the current thread running
|
||||
later = function(functor) {
|
||||
setTimeout(functor,0);
|
||||
},
|
||||
// String constants (for better minification)
|
||||
empty="",
|
||||
amp="&",
|
||||
qMark="?",
|
||||
success = "success",
|
||||
error = "error",
|
||||
|
||||
// Head element (for faster use)
|
||||
head = $("head"),
|
||||
// Page cache
|
||||
pageCache = {},
|
||||
|
||||
// ###################### DEFAULT OPTIONS ##
|
||||
xOptionsDefaults = {
|
||||
//beforeSend: undefined,
|
||||
//cache: false,
|
||||
callback: "C",
|
||||
//callbackParameter: undefined,
|
||||
//complete: undefined,
|
||||
//data: ""
|
||||
//dataFilter: undefined,
|
||||
//error: undefined,
|
||||
//pageCache: false,
|
||||
//success: undefined,
|
||||
//timeout: 0,
|
||||
url: location.href
|
||||
},
|
||||
|
||||
// ###################### MAIN FUNCTION ##
|
||||
jsonp = function(xOptions) {
|
||||
|
||||
// Build data with default
|
||||
xOptions = $.extend({},xOptionsDefaults,xOptions);
|
||||
|
||||
// References to beforeSend (for better minification)
|
||||
var beforeSendCallback = xOptions.beforeSend,
|
||||
|
||||
// Abort/done flag
|
||||
done = 0;
|
||||
|
||||
// Put a temporary abort
|
||||
xOptions.abort = function() { done = 1; };
|
||||
|
||||
// Call beforeSend if provided (early abort if false returned)
|
||||
if (defined(beforeSendCallback) && (beforeSendCallback(xOptions,xOptions)===false || done))
|
||||
return xOptions;
|
||||
|
||||
// References to xOptions members (for better minification)
|
||||
var successCallback = xOptions.success,
|
||||
completeCallback = xOptions.complete,
|
||||
errorCallback = xOptions.error,
|
||||
dataFilter = xOptions.dataFilter,
|
||||
callbackParameter = xOptions.callbackParameter,
|
||||
successCallbackName = xOptions.callback,
|
||||
cacheFlag = xOptions.cache,
|
||||
pageCacheFlag = xOptions.pageCache,
|
||||
url = xOptions.url,
|
||||
data = xOptions.data,
|
||||
timeout = xOptions.timeout,
|
||||
|
||||
// Misc variables
|
||||
splitUrl,splitData,i,j;
|
||||
|
||||
// Control entries
|
||||
url = defined(url)?url:empty;
|
||||
data = defined(data)?((typeof data)=="string"?data:$.param(data)):empty;
|
||||
|
||||
// Add callback parameter if provided as option
|
||||
defined(callbackParameter)
|
||||
&& (data += (data==empty?empty:amp)+escape(callbackParameter)+"=?");
|
||||
|
||||
// Add anticache parameter if needed
|
||||
!cacheFlag && !pageCacheFlag
|
||||
&& (data += (data==empty?empty:amp)+"_"+(new Date()).getTime()+"=");
|
||||
|
||||
// Search for ? in url
|
||||
splitUrl = url.split(qMark);
|
||||
// Also in parameters if provided
|
||||
// (and merge arrays)
|
||||
if (data!=empty) {
|
||||
splitData = data.split(qMark);
|
||||
j = splitUrl.length-1;
|
||||
j && (splitUrl[j] += amp + splitData.shift());
|
||||
splitUrl = splitUrl.concat(splitData);
|
||||
}
|
||||
// If more than 2 ? replace the last one by the callback
|
||||
i = splitUrl.length-2;
|
||||
i && (splitUrl[i] += successCallbackName + splitUrl.pop());
|
||||
|
||||
// Build the final url
|
||||
var finalUrl = splitUrl.join(qMark),
|
||||
|
||||
// Utility function
|
||||
notifySuccess = function(json) {
|
||||
// Apply the data filter if provided
|
||||
defined(dataFilter) && (json = dataFilter.apply(xOptions,[json]));
|
||||
// Call success then complete
|
||||
callIfDefined(successCallback,xOptions,[json,success]);
|
||||
callIfDefined(completeCallback,xOptions,[xOptions,success]);
|
||||
},
|
||||
notifyError = function(type) {
|
||||
// Call error then complete
|
||||
callIfDefined(errorCallback,xOptions,[xOptions,type]);
|
||||
callIfDefined(completeCallback,xOptions,[xOptions,type]);
|
||||
},
|
||||
|
||||
// Get from pageCache
|
||||
pageCached = pageCache[finalUrl];
|
||||
|
||||
// Check page cache
|
||||
if (pageCacheFlag && defined(pageCached)) {
|
||||
later(function() {
|
||||
// If an error was cached
|
||||
defined(pageCached.s)
|
||||
? notifySuccess(pageCached.s)
|
||||
: notifyError(error);
|
||||
});
|
||||
return xOptions;
|
||||
}
|
||||
|
||||
|
||||
// Create & write to the iframe (sends the request)
|
||||
// We let the hand to current code to avoid
|
||||
// pre-emptive callbacks
|
||||
|
||||
// We also install the timeout here to avoid
|
||||
// timeout before the code has been dumped to the frame
|
||||
// (in case of insanely short timeout values)
|
||||
later(function() {
|
||||
|
||||
// If it has been aborted, do nothing
|
||||
if (done) return;
|
||||
|
||||
// Create an iframe & add it to the document
|
||||
var frame = $("<iframe />").appendTo(head),
|
||||
|
||||
// Get the iframe's window and document objects
|
||||
tmp = frame[0],
|
||||
window = tmp.contentWindow || tmp.contentDocument,
|
||||
document = window.document,
|
||||
|
||||
// Declaration of cleanup function
|
||||
cleanUp,
|
||||
|
||||
// Declaration of timer for timeout (so we can clear it eventually)
|
||||
timeoutTimer,
|
||||
|
||||
// Error function
|
||||
errorFunction = function (_,type) {
|
||||
// If pure error (not timeout), cache if needed
|
||||
pageCacheFlag && !defined(type) && (pageCache[finalUrl] = empty);
|
||||
// Cleanup
|
||||
cleanUp();
|
||||
// Call error then complete
|
||||
notifyError(defined(type)?type:error);
|
||||
},
|
||||
|
||||
// Iframe variable cleaning function
|
||||
removeVariable = function(varName) {
|
||||
window[varName] = undefined;
|
||||
try { delete window[varName]; } catch(_) {}
|
||||
},
|
||||
|
||||
// Error callback name
|
||||
errorCallbackName = successCallbackName=="E"?"X":"E";
|
||||
|
||||
// Control if we actually retrieved the document
|
||||
if(!defined(document)) {
|
||||
document = window;
|
||||
window = document.getParentNode();
|
||||
}
|
||||
|
||||
// We have to open the document before
|
||||
// declaring variables in the iframe's window
|
||||
// Don't ask me why, I have no clue
|
||||
document.open();
|
||||
|
||||
// Install callbacks
|
||||
window[successCallbackName] = function(json) {
|
||||
// Set as treated
|
||||
done = 1;
|
||||
// Pagecache is needed
|
||||
pageCacheFlag && (pageCache[finalUrl] = {s: json});
|
||||
// Give hand back to frame
|
||||
// To finish gracefully
|
||||
later(function(){
|
||||
// Cleanup
|
||||
cleanUp();
|
||||
// Call success then complete
|
||||
notifySuccess(json);
|
||||
});
|
||||
};
|
||||
|
||||
window[errorCallbackName] = function(state) {
|
||||
// If not treated, mark
|
||||
// then give hand back to iframe
|
||||
// for it to finish gracefully
|
||||
(!state || state=="complete") && !done++ && later(errorFunction);
|
||||
};
|
||||
|
||||
// Clean up function (declaration)
|
||||
xOptions.abort = cleanUp = function() {
|
||||
// Clear the timeout (is it exists)
|
||||
clearTimeout(timeoutTimer);
|
||||
// Open the iframes document & clean
|
||||
document.open();
|
||||
removeVariable(errorCallbackName);
|
||||
removeVariable(successCallbackName);
|
||||
document.write(empty);
|
||||
document.close();
|
||||
frame.remove();
|
||||
};
|
||||
|
||||
// Write to the document
|
||||
document.write([
|
||||
'<html><head><script src="',
|
||||
finalUrl,'" onload="',
|
||||
errorCallbackName,'()" onreadystatechange="',
|
||||
errorCallbackName,'(this.readyState)"></script></head><body onload="',
|
||||
errorCallbackName,'()"></body></html>'
|
||||
].join(empty)
|
||||
);
|
||||
|
||||
// Close (makes some browsers happier)
|
||||
document.close();
|
||||
|
||||
// If a timeout is needed, install it
|
||||
timeout>0 && (timeoutTimer = setTimeout(function(){
|
||||
!done && errorFunction(empty,"timeout");
|
||||
},timeout));
|
||||
});
|
||||
|
||||
return xOptions;
|
||||
}
|
||||
|
||||
// ###################### SETUP FUNCTION ##
|
||||
jsonp.setup = function(xOptions) {
|
||||
$.extend(xOptionsDefaults,xOptions);
|
||||
};
|
||||
|
||||
// ###################### INSTALL in jQuery ##
|
||||
$.jsonp = jsonp;
|
||||
|
||||
})(jQuery);
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
/*
|
||||
* jQuery JSON Plugin
|
||||
* version: 1.0 (2008-04-17)
|
||||
*
|
||||
* This document is licensed as free software under the terms of the
|
||||
* MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*
|
||||
* Brantley Harris technically wrote this plugin, but it is based somewhat
|
||||
* on the JSON.org website's http://www.json.org/json2.js, which proclaims:
|
||||
* "NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.", a sentiment that
|
||||
* I uphold. I really just cleaned it up.
|
||||
*
|
||||
* It is also based heavily on MochiKit's serializeJSON, which is
|
||||
* copywrited 2005 by Bob Ippolito.
|
||||
*/
|
||||
(function($){function toIntegersAtLease(n){return n<10?"0"+n:n}Date.prototype.toJSON=function(date){return this.getUTCFullYear()+"-"+toIntegersAtLease(this.getUTCMonth())+"-"+toIntegersAtLease(this.getUTCDate())};var escapeable=/["\\\x00-\x1f\x7f-\x9f]/g;var meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};$.quoteString=function(string){if(escapeable.test(string)){return'"'+string.replace(escapeable,function(a){var c=meta[a];if(typeof c==="string"){return c}c=a.charCodeAt();return"\\u00"+Math.floor(c/16).toString(16)+(c%16).toString(16)})+'"'}return'"'+string+'"'};$.toJSON=function(o,compact){var type=typeof(o);if(type=="undefined"){return"undefined"}else{if(type=="number"||type=="boolean"){return o+""}else{if(o===null){return"null"}}}if(type=="string"){return $.quoteString(o)}if(type=="object"&&typeof o.toJSON=="function"){return o.toJSON(compact)}if(type!="function"&&typeof(o.length)=="number"){var ret=[];for(var i=0;i<o.length;i++){ret.push($.toJSON(o[i],compact))}if(compact){return"["+ret.join(",")+"]"}else{return"["+ret.join(", ")+"]"}}if(type=="function"){throw new TypeError("Unable to convert object of type 'function' to json.")}var ret=[];for(var k in o){var name;type=typeof(k);if(type=="number"){name='"'+k+'"'}else{if(type=="string"){name=$.quoteString(k)}else{continue}}var val=$.toJSON(o[k],compact);if(typeof(val)!="string"){continue}if(compact){ret.push(name+":"+val)}else{ret.push(name+": "+val)}}return"{"+ret.join(", ")+"}"};$.compactJSON=function(o){return $.toJSON(o,true)};$.evalJSON=function(src){return eval("("+src+")")};$.secureEvalJSON=function(src){var filtered=src;filtered=filtered.replace(/\\["\\\/bfnrtu]/g,"@");filtered=filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]");filtered=filtered.replace(/(?:^|:|,)(?:\s*\[)+/g,"");if(/^[\],:{}\s]*$/.test(filtered)){return eval("("+src+")")}else{throw new SyntaxError("Error parsing JSON, source is not valid.")}}})(jQuery);(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(b){var a;try{a=new RegExp('^("(\\\\.|[^"\\\\\\n\\r])*?"|[,:{}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t])+?$')}catch(c){a=/^(true|false|null|\[.*\]|\{.*\}|".*"|\d+|\d+\.\d+)$/}b.jStore={};b.extend(b.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(b.jStore).bind("jStore-ready",function(d){b.jStore.isReady=true;if(b.jStore.defaults.autoload){d.connect()}}).bind("flash-ready",function(){b.jStore.isFlashReady=true}),ready:function(d){if(b.jStore.isReady){d.apply(b.jStore,[b.jStore.CurrentEngine])}else{b.jStore.delegate.bind("jStore-ready",d)}},fail:function(d){b.jStore.delegate.bind("jStore-failure",d)},flashReady:function(d){if(b.jStore.isFlashReady){d.apply(b.jStore,[b.jStore.CurrentEngine])}else{b.jStore.delegate.bind("flash-ready",d)}},use:function(g,i,f){i=i||b.jStore.defaults.project||location.hostname.replace(/\./g,"-")||"unknown";var h=b.jStore.Engines[g.toLowerCase()]||null,d=(f?f+".":"")+i+"."+g;if(!h){throw"JSTORE_ENGINE_UNDEFINED"}h=new h(i,d);if(b.jStore.Instances[d]){throw"JSTORE_JRI_CONFLICT"}if(h.isAvailable()){b.jStore.Instances[d]=h;if(!b.jStore.CurrentEngine){b.jStore.CurrentEngine=h}b.jStore.delegate.trigger("jStore-ready",h)}else{if(!h.autoload){throw"JSTORE_ENGINE_UNAVILABLE"}else{h.included(function(){if(this.isAvailable()){b.jStore.Instances[d]=this;if(!b.jStore.CurrentEngine){b.jStore.CurrentEngine=this}b.jStore.delegate.trigger("jStore-ready",this)}else{b.jStore.delegate.trigger("jStore-failure",this)}}).include()}}},setCurrentEngine:function(d){if(!b.jStore.Instances.length){return b.jStore.FindEngine()}if(!d&&b.jStore.Instances.length>=1){b.jStore.delegate.trigger("jStore-ready",b.jStore.Instances[0]);return b.jStore.CurrentEngine=b.jStore.Instances[0]}if(d&&b.jStore.Instances[d]){b.jStore.delegate.trigger("jStore-ready",b.jStore.Instances[d]);return b.jStore.CurrentEngine=b.jStore.Instances[d]}throw"JSTORE_JRI_NO_MATCH"},FindEngine:function(){b.each(b.jStore.EngineOrder,function(d){if(b.jStore.Availability[this]()){b.jStore.use(this,b.jStore.defaults.project,"default");return false}})},load:function(){if(b.jStore.defaults.engine){return b.jStore.use(b.jStore.defaults.engine,b.jStore.defaults.project,"default")}try{b.jStore.FindEngine()}catch(d){}},safeStore:function(d){switch(typeof d){case"object":case"function":return b.compactJSON(d);case"number":case"boolean":case"string":case"xml":return d;case"undefined":default:return""}},safeResurrect:function(d){return a.test(d)?b.evalJSON(d):d},store:function(d,e){if(!b.jStore.CurrentEngine){return false}if(!e){return b.jStore.CurrentEngine.get(d)}return b.jStore.CurrentEngine.set(d,e)},remove:function(d){if(!b.jStore.CurrentEngine){return false}return b.jStore.CurrentEngine.rem(d)},get:function(d){return b.jStore.store(d)},set:function(d,e){return b.jStore.store(d,e)}});b.extend(b.fn,{store:function(e,f){if(!b.jStore.CurrentEngine){return this}var d=b.jStore.store(e,f);return !f?d:this},removeStore:function(d){b.jStore.remove(d);return this},getStore:function(d){return b.jStore.store(d)},setStore:function(d,e){b.jStore.store(d,e);return this}})})(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},interruptAccess:function(){if(!this.isReady){throw"JSTORE_ENGINE_NOT_READY"}},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){this.interruptAccess();return this.data[b]||null},set:function(b,c){this.interruptAccess();this.data[b]=c;return c},rem:function(b){this.interruptAccess();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){this.interruptAccess();var d=this.db.getItem(e);return c.jStore.safeResurrect((d&&d.value?d.value:d))},set:function(d,e){this.interruptAccess();this.db.setItem(d,c.jStore.safeStore(e));return e},rem:function(e){this.interruptAccess();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){this.interruptAccess();var c=this.db.f_get_cookie(d);return c=="null"?null:b.jStore.safeResurrect(c)},set:function(c,d){this.interruptAccess();this.db.f_set_cookie(c,b.jStore.safeStore(d));return d},rem:function(c){this.interruptAccess();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)]=b.jStore.safeResurrect(c.field(1));c.next()}c.close();this.delegate.trigger("engine-ready")},isAvailable:a,set:function(d,e){this.interruptAccess();var c=this.db;c.execute("BEGIN");c.execute("INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)",[d,b.jStore.safeStore(e)]);c.execute("COMMIT");return this._super(d,e)},rem:function(d){this.interruptAccess();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]=b.jStore.safeResurrect(j.v)}c.delegate.trigger("engine-ready")})})},isAvailable:a,set:function(c,d){this.interruptAccess();this.db.transaction(function(e){e.executeSql("INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)",[c,b.jStore.safeStore(d)])});return this._super(c,d)},rem:function(c){this.interruptAccess();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.interruptAccess();this.db.load(this.project);return b.jStore.safeResurrect(this.db.getAttribute(c))},set:function(c,d){this.interruptAccess();this.db.setAttribute(c,b.jStore.safeStore(d));this.db.save(this.project);return d},rem:function(c){this.interruptAccess();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);
|
|
@ -0,0 +1,963 @@
|
|||
/*!
|
||||
* 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
|
||||
*/
|
||||
/*!
|
||||
* jQuery JSON Plugin
|
||||
* version: 1.0 (2008-04-17)
|
||||
*
|
||||
* This document is licensed as free software under the terms of the
|
||||
* MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
*
|
||||
* Brantley Harris technically wrote this plugin, but it is based somewhat
|
||||
* on the JSON.org website's http://www.json.org/json2.js, which proclaims:
|
||||
* "NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.", a sentiment that
|
||||
* I uphold. I really just cleaned it up.
|
||||
*
|
||||
* It is also based heavily on MochiKit's serializeJSON, which is
|
||||
* copywrited 2005 by Bob Ippolito.
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
function toIntegersAtLease(n)
|
||||
// Format integers to have at least two digits.
|
||||
{
|
||||
return n < 10 ? '0' + n : n;
|
||||
}
|
||||
|
||||
Date.prototype.toJSON = function(date)
|
||||
// Yes, it polutes the Date namespace, but we'll allow it here, as
|
||||
// it's damned usefull.
|
||||
{
|
||||
return this.getUTCFullYear() + '-' +
|
||||
toIntegersAtLease(this.getUTCMonth()) + '-' +
|
||||
toIntegersAtLease(this.getUTCDate());
|
||||
};
|
||||
|
||||
var escapeable = /["\\\x00-\x1f\x7f-\x9f]/g;
|
||||
var meta = { // table of character substitutions
|
||||
'\b': '\\b',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\f': '\\f',
|
||||
'\r': '\\r',
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
};
|
||||
|
||||
$.quoteString = function(string)
|
||||
// Places quotes around a string, inteligently.
|
||||
// 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.
|
||||
{
|
||||
if (escapeable.test(string))
|
||||
{
|
||||
return '"' + string.replace(escapeable, function (a)
|
||||
{
|
||||
var c = meta[a];
|
||||
if (typeof c === 'string') {
|
||||
return c;
|
||||
}
|
||||
c = a.charCodeAt();
|
||||
return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
|
||||
}) + '"';
|
||||
}
|
||||
return '"' + string + '"';
|
||||
};
|
||||
|
||||
$.toJSON = function(o, compact)
|
||||
{
|
||||
var type = typeof(o);
|
||||
|
||||
if (type == "undefined")
|
||||
return "undefined";
|
||||
else if (type == "number" || type == "boolean")
|
||||
return o + "";
|
||||
else if (o === null)
|
||||
return "null";
|
||||
|
||||
// Is it a string?
|
||||
if (type == "string")
|
||||
{
|
||||
return $.quoteString(o);
|
||||
}
|
||||
|
||||
// Does it have a .toJSON function?
|
||||
if (type == "object" && typeof o.toJSON == "function")
|
||||
return o.toJSON(compact);
|
||||
|
||||
// Is it an array?
|
||||
if (type != "function" && typeof(o.length) == "number")
|
||||
{
|
||||
var ret = [];
|
||||
for (var i = 0; i < o.length; i++) {
|
||||
ret.push( $.toJSON(o[i], compact) );
|
||||
}
|
||||
if (compact)
|
||||
return "[" + ret.join(",") + "]";
|
||||
else
|
||||
return "[" + ret.join(", ") + "]";
|
||||
}
|
||||
|
||||
// If it's a function, we have to warn somebody!
|
||||
if (type == "function") {
|
||||
throw new TypeError("Unable to convert object of type 'function' to json.");
|
||||
}
|
||||
|
||||
// It's probably an object, then.
|
||||
var ret = [];
|
||||
for (var k in o) {
|
||||
var name;
|
||||
type = typeof(k);
|
||||
|
||||
if (type == "number")
|
||||
name = '"' + k + '"';
|
||||
else if (type == "string")
|
||||
name = $.quoteString(k);
|
||||
else
|
||||
continue; //skip non-string or number keys
|
||||
|
||||
var val = $.toJSON(o[k], compact);
|
||||
if (typeof(val) != "string") {
|
||||
// skip non-serializable values
|
||||
continue;
|
||||
}
|
||||
|
||||
if (compact)
|
||||
ret.push(name + ":" + val);
|
||||
else
|
||||
ret.push(name + ": " + val);
|
||||
}
|
||||
return "{" + ret.join(", ") + "}";
|
||||
};
|
||||
|
||||
$.compactJSON = function(o)
|
||||
{
|
||||
return $.toJSON(o, true);
|
||||
};
|
||||
|
||||
$.evalJSON = function(src)
|
||||
// Evals JSON that we know to be safe.
|
||||
{
|
||||
try {
|
||||
return eval("(" + src + ")");
|
||||
} catch(e) {
|
||||
return src;
|
||||
}
|
||||
};
|
||||
|
||||
$.secureEvalJSON = function(src)
|
||||
// Evals JSON in a way that is *more* secure.
|
||||
{
|
||||
var filtered = src;
|
||||
filtered = filtered.replace(/\\["\\\/bfnrtu]/g, '@');
|
||||
filtered = filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
|
||||
filtered = filtered.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
|
||||
|
||||
if (/^[\],:{}\s]*$/.test(filtered))
|
||||
return eval("(" + src + ")");
|
||||
else
|
||||
throw new SyntaxError("Error parsing JSON, source is not valid.");
|
||||
};
|
||||
})(jQuery);
|
||||
/**
|
||||
* 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($){
|
||||
|
||||
var rxJson;
|
||||
|
||||
try {
|
||||
rxJson = new RegExp('^("(\\\\.|[^"\\\\\\n\\r])*?"|[,:{}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t])+?$')
|
||||
} catch (e) {
|
||||
rxJson = /^(true|false|null|\[.*\]|\{.*\}|".*"|\d+|\d+\.\d+)$/
|
||||
}
|
||||
|
||||
// Setup the jStore namespace in jQuery for options storage
|
||||
$.jStore = {};
|
||||
|
||||
// Seed the object
|
||||
$.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
|
||||
ready: function(callback){
|
||||
if ($.jStore.isReady) callback.apply($.jStore, [$.jStore.CurrentEngine]);
|
||||
else $.jStore.delegate.bind('jStore-ready', callback);
|
||||
},
|
||||
// Enable failure callback registration for jStore
|
||||
fail: function(callback){
|
||||
$.jStore.delegate.bind('jStore-failure', callback);
|
||||
},
|
||||
// Enable ready callback for Flash
|
||||
flashReady: function(callback){
|
||||
if ($.jStore.isFlashReady) callback.apply($.jStore, [$.jStore.CurrentEngine]);
|
||||
else $.jStore.delegate.bind('flash-ready', callback);
|
||||
},
|
||||
// Enable and test an engine
|
||||
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
|
||||
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
|
||||
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 way for users to call for auto-loading
|
||||
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) {}
|
||||
},
|
||||
// Parse a value as JSON before its stored.
|
||||
safeStore: function(value){
|
||||
switch (typeof value){
|
||||
case 'object': case 'function': return $.compactJSON(value);
|
||||
case 'number': case 'boolean': case 'string': case 'xml': return value;
|
||||
case 'undefined': default: return '';
|
||||
}
|
||||
},
|
||||
// Restores JSON'd values before returning
|
||||
safeResurrect: function(value){
|
||||
return rxJson.test(value) ? $.evalJSON(value) : value;
|
||||
},
|
||||
// Provide a simple interface for storing/getting values
|
||||
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 removing values
|
||||
remove: function(key){
|
||||
if (!$.jStore.CurrentEngine) return false;
|
||||
|
||||
return $.jStore.CurrentEngine.rem(key);
|
||||
},
|
||||
// Alias access for reading
|
||||
get: function(key){
|
||||
return $.jStore.store(key);
|
||||
},
|
||||
// Alias access for setting
|
||||
set: function(key, value){
|
||||
return $.jStore.store(key, value);
|
||||
}
|
||||
})
|
||||
|
||||
// Extend the jQuery funcitonal object
|
||||
$.extend($.fn, {
|
||||
// Provide a chainable interface for storing values/getting a value at the end of a chain
|
||||
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
|
||||
removeStore: function(key){
|
||||
$.jStore.remove(key);
|
||||
|
||||
return this;
|
||||
},
|
||||
// Alias access for reading at the end of a chain.
|
||||
getStore: function(key){
|
||||
return $.jStore.store(key);
|
||||
},
|
||||
// Alias access for setting on a chanin.
|
||||
setStore: function(key, value){
|
||||
$.jStore.store(key, value);
|
||||
return this;
|
||||
}
|
||||
})
|
||||
|
||||
})(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;
|
||||
},
|
||||
// All get/set/rem functions across the engines should add this to the
|
||||
// first line of those functions to prevent accessing the engine while unstable.
|
||||
interruptAccess: function(){
|
||||
if (!this.isReady) throw 'JSTORE_ENGINE_NOT_READY';
|
||||
},
|
||||
/** 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){
|
||||
this.interruptAccess();
|
||||
return this.data[key] || null;
|
||||
},
|
||||
set: function(key, value){
|
||||
this.interruptAccess();
|
||||
this.data[key] = value;
|
||||
return value;
|
||||
},
|
||||
rem: function(key){
|
||||
this.interruptAccess();
|
||||
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){
|
||||
this.interruptAccess();
|
||||
var out = this.db.getItem(key);
|
||||
// Gecko's getItem returns {value: 'the value'}, WebKit returns 'the value'
|
||||
return $.jStore.safeResurrect( (out && out.value ? out.value : out) );
|
||||
},
|
||||
set: function(key, value){
|
||||
this.interruptAccess();
|
||||
this.db.setItem(key,$.jStore.safeStore(value));
|
||||
return value;
|
||||
},
|
||||
rem: function(key){
|
||||
this.interruptAccess();
|
||||
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){
|
||||
this.interruptAccess();
|
||||
var out = this.db.f_get_cookie(key);
|
||||
return out == 'null' ? null : $.jStore.safeResurrect(out);
|
||||
},
|
||||
set: function(key, value){
|
||||
this.interruptAccess();
|
||||
this.db.f_set_cookie(key, $.jStore.safeStore(value));
|
||||
return value;
|
||||
},
|
||||
rem: function(key){
|
||||
this.interruptAccess();
|
||||
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)] = $.jStore.safeResurrect( 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){
|
||||
this.interruptAccess();
|
||||
// Update the database
|
||||
var db = this.db;
|
||||
db.execute( 'BEGIN' );
|
||||
db.execute( 'INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)', [key,$.jStore.safeStore(value)] );
|
||||
db.execute( 'COMMIT' );
|
||||
return this._super(key, value);
|
||||
},
|
||||
rem: function(key){
|
||||
this.interruptAccess();
|
||||
// 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] = $.jStore.safeResurrect( row.v );
|
||||
}
|
||||
|
||||
// Fire our delegate to indicate we're ready for data transactions
|
||||
self.delegate.trigger('engine-ready');
|
||||
});
|
||||
});
|
||||
},
|
||||
isAvailable: avilability,
|
||||
set: function(key, value){
|
||||
this.interruptAccess();
|
||||
// Update the database
|
||||
this.db.transaction(function(db){
|
||||
db.executeSql( 'INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)', [key,$.jStore.safeStore(value)]);
|
||||
});
|
||||
return this._super(key, value);
|
||||
},
|
||||
rem: function(key){
|
||||
this.interruptAccess();
|
||||
// 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.interruptAccess();
|
||||
this.db.load(this.project);
|
||||
return $.jStore.safeResurrect( this.db.getAttribute(key) );
|
||||
},
|
||||
set: function(key, value){
|
||||
this.interruptAccess();
|
||||
this.db.setAttribute(key, $.jStore.safeStore(value));
|
||||
this.db.save(this.project);
|
||||
return value;
|
||||
},
|
||||
rem: function(key){
|
||||
this.interruptAccess();
|
||||
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);
|
|
@ -0,0 +1,230 @@
|
|||
|
||||
/**
|
||||
* jQuery MD5 hash algorithm function
|
||||
*
|
||||
* <code>
|
||||
* Calculate the md5 hash of a String
|
||||
* String $.md5 ( String str )
|
||||
* </code>
|
||||
*
|
||||
* Calculates the MD5 hash of str using the » RSA Data Security, Inc. MD5 Message-Digest Algorithm, and returns that hash.
|
||||
* MD5 (Message-Digest algorithm 5) is a widely-used cryptographic hash function with a 128-bit hash value. MD5 has been employed in a wide variety of security applications, and is also commonly used to check the integrity of data. The generated hash is also non-reversable. Data cannot be retrieved from the message digest, the digest uniquely identifies the data.
|
||||
* MD5 was developed by Professor Ronald L. Rivest in 1994. Its 128 bit (16 byte) message digest makes it a faster implementation than SHA-1.
|
||||
* This script is used to process a variable length message into a fixed-length output of 128 bits using the MD5 algorithm. It is fully compatible with UTF-8 encoding. It is very useful when u want to transfer encrypted passwords over the internet. If you plan using UTF-8 encoding in your project don't forget to set the page encoding to UTF-8 (Content-Type meta tag).
|
||||
* This function orginally get from the WebToolkit and rewrite for using as the jQuery plugin.
|
||||
*
|
||||
* Example
|
||||
* Code
|
||||
* <code>
|
||||
* $.md5("I'm Persian.");
|
||||
* </code>
|
||||
* Result
|
||||
* <code>
|
||||
* "b8c901d0f02223f9761016cfff9d68df"
|
||||
* </code>
|
||||
*
|
||||
* @alias Muhammad Hussein Fattahizadeh < muhammad [AT] semnanweb [DOT] com >
|
||||
* @link http://www.semnanweb.com/jquery-plugin/md5.html
|
||||
* @see http://www.webtoolkit.info/
|
||||
* @license http://www.gnu.org/licenses/gpl.html [GNU General Public License]
|
||||
* @param {jQuery} {md5:function(string))
|
||||
* @return string
|
||||
*/
|
||||
|
||||
(function($){
|
||||
|
||||
var rotateLeft = function(lValue, iShiftBits) {
|
||||
return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
|
||||
}
|
||||
|
||||
var addUnsigned = function(lX, lY) {
|
||||
var lX4, lY4, lX8, lY8, lResult;
|
||||
lX8 = (lX & 0x80000000);
|
||||
lY8 = (lY & 0x80000000);
|
||||
lX4 = (lX & 0x40000000);
|
||||
lY4 = (lY & 0x40000000);
|
||||
lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
|
||||
if (lX4 & lY4) return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
|
||||
if (lX4 | lY4) {
|
||||
if (lResult & 0x40000000) return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
|
||||
else return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
|
||||
} else {
|
||||
return (lResult ^ lX8 ^ lY8);
|
||||
}
|
||||
}
|
||||
|
||||
var F = function(x, y, z) {
|
||||
return (x & y) | ((~ x) & z);
|
||||
}
|
||||
|
||||
var G = function(x, y, z) {
|
||||
return (x & z) | (y & (~ z));
|
||||
}
|
||||
|
||||
var H = function(x, y, z) {
|
||||
return (x ^ y ^ z);
|
||||
}
|
||||
|
||||
var I = function(x, y, z) {
|
||||
return (y ^ (x | (~ z)));
|
||||
}
|
||||
|
||||
var FF = function(a, b, c, d, x, s, ac) {
|
||||
a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac));
|
||||
return addUnsigned(rotateLeft(a, s), b);
|
||||
};
|
||||
|
||||
var GG = function(a, b, c, d, x, s, ac) {
|
||||
a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac));
|
||||
return addUnsigned(rotateLeft(a, s), b);
|
||||
};
|
||||
|
||||
var HH = function(a, b, c, d, x, s, ac) {
|
||||
a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac));
|
||||
return addUnsigned(rotateLeft(a, s), b);
|
||||
};
|
||||
|
||||
var II = function(a, b, c, d, x, s, ac) {
|
||||
a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac));
|
||||
return addUnsigned(rotateLeft(a, s), b);
|
||||
};
|
||||
|
||||
var convertToWordArray = function(string) {
|
||||
var lWordCount;
|
||||
var lMessageLength = string.length;
|
||||
var lNumberOfWordsTempOne = lMessageLength + 8;
|
||||
var lNumberOfWordsTempTwo = (lNumberOfWordsTempOne - (lNumberOfWordsTempOne % 64)) / 64;
|
||||
var lNumberOfWords = (lNumberOfWordsTempTwo + 1) * 16;
|
||||
var lWordArray = Array(lNumberOfWords - 1);
|
||||
var lBytePosition = 0;
|
||||
var lByteCount = 0;
|
||||
while (lByteCount < lMessageLength) {
|
||||
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
|
||||
lBytePosition = (lByteCount % 4) * 8;
|
||||
lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
|
||||
lByteCount++;
|
||||
}
|
||||
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
|
||||
lBytePosition = (lByteCount % 4) * 8;
|
||||
lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
|
||||
lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
|
||||
lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
|
||||
return lWordArray;
|
||||
};
|
||||
|
||||
var wordToHex = function(lValue) {
|
||||
var WordToHexValue = "", WordToHexValueTemp = "", lByte, lCount;
|
||||
for (lCount = 0; lCount <= 3; lCount++) {
|
||||
lByte = (lValue >>> (lCount * 8)) & 255;
|
||||
WordToHexValueTemp = "0" + lByte.toString(16);
|
||||
WordToHexValue = WordToHexValue + WordToHexValueTemp.substr(WordToHexValueTemp.length - 2, 2);
|
||||
}
|
||||
return WordToHexValue;
|
||||
};
|
||||
|
||||
var uTF8Encode = function(string) {
|
||||
string = string.replace(/\x0d\x0a/g, "\x0a");
|
||||
var output = "";
|
||||
for (var n = 0; n < string.length; n++) {
|
||||
var c = string.charCodeAt(n);
|
||||
if (c < 128) {
|
||||
output += String.fromCharCode(c);
|
||||
} else if ((c > 127) && (c < 2048)) {
|
||||
output += String.fromCharCode((c >> 6) | 192);
|
||||
output += String.fromCharCode((c & 63) | 128);
|
||||
} else {
|
||||
output += String.fromCharCode((c >> 12) | 224);
|
||||
output += String.fromCharCode(((c >> 6) & 63) | 128);
|
||||
output += String.fromCharCode((c & 63) | 128);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
};
|
||||
|
||||
$.extend({
|
||||
md5: function(string) {
|
||||
var x = Array();
|
||||
var k, AA, BB, CC, DD, a, b, c, d;
|
||||
var S11=7, S12=12, S13=17, S14=22;
|
||||
var S21=5, S22=9 , S23=14, S24=20;
|
||||
var S31=4, S32=11, S33=16, S34=23;
|
||||
var S41=6, S42=10, S43=15, S44=21;
|
||||
string = uTF8Encode(string);
|
||||
x = convertToWordArray(string);
|
||||
a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
|
||||
for (k = 0; k < x.length; k += 16) {
|
||||
AA = a; BB = b; CC = c; DD = d;
|
||||
a = FF(a, b, c, d, x[k+0], S11, 0xD76AA478);
|
||||
d = FF(d, a, b, c, x[k+1], S12, 0xE8C7B756);
|
||||
c = FF(c, d, a, b, x[k+2], S13, 0x242070DB);
|
||||
b = FF(b, c, d, a, x[k+3], S14, 0xC1BDCEEE);
|
||||
a = FF(a, b, c, d, x[k+4], S11, 0xF57C0FAF);
|
||||
d = FF(d, a, b, c, x[k+5], S12, 0x4787C62A);
|
||||
c = FF(c, d, a, b, x[k+6], S13, 0xA8304613);
|
||||
b = FF(b, c, d, a, x[k+7], S14, 0xFD469501);
|
||||
a = FF(a, b, c, d, x[k+8], S11, 0x698098D8);
|
||||
d = FF(d, a, b, c, x[k+9], S12, 0x8B44F7AF);
|
||||
c = FF(c, d, a, b, x[k+10], S13, 0xFFFF5BB1);
|
||||
b = FF(b, c, d, a, x[k+11], S14, 0x895CD7BE);
|
||||
a = FF(a, b, c, d, x[k+12], S11, 0x6B901122);
|
||||
d = FF(d, a, b, c, x[k+13], S12, 0xFD987193);
|
||||
c = FF(c, d, a, b, x[k+14], S13, 0xA679438E);
|
||||
b = FF(b, c, d, a, x[k+15], S14, 0x49B40821);
|
||||
a = GG(a, b, c, d, x[k+1], S21, 0xF61E2562);
|
||||
d = GG(d, a, b, c, x[k+6], S22, 0xC040B340);
|
||||
c = GG(c, d, a, b, x[k+11], S23, 0x265E5A51);
|
||||
b = GG(b, c, d, a, x[k+0], S24, 0xE9B6C7AA);
|
||||
a = GG(a, b, c, d, x[k+5], S21, 0xD62F105D);
|
||||
d = GG(d, a, b, c, x[k+10], S22, 0x2441453);
|
||||
c = GG(c, d, a, b, x[k+15], S23, 0xD8A1E681);
|
||||
b = GG(b, c, d, a, x[k+4], S24, 0xE7D3FBC8);
|
||||
a = GG(a, b, c, d, x[k+9], S21, 0x21E1CDE6);
|
||||
d = GG(d, a, b, c, x[k+14], S22, 0xC33707D6);
|
||||
c = GG(c, d, a, b, x[k+3], S23, 0xF4D50D87);
|
||||
b = GG(b, c, d, a, x[k+8], S24, 0x455A14ED);
|
||||
a = GG(a, b, c, d, x[k+13], S21, 0xA9E3E905);
|
||||
d = GG(d, a, b, c, x[k+2], S22, 0xFCEFA3F8);
|
||||
c = GG(c, d, a, b, x[k+7], S23, 0x676F02D9);
|
||||
b = GG(b, c, d, a, x[k+12], S24, 0x8D2A4C8A);
|
||||
a = HH(a, b, c, d, x[k+5], S31, 0xFFFA3942);
|
||||
d = HH(d, a, b, c, x[k+8], S32, 0x8771F681);
|
||||
c = HH(c, d, a, b, x[k+11], S33, 0x6D9D6122);
|
||||
b = HH(b, c, d, a, x[k+14], S34, 0xFDE5380C);
|
||||
a = HH(a, b, c, d, x[k+1], S31, 0xA4BEEA44);
|
||||
d = HH(d, a, b, c, x[k+4], S32, 0x4BDECFA9);
|
||||
c = HH(c, d, a, b, x[k+7], S33, 0xF6BB4B60);
|
||||
b = HH(b, c, d, a, x[k+10], S34, 0xBEBFBC70);
|
||||
a = HH(a, b, c, d, x[k+13], S31, 0x289B7EC6);
|
||||
d = HH(d, a, b, c, x[k+0], S32, 0xEAA127FA);
|
||||
c = HH(c, d, a, b, x[k+3], S33, 0xD4EF3085);
|
||||
b = HH(b, c, d, a, x[k+6], S34, 0x4881D05);
|
||||
a = HH(a, b, c, d, x[k+9], S31, 0xD9D4D039);
|
||||
d = HH(d, a, b, c, x[k+12], S32, 0xE6DB99E5);
|
||||
c = HH(c, d, a, b, x[k+15], S33, 0x1FA27CF8);
|
||||
b = HH(b, c, d, a, x[k+2], S34, 0xC4AC5665);
|
||||
a = II(a, b, c, d, x[k+0], S41, 0xF4292244);
|
||||
d = II(d, a, b, c, x[k+7], S42, 0x432AFF97);
|
||||
c = II(c, d, a, b, x[k+14], S43, 0xAB9423A7);
|
||||
b = II(b, c, d, a, x[k+5], S44, 0xFC93A039);
|
||||
a = II(a, b, c, d, x[k+12], S41, 0x655B59C3);
|
||||
d = II(d, a, b, c, x[k+3], S42, 0x8F0CCC92);
|
||||
c = II(c, d, a, b, x[k+10], S43, 0xFFEFF47D);
|
||||
b = II(b, c, d, a, x[k+1], S44, 0x85845DD1);
|
||||
a = II(a, b, c, d, x[k+8], S41, 0x6FA87E4F);
|
||||
d = II(d, a, b, c, x[k+15], S42, 0xFE2CE6E0);
|
||||
c = II(c, d, a, b, x[k+6], S43, 0xA3014314);
|
||||
b = II(b, c, d, a, x[k+13], S44, 0x4E0811A1);
|
||||
a = II(a, b, c, d, x[k+4], S41, 0xF7537E82);
|
||||
d = II(d, a, b, c, x[k+11], S42, 0xBD3AF235);
|
||||
c = II(c, d, a, b, x[k+2], S43, 0x2AD7D2BB);
|
||||
b = II(b, c, d, a, x[k+9], S44, 0xEB86D391);
|
||||
a = addUnsigned(a, AA);
|
||||
b = addUnsigned(b, BB);
|
||||
c = addUnsigned(c, CC);
|
||||
d = addUnsigned(d, DD);
|
||||
}
|
||||
var tempValue = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);
|
||||
return tempValue.toLowerCase();
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
|
@ -0,0 +1,8 @@
|
|||
Emoticons and "error" icon from "LED Icon Set" by led24.de
|
||||
----------------------------------------------------------
|
||||
You can do whatever you want with these icons (use on web or in desktop applications) as long as you don’t pass them off as your own and remove this readme file. A credit statement and a link back to
|
||||
http://led24.de/iconset/ or http://led24.de/ would be appreciated.
|
||||
|
||||
Follow us on twitter http://twitter.com/gasyoun or email leds24@gmail.com
|
||||
512 icons 20/05/2009
|
||||
----------------------------------------------------------
|
After Width: | Height: | Size: 868 B |
After Width: | Height: | Size: 814 B |
After Width: | Height: | Size: 853 B |
After Width: | Height: | Size: 853 B |
After Width: | Height: | Size: 850 B |
After Width: | Height: | Size: 843 B |
After Width: | Height: | Size: 860 B |
After Width: | Height: | Size: 846 B |
After Width: | Height: | Size: 854 B |
After Width: | Height: | Size: 121 B |
After Width: | Height: | Size: 176 B |
After Width: | Height: | Size: 552 B |
After Width: | Height: | Size: 212 B |
After Width: | Height: | Size: 706 B |
After Width: | Height: | Size: 142 B |
After Width: | Height: | Size: 141 B |
After Width: | Height: | Size: 234 B |
After Width: | Height: | Size: 109 B |
|
@ -0,0 +1,535 @@
|
|||
.imjs-default { display: none; }
|
||||
|
||||
/* [begin] Chatbox */
|
||||
.imjs-chatbox {
|
||||
position: absolute;
|
||||
bottom: 25px;
|
||||
right: -1px;
|
||||
width: 225px;
|
||||
border: 1px solid #cecece;
|
||||
font: 12px/14px Helvetica Neue, Helvetica, Arial, Calibri, Tahoma, Verdana, sans-serif;
|
||||
color: #000;
|
||||
cursor: default;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.imjs-chatbox > div {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* [begin] Chatbox header */
|
||||
div.imjs-header {
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 215px;
|
||||
height: 12px;
|
||||
padding: 5px;
|
||||
background: #f0efed;
|
||||
border-bottom: 1px solid #999;
|
||||
font-weight: 700;
|
||||
box-shadow: 0 1px 2px #ccc;
|
||||
-moz-box-shadow: 0 1px 2px #ccc;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
div.imjs-header a {
|
||||
position: absolute;
|
||||
text-shadow: none;
|
||||
color: #333;
|
||||
text-decoration: none;
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
div.imjs-header a.imjs-close {
|
||||
top: 6px;
|
||||
right: 5px;
|
||||
height: 0;
|
||||
padding-top: 10px;
|
||||
width: 10px;
|
||||
overflow: hidden;
|
||||
background: url(images/closemin.png) 0 0 no-repeat;
|
||||
}
|
||||
|
||||
div.imjs-header a.imjs-minimize {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding-top: 23px;
|
||||
height: 0;
|
||||
width: 207px;
|
||||
overflow: hidden;
|
||||
background: url(images/closemin.png) 100% -10px no-repeat;
|
||||
}
|
||||
|
||||
div.imjs-header a.imjs-minimize:active {
|
||||
outline: none;
|
||||
}
|
||||
/* [end] Chatbox header */
|
||||
|
||||
/* [begin] Message log */
|
||||
ul.imjs-msglog {
|
||||
display: block;
|
||||
overflow-y: auto;
|
||||
height: 235px;
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-bottom: 1px solid #ddd;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
li.imjs-date {
|
||||
display: block;
|
||||
padding: 5px 5px 3px 8px;
|
||||
border-top: 1px dotted #afafaf;
|
||||
background-color: #e9e9e9;
|
||||
}
|
||||
|
||||
li.imjs-error {
|
||||
display: block;
|
||||
padding: 0 5px 3px 8px;
|
||||
border-top: 1px dotted #afafaf;
|
||||
background-color: #ffeded;
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
li.imjs-error span.imjs-msg-time {
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
li.imjs-msg-a, li.imjs-msg-b {
|
||||
display: block;
|
||||
padding: 3px 5px 3px 8px;
|
||||
border-top: 1px dotted #bfbfbf;
|
||||
}
|
||||
|
||||
li.imjs-msg-b > span {
|
||||
color: #ff0000;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
li.imjs-msg-a > span {
|
||||
color: #0099ff;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
li.imjs-msg-old {
|
||||
opacity: 0.4;
|
||||
}
|
||||
/* [end] Message log */
|
||||
|
||||
/* [begin] Message Log Messages */
|
||||
ul.imjs-msglog li ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 11px;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
ul.imjs-msglog li ul span {
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
color: #bcbcbc;
|
||||
}
|
||||
|
||||
li.imjs-msg-a ul p, li.imjs-msg-b ul p, li.imjs-date ul p {
|
||||
margin: 0;
|
||||
}
|
||||
/* [end] Message Log Messages */
|
||||
|
||||
/* [begin] Input */
|
||||
textarea.imjs-input {
|
||||
font: 12px/14px Helvetica Neue, Helvetica, Arial, Calibri, Tahoma, Verdana, sans-serif;
|
||||
height: 16px;
|
||||
padding: 3px;
|
||||
margin: 0;
|
||||
width: 219px;
|
||||
border: solid #aaa;
|
||||
border-width: 1px 0 0 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
/* [end] Input */
|
||||
/* [end] Chatbox */
|
||||
|
||||
/* [begin] Messenger bar */
|
||||
ul#imjs-bar {
|
||||
display: block;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
width: 95%;
|
||||
background: #f0efed url(images/w.png) top left repeat-x;
|
||||
height: 25px;
|
||||
border: solid #cfceca;
|
||||
border-width: 1px 1px 0 1px;
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0 0 0 -47.5%;
|
||||
font: 12px/25px Helvetica Neue, Helvetica, Arial, Calibri, Tahoma, Verdana, sans-serif;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
/* [begin] Generic bar item */
|
||||
ul#imjs-bar > li {
|
||||
position: relative;
|
||||
float: right;
|
||||
width: 161px;
|
||||
border-left: 1px solid #cecece;
|
||||
padding: 0 10px;
|
||||
cursor: pointer;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
}
|
||||
|
||||
ul#imjs-bar > li:hover {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
ul#imjs-bar > li .imjs-tab-text strong {
|
||||
position: relative;
|
||||
color: #00cc00;
|
||||
font-size: 28px;
|
||||
line-height: 19px;
|
||||
top: 6px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
ul#imjs-bar > li.imjs-offline .imjs-tab-text strong {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
ul#imjs-bar > li.imjs-away .imjs-tab-text strong {
|
||||
color: #df9b00;
|
||||
}
|
||||
|
||||
ul#imjs-bar > li.imjs-selected {
|
||||
text-shadow: 0 1px 0 #eaeaea;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
margin: -1px 0 0;
|
||||
border: solid #444;
|
||||
border-width: 0 1px 1px 1px;
|
||||
width: 160px;
|
||||
line-height: 23px;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
ul#imjs-bar > li.imjs-selected .imjs-tab-text {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
ul#imjs-bar > li.imjs-selected .imjs-tab-text strong {
|
||||
line-height: 17px;
|
||||
}
|
||||
|
||||
ul#imjs-bar > li.imjs-selected .imjs-tab-text a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
ul#imjs-bar > li.imjs-selected > .imjs-chatbox {
|
||||
border-color: #444;
|
||||
border-bottom: 0;
|
||||
padding-bottom: 1px;
|
||||
background-image: url(images/bottom.png);
|
||||
background-position: left bottom;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
ul#imjs-bar > li.imjs-selected > #imjs-friends-panel.imjs-chatbox {
|
||||
background-repeat: repeat-x;
|
||||
background-position: -45px bottom;
|
||||
}
|
||||
|
||||
/* [begin] Generic bar close */
|
||||
ul#imjs-bar > li .imjs-tab-text a {
|
||||
float: right;
|
||||
text-decoration: none;
|
||||
display: none;
|
||||
width: 10px;
|
||||
height: 0;
|
||||
padding-top: 10px;
|
||||
overflow: hidden;
|
||||
margin-top: 7.5px;
|
||||
background: url(images/closemin.png) 0 0 no-repeat;
|
||||
}
|
||||
|
||||
ul#imjs-bar > li:hover .imjs-tab-text a {
|
||||
display: inline;
|
||||
}
|
||||
/* [end] Generic bar close */
|
||||
/* [end] Generic bar item */
|
||||
|
||||
/* [begin] Bar scrolling buttons */
|
||||
ul#imjs-bar > li.imjs-scroll {
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
font-size: 9px;
|
||||
font-weight: 700;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
ul#imjs-bar li#imjs-scroll-left {
|
||||
padding: 1px 6px 0 4px;
|
||||
background-image: url(images/sl.png);
|
||||
background-position: 5px center;
|
||||
}
|
||||
|
||||
ul#imjs-bar li#imjs-scroll-right {
|
||||
padding: 1px 5px 0;
|
||||
background-image: url(images/sr.png);
|
||||
background-position: 20px center;
|
||||
}
|
||||
/* [end] Bar scrolling buttons */
|
||||
|
||||
/* [begin] Notification icon */
|
||||
span.imjs-notification {
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
right: -9px;
|
||||
top: -12px;
|
||||
padding: 2px;
|
||||
line-height: 16px;
|
||||
background: #eb2121;
|
||||
color: #fff;
|
||||
text-shadow: none;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
}
|
||||
/* [end] Notification icon */
|
||||
|
||||
/* [begin] Tooltip */
|
||||
span.imjs-tooltip {
|
||||
display: none;
|
||||
position: absolute;
|
||||
padding-bottom: 5px;
|
||||
margin: 0 0 3px 6px;
|
||||
left: -10000px;
|
||||
background: url(images/tooltip.png) right bottom no-repeat;
|
||||
color: #fff;
|
||||
text-shadow: none;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
span.imjs-tooltip p {
|
||||
font: 11px/18px Helvetica Neue, Helvetica, Arial, Calibri, Tahoma, Verdana, sans-serif;
|
||||
margin: 0;
|
||||
padding: 2px 6px;
|
||||
background: #000;
|
||||
max-width: 200px;
|
||||
}
|
||||
/* [end] Tooltip */
|
||||
|
||||
/* [begin] Friends list button */
|
||||
ul#imjs-bar > li#imjs-friends.imjs-not-connected,
|
||||
ul#imjs-bar > li#imjs-friends.not-connected:hover {
|
||||
width: 10px;
|
||||
background-image: url(images/error.png);
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
ul#imjs-bar > li#imjs-friends.imjs-not-connected span.imjs-tab-text {
|
||||
margin-left: -10000px;
|
||||
}
|
||||
|
||||
li#imjs-friends .imjs-tab-text span {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
li#imjs-friends .imjs-tab-text span > span {
|
||||
color: #222;
|
||||
font-weight: 700;
|
||||
}
|
||||
/* [end] Friends list button */
|
||||
/* [end] Messenger bar */
|
||||
|
||||
/* [begin] Friends list */
|
||||
div#imjs-friends-panel {
|
||||
background: #fff;
|
||||
width: 200px;
|
||||
right: auto;
|
||||
left: -1px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
div#imjs-friends-panel div.imjs-header {
|
||||
width: 190px;
|
||||
}
|
||||
|
||||
div#imjs-friends-panel a.imjs-minimize {
|
||||
width: 194px;
|
||||
}
|
||||
|
||||
div#imjs-friends-panel a.imjs-minimize:active {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
ul#imjs-friends-list {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font: 12px/25px Helvetica Neue, Helvetica, Arial, Calibri, Tahoma, Verdana, sans-serif;
|
||||
max-height: 300px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
ul#imjs-friends-list li, ul.imjs-friend-group li {
|
||||
width: 200px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
span.imjs-friend-group-header {
|
||||
display: block;
|
||||
padding: 0 0 0 5px;
|
||||
width: 195px;
|
||||
font-weight: 700;
|
||||
border-top: 1px solid #aaa;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
li.imjs-friend-group ul {
|
||||
margin: 0 0 5px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li.imjs-friend-group ul li {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
li.imjs-friend-group ul li:hover {
|
||||
background: #0055aa;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
li.imjs-friend-group ul li > strong {
|
||||
position: relative;
|
||||
color: #00cc00;
|
||||
font-size: 28px;
|
||||
line-height: 19px;
|
||||
top: 6px;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
li.imjs-friend-group ul li.imjs-offline > strong {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
li.imjs-friend-group ul li.imjs-away > strong {
|
||||
color: #df9b00;
|
||||
}
|
||||
|
||||
li.imjs-friend-group ul li.imjs-selected {
|
||||
background: #686868;
|
||||
color: #eee;
|
||||
font-weight: 700;
|
||||
text-shadow: 0 1px 0 #333;
|
||||
}
|
||||
|
||||
div#imjs-friends-panel form, div#imjs-friends-panel form p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
input#imjs-search-friends {
|
||||
font: 12px/14px Helvetica Neue, Helvetica, Arial, Calibri, Tahoma, Verdana, sans-serif;
|
||||
height: 16px;
|
||||
width: 194px;
|
||||
padding: 6px 3px 3px;
|
||||
margin: 0;
|
||||
border: solid #aaa;
|
||||
border-width: 1px 0 0 0;
|
||||
color: #aaa;
|
||||
}
|
||||
/* [end] Friends list */
|
||||
|
||||
/* [begin] Login/Registration Forms */
|
||||
div#imjs-lr form {
|
||||
background: #F0EFED url(images/w.png) repeat-x;
|
||||
border: 1px solid #cfceca;
|
||||
max-width: 220px;
|
||||
padding: 5px 5px 10px 8px;
|
||||
overflow: auto;
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
}
|
||||
|
||||
div#imjs-lr .error {
|
||||
font: 700 12px/18px Helvetica Neue, Helvetica, Arial, Calibri, Tahoma, Verdana, sans-serif;
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
div#imjs-lr form fieldset {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div#imjs-lr form h2 {
|
||||
font: 700 20px/24px Helvetica Neue, Helvetica, Arial, Calibri, Tahoma, Verdana, sans-serif;
|
||||
margin: 0;
|
||||
padding: 7px 0 0 2px;
|
||||
color: #555;
|
||||
text-shadow: 0 1px 0px #fff;
|
||||
}
|
||||
|
||||
div#imjs-lr form label {
|
||||
display: block;
|
||||
font: 700 12px/14px Helvetica Neue, Helvetica, Arial, Calibri, Tahoma, Verdana, sans-serif;
|
||||
color: #7B7A79;
|
||||
}
|
||||
|
||||
div#imjs-lr form input {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
div#imjs-lr form input.imjs-lr-error, div#imjs-lr form input.imjs-lr-error:focus {
|
||||
margin: -1px;
|
||||
border: 2px solid #ff1111;
|
||||
}
|
||||
|
||||
div#imjs-lr form button {
|
||||
float: right;
|
||||
background: #f4f3f1;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
div#imjs-lr form input, div#imjs-lr form button {
|
||||
border: 1px solid #ddd;
|
||||
color: #000;
|
||||
padding: 4px 3px;
|
||||
font: 16px/20px Helvetica Neue, Helvetica, Arial, Calibri, Tahoma, Verdana, sans-serif;
|
||||
-moz-border-radius: 2px;
|
||||
-webkit-border-radius: 2px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div#imjs-lr form p {
|
||||
padding-left: 2px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
div#imjs-lr form input:focus, div#imjs-lr form button:focus {
|
||||
position: relative;
|
||||
border: 2px solid #999;
|
||||
margin: -1px;
|
||||
}
|
||||
|
||||
p.imjs-submit {
|
||||
width: 207px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
form#imjs-login {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
/* [end] Login/Registration Forms */
|
|
@ -0,0 +1,132 @@
|
|||
<!-- Ajax IM Instant Messenger, Footer Bar -->
|
||||
<ul id="imjs-bar">
|
||||
<li id="imjs-friends" class="imjs-not-connected">
|
||||
<span class="imjs-tab-text"><strong>•</strong> Friends <span>(<span>0</span>)</span></span>
|
||||
<div id="imjs-friends-panel" class="imjs-chatbox">
|
||||
<div class="imjs-header">
|
||||
<span>{username}</span>
|
||||
<a href="#" class="imjs-minimize">_</a>
|
||||
</div>
|
||||
<ul id="imjs-friends-list">
|
||||
<li class="imjs-friend-group imjs-default">
|
||||
<span class="imjs-friend-group-header">{group}</span>
|
||||
<ul>
|
||||
<li class="imjs-friend imjs-default"><strong>•</strong> {username}</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<form>
|
||||
<p><input type="text" id="imjs-search-friends" value="Search" /></p>
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
<li id="imjs-scroll-right" class="imjs-scroll">{count}</li>
|
||||
<li class="imjs-tab imjs-default">
|
||||
<span class="imjs-tab-text"><strong>•</strong> {label} <a href="#" class="imjs-close">x</a></span>
|
||||
<span class="imjs-notification">{count}</span>
|
||||
<form class="imjs-chatbox">
|
||||
<div>
|
||||
<div class="imjs-header">
|
||||
<span>{username}</span>
|
||||
<a href="#" class="imjs-close">x</a>
|
||||
<a href="#" class="imjs-minimize">_</a>
|
||||
</div>
|
||||
<ul class="imjs-msglog">
|
||||
<li class="imjs-date">
|
||||
<ul>
|
||||
<li>
|
||||
<span class="imjs-msg-time">hh:MM TT •</span>
|
||||
<p class="imjs-date-date">ddd, mmmm d, yyyy</p>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="imjs-error">
|
||||
<ul>
|
||||
<li>
|
||||
<span class="imjs-msg-time">hh:MM TT •</span>
|
||||
<p class="imjs-error-error">ddd, mmmm d, yyyy</p>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="imjs-msg-a">
|
||||
<span>{username}</span>
|
||||
<ul class="imjs-msg-a-container">
|
||||
<li class="imjs-msg-a-msg">
|
||||
<span class="imjs-msg-time">hh:MM TT •</span>
|
||||
<p>{message}</p>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="imjs-msg-b">
|
||||
<span>{username}</span>
|
||||
<ul class="imjs-msg-b-container">
|
||||
<li class="imjs-msg-b-msg">
|
||||
<span class="imjs-msg-time">hh:MM TT •</span>
|
||||
<p>{message}</p>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<textarea class="imjs-input"></textarea>
|
||||
</div>
|
||||
</form>
|
||||
</li>
|
||||
<li id="imjs-scroll-left" class="imjs-scroll">{count}</li>
|
||||
</ul>
|
||||
<span class="imjs-tooltip"><p>{tip}</p></span>
|
||||
|
||||
<!-- Ajax IM Instant Messenger, Login/Registration Form -->
|
||||
<div id="imjs-lr">
|
||||
<form id="imjs-login">
|
||||
<fieldset>
|
||||
<h2>Login</h2>
|
||||
|
||||
<p class="error"></p>
|
||||
|
||||
<p>
|
||||
<label for="imjs-login-username">Username</label>
|
||||
<input type="text" name="username" id="imjs-login-username" />
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="imjs-login-password">Password</label>
|
||||
<input type="password" name="password" id="imjs-login-password" />
|
||||
</p>
|
||||
|
||||
<p class="imjs-submit">
|
||||
<button id="imjs-login-submit">Sign In</button>
|
||||
</p>
|
||||
</fieldset>
|
||||
|
||||
<p id="imjs-logged-in">Signed in as <strong>{username}</strong>. <a href="#logout">Sign Out</a>.</p>
|
||||
</form>
|
||||
|
||||
<form id="imjs-register">
|
||||
<fieldset>
|
||||
<h2>Register</h2>
|
||||
|
||||
<p class="error"></p>
|
||||
|
||||
<p>
|
||||
<label for="imjs-register-username">Username</label>
|
||||
<input type="text" name="username" id="imjs-register-username" />
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="imjs-register-password">Password</label>
|
||||
<input type="password" name="password" id="imjs-register-password" />
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="imjs-register-cpassword">Confirm Password</label>
|
||||
<input type="password" name="cpassword" id="imjs-register-cpassword" />
|
||||
</p>
|
||||
|
||||
<p class="imjs-submit">
|
||||
<button id="imjs-register-submit">Register</button>
|
||||
</p>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
|
@ -0,0 +1,23 @@
|
|||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src="/web_chat/static/lib/AjaxIM/js/jquery-1.3.2.js"></script>
|
||||
<script type="text/javascript" src="/web_chat/static/lib/AjaxIM/js/jquery.jsonp-1.1.0.js"></script>
|
||||
<script type="text/javascript" src="/web_chat/static/lib/AjaxIM/js/jquery.jstore-all-min.js"></script>
|
||||
<script type="text/javascript" src="/web_chat/static/lib/AjaxIM/js/jquery.md5.js"></script>
|
||||
<script type="text/javascript" src="/web_chat/static/lib/AjaxIM/js/im.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
var AjaxIM, AjaxIMLoadedFunction;
|
||||
$(function() {
|
||||
AjaxIM.init({
|
||||
pollServer: '/web_chat/pollserver',
|
||||
theme: '/web_chat/static/lib/AjaxIM/themes/default',
|
||||
flashStorage: '/web_chat/static/lib/AjaxIM/js/jStore.Flash.html'
|
||||
});
|
||||
AjaxIM.client.login();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -19,6 +19,25 @@ import nonliterals
|
|||
import xmlrpctimeout
|
||||
import logging
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# Globals
|
||||
#-----------------------------------------------------------
|
||||
|
||||
path_root = os.path.dirname(os.path.dirname(os.path.normpath(__file__)))
|
||||
path_addons = os.path.join(path_root, 'addons')
|
||||
cherrypy_root = None
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# Per Database Globals (might move into a pool if needed)
|
||||
#-----------------------------------------------------------
|
||||
|
||||
applicationsession = {}
|
||||
addons_module = {}
|
||||
addons_manifest = {}
|
||||
controllers_class = {}
|
||||
controllers_object = {}
|
||||
controllers_path = {}
|
||||
|
||||
#----------------------------------------------------------
|
||||
# OpenERP Client Library
|
||||
#----------------------------------------------------------
|
||||
|
@ -269,9 +288,13 @@ class JsonRequest(object):
|
|||
"""
|
||||
|
||||
def parse(self, request):
|
||||
self.request = request
|
||||
self.params = request.get("params", {})
|
||||
self.applicationsession = applicationsession
|
||||
self.httpsession_id = "cookieid"
|
||||
self.httpsession = cherrypy.session
|
||||
self.session_id = self.params.pop("session_id", None) or uuid.uuid4().hex
|
||||
self.session = cherrypy.session.setdefault(self.session_id, OpenERPSession())
|
||||
self.session = self.httpsession.setdefault(self.session_id, OpenERPSession())
|
||||
self.context = self.params.pop('context', None)
|
||||
return self.params
|
||||
|
||||
|
@ -290,16 +313,16 @@ class JsonRequest(object):
|
|||
:returns: a string-encoded JSON-RPC2 reply
|
||||
:rtype: bytes
|
||||
'''
|
||||
# Read POST content or POST Form Data named "request"
|
||||
if requestf:
|
||||
request = simplejson.load(
|
||||
requestf, object_hook=nonliterals.non_literal_decoder)
|
||||
request = simplejson.load(requestf, object_hook=nonliterals.non_literal_decoder)
|
||||
else:
|
||||
request = simplejson.loads(
|
||||
request, object_hook=nonliterals.non_literal_decoder)
|
||||
request = simplejson.loads(request, object_hook=nonliterals.non_literal_decoder)
|
||||
try:
|
||||
print "--> %s.%s %s" % (controller.__class__.__name__, method.__name__, request)
|
||||
error = None
|
||||
result = method(controller, self, **self.parse(request))
|
||||
self.parse(request)
|
||||
result = method(controller, self, **self.params)
|
||||
except OpenERPUnboundException:
|
||||
error = {
|
||||
'code': 100,
|
||||
|
@ -340,8 +363,7 @@ class JsonRequest(object):
|
|||
print "<--", response
|
||||
print
|
||||
|
||||
content = simplejson.dumps(
|
||||
response, cls=nonliterals.NonLiteralEncoder)
|
||||
content = simplejson.dumps(response, cls=nonliterals.NonLiteralEncoder)
|
||||
cherrypy.response.headers['Content-Type'] = 'application/json'
|
||||
cherrypy.response.headers['Content-Length'] = len(content)
|
||||
return content
|
||||
|
@ -349,47 +371,38 @@ class JsonRequest(object):
|
|||
def jsonrequest(f):
|
||||
@cherrypy.expose
|
||||
@functools.wraps(f)
|
||||
def json_handler(self):
|
||||
return JsonRequest().dispatch(self, f, requestf=cherrypy.request.body)
|
||||
def json_handler(controller):
|
||||
return JsonRequest().dispatch(controller, f, requestf=cherrypy.request.body)
|
||||
|
||||
return json_handler
|
||||
|
||||
class HttpRequest(object):
|
||||
""" Regular GET/POST request
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
# result may be filled, it's content will be updated by the return
|
||||
# value of the dispatched function if it's a dict
|
||||
def dispatch(self, controller, f, request, **kw):
|
||||
self.request = request
|
||||
self.applicationsession = applicationsession
|
||||
self.httpsession_id = "cookieid"
|
||||
self.httpsession = cherrypy.session
|
||||
self.result = ""
|
||||
|
||||
def dispatch(self, controller, f, request):
|
||||
print "GET/POST --> %s.%s %s" % (controller.__class__.__name__, f.__name__, request)
|
||||
r = f(controller, self, request)
|
||||
print "GET/POST --> %s.%s %s %r" % (controller.__class__.__name__, f.__name__, request, kw)
|
||||
r = f(controller, self, **kw)
|
||||
print "<--", r
|
||||
print
|
||||
return r
|
||||
|
||||
def httprequest(f):
|
||||
# check cleaner wrapping:
|
||||
# functools.wraps(f)(lambda x: JsonRequest().dispatch(x, f))
|
||||
l = lambda self, request: HttpRequest().dispatch(self, f, request)
|
||||
l.exposed = 1
|
||||
return l
|
||||
def http_handler(self,*l, **kw):
|
||||
return HttpRequest().dispatch(self, f, cherrypy.request, **kw)
|
||||
http_handler.exposed = 1
|
||||
return http_handler
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# Cherrypy stuff
|
||||
#-----------------------------------------------------------
|
||||
|
||||
path_root = os.path.dirname(os.path.dirname(os.path.normpath(__file__)))
|
||||
path_addons = os.path.join(path_root, 'addons')
|
||||
cherrypy_root = None
|
||||
|
||||
# globals might move into a pool if needed
|
||||
addons_module = {}
|
||||
addons_manifest = {}
|
||||
controllers_class = {}
|
||||
controllers_object = {}
|
||||
controllers_path = {}
|
||||
|
||||
class ControllerType(type):
|
||||
def __init__(cls, name, bases, attrs):
|
||||
super(ControllerType, cls).__init__(name, bases, attrs)
|
||||
|
|