[merge]
bzr revid: nicolas.vanhoren@openerp.com-20120217101731-3g9hrhs65qb32pkv
|
@ -1,7 +1,8 @@
|
|||
import common
|
||||
import controllers
|
||||
import logging
|
||||
|
||||
from . import common
|
||||
from . import controllers
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class Options(object):
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
"static/lib/jquery.superfish/js/hoverIntent.js",
|
||||
"static/lib/jquery.superfish/js/superfish.js",
|
||||
"static/lib/jquery.ui/js/jquery-ui-1.8.17.custom.min.js",
|
||||
"static/lib/jquery.ui/js/jquery-ui-timepicker-addon.js",
|
||||
"static/lib/jquery.ui.timepicker/js/jquery-ui-timepicker-addon.js",
|
||||
"static/lib/jquery.ui.notify/js/jquery.notify.js",
|
||||
"static/lib/jquery.deferred-queue/jquery.deferred-queue.js",
|
||||
"static/lib/jquery.scrollTo/jquery.scrollTo-min.js",
|
||||
|
@ -56,6 +56,7 @@
|
|||
'css' : [
|
||||
"static/lib/jquery.superfish/css/superfish.css",
|
||||
"static/lib/jquery.ui/css/smoothness/jquery-ui-1.8.17.custom.css",
|
||||
"static/lib/jquery.ui.timepicker/css/jquery-ui-timepicker-addon.css",
|
||||
"static/lib/jquery.ui.notify/css/ui.notify.css",
|
||||
"static/lib/jquery.tipsy/tipsy.css",
|
||||
"static/src/css/base.css",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/python
|
||||
import http
|
||||
import nonliterals
|
||||
import release
|
||||
import session
|
||||
import xml2json
|
||||
from . import http
|
||||
from . import nonliterals
|
||||
from . import release
|
||||
from . import session
|
||||
from . import xml2json
|
||||
|
|
|
@ -25,9 +25,9 @@ import werkzeug.utils
|
|||
import werkzeug.wrappers
|
||||
import werkzeug.wsgi
|
||||
|
||||
import nonliterals
|
||||
import session
|
||||
import openerplib
|
||||
from . import nonliterals
|
||||
from . import session
|
||||
from . import openerplib
|
||||
|
||||
__all__ = ['Root', 'jsonrequest', 'httprequest', 'Controller',
|
||||
'WebRequest', 'JsonRequest', 'HttpRequest']
|
||||
|
@ -357,11 +357,13 @@ def session_context(request, storage_path, session_cookie='sessionid'):
|
|||
# session id, and are generally noise
|
||||
removed_sessions = set()
|
||||
for key, value in request.session.items():
|
||||
if (isinstance(value, session.OpenERPSession)
|
||||
and not value._uid
|
||||
and not value.jsonp_requests
|
||||
and value._creation_time + (60*5) < time.time() # FIXME do not use a fixed value
|
||||
):
|
||||
if not isinstance(value, session.OpenERPSession):
|
||||
continue
|
||||
if getattr(value, '_suicide', False) or (
|
||||
not value._uid
|
||||
and not value.jsonp_requests
|
||||
# FIXME do not use a fixed value
|
||||
and value._creation_time + (60*5) < time.time()):
|
||||
_logger.debug('remove session %s', key)
|
||||
removed_sessions.add(key)
|
||||
del request.session[key]
|
||||
|
|
|
@ -28,5 +28,5 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from main import *
|
||||
from .main import *
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import logging
|
|||
import time
|
||||
import openerplib
|
||||
|
||||
import nonliterals
|
||||
from . import nonliterals
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
#----------------------------------------------------------
|
||||
|
@ -36,6 +36,7 @@ class OpenERPSession(object):
|
|||
self._uid = False
|
||||
self._login = False
|
||||
self._password = False
|
||||
self._suicide = False
|
||||
self.context = {}
|
||||
self.contexts_store = {}
|
||||
self.domains_store = {}
|
||||
|
|
|
@ -1 +1 @@
|
|||
import main
|
||||
from . import main
|
||||
|
|
|
@ -5,8 +5,10 @@ import base64
|
|||
import csv
|
||||
import glob
|
||||
import itertools
|
||||
import logging
|
||||
import operator
|
||||
import datetime
|
||||
import hashlib
|
||||
import os
|
||||
import re
|
||||
import simplejson
|
||||
|
@ -19,6 +21,7 @@ from cStringIO import StringIO
|
|||
|
||||
import babel.messages.pofile
|
||||
import werkzeug.utils
|
||||
import werkzeug.wrappers
|
||||
try:
|
||||
import xlwt
|
||||
except ImportError:
|
||||
|
@ -34,21 +37,22 @@ openerpweb = common.http
|
|||
|
||||
def concat_xml(file_list):
|
||||
"""Concatenate xml files
|
||||
return (concat,timestamp)
|
||||
concat: concatenation of file content
|
||||
timestamp: max(os.path.getmtime of file_list)
|
||||
|
||||
:param list(str) file_list: list of files to check
|
||||
:returns: (concatenation_result, checksum)
|
||||
:rtype: (str, str)
|
||||
"""
|
||||
checksum = hashlib.new('sha1')
|
||||
if not file_list:
|
||||
return '', None
|
||||
return '', checksum.hexdigest()
|
||||
|
||||
root = None
|
||||
files_timestamp = 0
|
||||
for fname in file_list:
|
||||
ftime = os.path.getmtime(fname)
|
||||
if ftime > files_timestamp:
|
||||
files_timestamp = ftime
|
||||
|
||||
xml = ElementTree.parse(fname).getroot()
|
||||
with open(fname, 'rb') as fp:
|
||||
contents = fp.read()
|
||||
checksum.update(contents)
|
||||
fp.seek(0)
|
||||
xml = ElementTree.parse(fp).getroot()
|
||||
|
||||
if root is None:
|
||||
root = ElementTree.Element(xml.tag)
|
||||
|
@ -57,17 +61,21 @@ def concat_xml(file_list):
|
|||
|
||||
for child in xml.getchildren():
|
||||
root.append(child)
|
||||
return ElementTree.tostring(root, 'utf-8'), files_timestamp
|
||||
return ElementTree.tostring(root, 'utf-8'), checksum.hexdigest()
|
||||
|
||||
|
||||
def concat_files(file_list, reader=None, intersperse=""):
|
||||
""" Concatenate file content
|
||||
return (concat,timestamp)
|
||||
concat: concatenation of file content, read by `reader`
|
||||
timestamp: max(os.path.getmtime of file_list)
|
||||
""" Concatenates contents of all provided files
|
||||
|
||||
:param list(str) file_list: list of files to check
|
||||
:param function reader: reading procedure for each file
|
||||
:param str intersperse: string to intersperse between file contents
|
||||
:returns: (concatenation_result, checksum)
|
||||
:rtype: (str, str)
|
||||
"""
|
||||
checksum = hashlib.new('sha1')
|
||||
if not file_list:
|
||||
return '', None
|
||||
return '', checksum.hexdigest()
|
||||
|
||||
if reader is None:
|
||||
def reader(f):
|
||||
|
@ -75,19 +83,18 @@ def concat_files(file_list, reader=None, intersperse=""):
|
|||
return fp.read()
|
||||
|
||||
files_content = []
|
||||
files_timestamp = 0
|
||||
for fname in file_list:
|
||||
ftime = os.path.getmtime(fname)
|
||||
if ftime > files_timestamp:
|
||||
files_timestamp = ftime
|
||||
contents = reader(fname)
|
||||
checksum.update(contents)
|
||||
files_content.append(contents)
|
||||
|
||||
files_content.append(reader(fname))
|
||||
files_concat = intersperse.join(files_content)
|
||||
return files_concat,files_timestamp
|
||||
return files_concat, checksum.hexdigest()
|
||||
|
||||
html_template = """<!DOCTYPE html>
|
||||
<html style="height: 100%%">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<title>OpenERP</title>
|
||||
<link rel="shortcut icon" href="/web/static/src/img/favicon.ico" type="image/x-icon"/>
|
||||
|
@ -149,10 +156,51 @@ class WebClient(openerpweb.Controller):
|
|||
def qweblist(self, req, mods=None):
|
||||
return self.manifest_list(req, mods, 'qweb')
|
||||
|
||||
def get_last_modified(self, files):
|
||||
""" Returns the modification time of the most recently modified
|
||||
file provided
|
||||
|
||||
:param list(str) files: names of files to check
|
||||
:return: most recent modification time amongst the fileset
|
||||
:rtype: datetime.datetime
|
||||
"""
|
||||
files = list(files)
|
||||
if files:
|
||||
return max(datetime.datetime.fromtimestamp(os.path.getmtime(f))
|
||||
for f in files)
|
||||
return datetime.datetime(1970, 1, 1)
|
||||
|
||||
def make_conditional(self, req, response, last_modified=None, etag=None):
|
||||
""" Makes the provided response conditional based upon the request,
|
||||
and mandates revalidation from clients
|
||||
|
||||
Uses Werkzeug's own :meth:`ETagResponseMixin.make_conditional`, after
|
||||
setting ``last_modified`` and ``etag`` correctly on the response object
|
||||
|
||||
:param req: OpenERP request
|
||||
:type req: web.common.http.WebRequest
|
||||
:param response: Werkzeug response
|
||||
:type response: werkzeug.wrappers.Response
|
||||
:param datetime.datetime last_modified: last modification date of the response content
|
||||
:param str etag: some sort of checksum of the content (deep etag)
|
||||
:return: the response object provided
|
||||
:rtype: werkzeug.wrappers.Response
|
||||
"""
|
||||
response.cache_control.must_revalidate = True
|
||||
response.cache_control.max_age = 0
|
||||
if last_modified:
|
||||
response.last_modified = last_modified
|
||||
if etag:
|
||||
response.set_etag(etag)
|
||||
return response.make_conditional(req.httprequest)
|
||||
|
||||
@openerpweb.httprequest
|
||||
def css(self, req, mods=None):
|
||||
|
||||
files = list(self.manifest_glob(req, mods, 'css'))
|
||||
last_modified = self.get_last_modified(f[0] for f in files)
|
||||
if req.httprequest.if_modified_since and req.httprequest.if_modified_since >= last_modified:
|
||||
return werkzeug.wrappers.Response(status=304)
|
||||
|
||||
file_map = dict(files)
|
||||
|
||||
rx_import = re.compile(r"""@import\s+('|")(?!'|"|/|https?://)""", re.U)
|
||||
|
@ -181,24 +229,37 @@ class WebClient(openerpweb.Controller):
|
|||
)
|
||||
return data
|
||||
|
||||
content,timestamp = concat_files((f[0] for f in files), reader)
|
||||
# TODO use timestamp to set Last mofified date and E-tag
|
||||
return req.make_response(content, [('Content-Type', 'text/css')])
|
||||
content, checksum = concat_files((f[0] for f in files), reader)
|
||||
|
||||
return self.make_conditional(
|
||||
req, req.make_response(content, [('Content-Type', 'text/css')]),
|
||||
last_modified, checksum)
|
||||
|
||||
@openerpweb.httprequest
|
||||
def js(self, req, mods=None):
|
||||
files = [f[0] for f in self.manifest_glob(req, mods, 'js')]
|
||||
content, timestamp = concat_files(files, intersperse=';')
|
||||
# TODO use timestamp to set Last mofified date and E-tag
|
||||
return req.make_response(content, [('Content-Type', 'application/javascript')])
|
||||
last_modified = self.get_last_modified(files)
|
||||
if req.httprequest.if_modified_since and req.httprequest.if_modified_since >= last_modified:
|
||||
return werkzeug.wrappers.Response(status=304)
|
||||
|
||||
content, checksum = concat_files(files, intersperse=';')
|
||||
|
||||
return self.make_conditional(
|
||||
req, req.make_response(content, [('Content-Type', 'application/javascript')]),
|
||||
last_modified, checksum)
|
||||
|
||||
@openerpweb.httprequest
|
||||
def qweb(self, req, mods=None):
|
||||
files = [f[0] for f in self.manifest_glob(req, mods, 'qweb')]
|
||||
content,timestamp = concat_xml(files)
|
||||
# TODO use timestamp to set Last mofified date and E-tag
|
||||
return req.make_response(content, [('Content-Type', 'text/xml')])
|
||||
last_modified = self.get_last_modified(files)
|
||||
if req.httprequest.if_modified_since and req.httprequest.if_modified_since >= last_modified:
|
||||
return werkzeug.wrappers.Response(status=304)
|
||||
|
||||
content,checksum = concat_xml(files)
|
||||
|
||||
return self.make_conditional(
|
||||
req, req.make_response(content, [('Content-Type', 'text/xml')]),
|
||||
last_modified, checksum)
|
||||
|
||||
@openerpweb.httprequest
|
||||
def home(self, req, s_action=None, **kw):
|
||||
|
@ -554,6 +615,10 @@ class Session(openerpweb.Controller):
|
|||
req.session.assert_valid()
|
||||
return None
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def destroy(self, req):
|
||||
req.session._suicide = True
|
||||
|
||||
def eval_context_and_domain(session, context, domain=None):
|
||||
e_context = session.eval_context(context)
|
||||
# should we give the evaluated context as an evaluation context to the domain?
|
||||
|
@ -676,15 +741,33 @@ def fix_view_modes(action):
|
|||
class Menu(openerpweb.Controller):
|
||||
_cp_path = "/web/menu"
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def load(self, req):
|
||||
return {'data': self.do_load(req)}
|
||||
|
||||
def do_load_level(self, req, parent_id=False):
|
||||
Menus = req.session.model('ir.ui.menu')
|
||||
context = req.session.eval_context(req.context)
|
||||
menu_ids = Menus.search([('parent_id','=',parent_id)], 0, False, False, context)
|
||||
menu_items = Menus.read(menu_ids, ['name', 'sequence', 'parent_id'], context)
|
||||
for menu in menu_items:
|
||||
menu['children'] = self.do_load_level(req, parent_id = menu['id'])
|
||||
return menu_items
|
||||
@openerpweb.jsonrequest
|
||||
def get_user_roots(self, req):
|
||||
return self.do_get_user_roots(req)
|
||||
|
||||
def do_get_user_roots(self, req):
|
||||
""" Return all root menu ids visible for the session user.
|
||||
|
||||
:param req: A request object, with an OpenERP session attribute
|
||||
:type req: < session -> OpenERPSession >
|
||||
:return: the root menu ids
|
||||
:rtype: list(int)
|
||||
"""
|
||||
s = req.session
|
||||
context = s.eval_context(req.context)
|
||||
Menus = s.model('ir.ui.menu')
|
||||
# If a menu action is defined use its domain to get the root menu items
|
||||
user_menu_id = s.model('res.users').read([s._uid], ['menu_id'], context)[0]['menu_id']
|
||||
if user_menu_id:
|
||||
menu_domain = s.model('ir.actions.act_window').read([user_menu_id[0]], ['domain'], context)[0]['domain']
|
||||
menu_domain = ast.literal_eval(menu_domain)
|
||||
else:
|
||||
menu_domain = [('parent_id', '=', False)]
|
||||
return Menus.search(menu_domain, 0, False, False, context)
|
||||
|
||||
def do_load(self, req):
|
||||
""" Loads all menu items (all applications and their sub-menus).
|
||||
|
@ -694,13 +777,38 @@ class Menu(openerpweb.Controller):
|
|||
:return: the menu root
|
||||
:rtype: dict('children': menu_nodes)
|
||||
"""
|
||||
root_children = self.do_load_level(req)
|
||||
root_menu = {'id': False, 'name': 'root', 'parent_id': [-1, ''], 'children': root_children}
|
||||
return root_menu
|
||||
context = req.session.eval_context(req.context)
|
||||
Menus = req.session.model('ir.ui.menu')
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def load(self, req):
|
||||
return {'data': self.do_load(req)}
|
||||
menu_roots = Menus.read(self.do_get_user_roots(req), ['name', 'sequence', 'parent_id'], context)
|
||||
menu_root = {'id': False, 'name': 'root', 'parent_id': [-1, ''], 'children' : menu_roots}
|
||||
|
||||
# menus are loaded fully unlike a regular tree view, cause there are a
|
||||
# limited number of items (752 when all 6.1 addons are installed)
|
||||
menu_ids = Menus.search([], 0, False, False, context)
|
||||
menu_items = Menus.read(menu_ids, ['name', 'sequence', 'parent_id'], context)
|
||||
# adds roots at the end of the sequence, so that they will overwrite
|
||||
# equivalent menu items from full menu read when put into id:item
|
||||
# mapping, resulting in children being correctly set on the roots.
|
||||
menu_items.extend(menu_roots)
|
||||
|
||||
# make a tree using parent_id
|
||||
menu_items_map = dict((menu_item["id"], menu_item) for menu_item in menu_items)
|
||||
for menu_item in menu_items:
|
||||
if menu_item['parent_id']:
|
||||
parent = menu_item['parent_id'][0]
|
||||
else:
|
||||
parent = False
|
||||
if parent in menu_items_map:
|
||||
menu_items_map[parent].setdefault(
|
||||
'children', []).append(menu_item)
|
||||
|
||||
# sort by sequence a tree using parent_id
|
||||
for menu_item in menu_items:
|
||||
menu_item.setdefault('children', []).sort(
|
||||
key=operator.itemgetter('sequence'))
|
||||
|
||||
return menu_root
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def action(self, req, menu_id):
|
||||
|
@ -743,21 +851,24 @@ class DataSet(openerpweb.Controller):
|
|||
context, domain = eval_context_and_domain(
|
||||
req.session, req.context, domain)
|
||||
|
||||
ids = Model.search(domain, 0, False, sort or False, context)
|
||||
# need to fill the dataset with all ids for the (domain, context) pair,
|
||||
# so search un-paginated and paginate manually before reading
|
||||
paginated_ids = ids[offset:(offset + limit if limit else None)]
|
||||
ids = Model.search(domain, offset or 0, limit or False, sort or False, context)
|
||||
if limit and len(ids) == limit:
|
||||
length = Model.search_count(domain, context)
|
||||
else:
|
||||
length = len(ids) + (offset or 0)
|
||||
if fields and fields == ['id']:
|
||||
# shortcut read if we only want the ids
|
||||
return {
|
||||
'ids': ids,
|
||||
'records': [{'id': id} for id in paginated_ids]
|
||||
'length': length,
|
||||
'records': [{'id': id} for id in ids]
|
||||
}
|
||||
|
||||
records = Model.read(paginated_ids, fields or False, context)
|
||||
records = Model.read(ids, fields or False, context)
|
||||
records.sort(key=lambda obj: ids.index(obj['id']))
|
||||
return {
|
||||
'ids': ids,
|
||||
'length': length,
|
||||
'records': records
|
||||
}
|
||||
|
||||
|
@ -1134,11 +1245,21 @@ class SearchView(View):
|
|||
|
||||
@openerpweb.jsonrequest
|
||||
def get_filters(self, req, model):
|
||||
logger = logging.getLogger(__name__ + '.SearchView.get_filters')
|
||||
Model = req.session.model("ir.filters")
|
||||
filters = Model.get_filters(model)
|
||||
for filter in filters:
|
||||
filter["context"] = req.session.eval_context(parse_context(filter["context"], req.session))
|
||||
filter["domain"] = req.session.eval_domain(parse_domain(filter["domain"], req.session))
|
||||
try:
|
||||
filter["context"] = req.session.eval_context(
|
||||
parse_context(filter["context"], req.session))
|
||||
filter["domain"] = req.session.eval_domain(
|
||||
parse_domain(filter["domain"], req.session))
|
||||
except Exception:
|
||||
logger.exception("Failed to parse custom filter %s in %s",
|
||||
filter['name'], model)
|
||||
filter['disabled'] = True
|
||||
del filter['context']
|
||||
del filter['domain']
|
||||
return filters
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
|
@ -1406,8 +1527,6 @@ class Export(View):
|
|||
if import_compat:
|
||||
if exclude and field_name in exclude:
|
||||
continue
|
||||
if 'function' in field:
|
||||
continue
|
||||
if field.get('readonly'):
|
||||
# If none of the field's states unsets readonly, skip the field
|
||||
if all(dict(attrs).get('readonly', True)
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
|
||||
Tipsy.prototype = {
|
||||
show: function() {
|
||||
$.fn.tipsy.clear();
|
||||
if (!this.$element.parent().length) {
|
||||
return;
|
||||
}
|
||||
var title = this.getTitle();
|
||||
if (title && this.enabled) {
|
||||
var $tip = this.tip();
|
||||
|
@ -175,6 +179,10 @@
|
|||
return this;
|
||||
|
||||
};
|
||||
|
||||
$.fn.tipsy.clear = function() {
|
||||
$('div.tipsy').stop().remove();
|
||||
}
|
||||
|
||||
$.fn.tipsy.defaults = {
|
||||
className: null,
|
||||
|
|
6
addons/web/static/lib/jquery.ui.timepicker/css/jquery-ui-timepicker-addon.css
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
.ui-timepicker-div .ui-widget-header { margin-bottom: 8px; }
|
||||
.ui-timepicker-div dl { text-align: left; }
|
||||
.ui-timepicker-div dl dt { height: 25px; margin-bottom: -25px; }
|
||||
.ui-timepicker-div dl dd { margin: 0 10px 10px 65px; }
|
||||
.ui-timepicker-div td { font-size: 90%; }
|
||||
.ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; }
|
|
@ -241,8 +241,8 @@ QWeb2.Engine = (function() {
|
|||
return true;
|
||||
},
|
||||
load_xml : function(s) {
|
||||
s = s.replace(/^\s*|\s*$/g, '');
|
||||
if (this.tools.trim(s)[0] === '<') {
|
||||
s = this.tools.trim(s);
|
||||
if (s.charAt(0) === '<') {
|
||||
return this.load_xml_string(s);
|
||||
} else {
|
||||
var req = this.get_xhr();
|
||||
|
@ -256,6 +256,9 @@ QWeb2.Engine = (function() {
|
|||
req.send(null);
|
||||
var xDoc = req.responseXML;
|
||||
if (xDoc) {
|
||||
if (!xDoc.documentElement) {
|
||||
throw new Error("QWeb2: This xml document has no root document : " + xDoc.responseText);
|
||||
}
|
||||
if (xDoc.documentElement.nodeName == "parsererror") {
|
||||
return this.tools.exception(xDoc.documentElement.childNodes[0].nodeValue);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
body { padding: 0; margin: 0; }
|
||||
body.openerp {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.openerp {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
font-size: 80%;
|
||||
font-family: Ubuntu, Helvetica, sans-serif;
|
||||
}
|
||||
|
@ -382,6 +385,14 @@ label.error {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
/* IE Hack - for IE < 9
|
||||
* Avoids footer to be placed statically at 100% cutting the middle of the views
|
||||
* */
|
||||
.openerp .oe-application-container {
|
||||
height: auto\9;
|
||||
min-height: 100%\9;
|
||||
}
|
||||
|
||||
/* Menu */
|
||||
.openerp .menu {
|
||||
height: 34px;
|
||||
|
@ -747,6 +758,7 @@ label.error {
|
|||
}
|
||||
.openerp .filter_label.enabled, .openerp .filter_icon.enabled {
|
||||
background: #aaa;
|
||||
filter: none;
|
||||
-moz-box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
-o-box-shadow: none;
|
||||
|
@ -1172,7 +1184,20 @@ label.error {
|
|||
|
||||
|
||||
/* Form */
|
||||
|
||||
.openerp .oe_form_button_save_dirty {
|
||||
display: none;
|
||||
}
|
||||
.openerp .oe_form_dirty > .oe_form_header > .oe_form_buttons > .oe_form_button_save {
|
||||
color: white;
|
||||
background: #dc5f59;
|
||||
background: -moz-linear-gradient(#dc5f59, #b33630);
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#dc5f59), to(#b33630));
|
||||
background: -webkit-linear-gradient(#dc5f59, #b33630);
|
||||
-moz-box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
-box-shadow: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
.openerp .oe_form_frame_cell input[type="checkbox"] {
|
||||
margin-top: 3px;
|
||||
vertical-align: middle;
|
||||
|
@ -1208,6 +1233,11 @@ label.error {
|
|||
.openerp td.oe_form_frame_cell {
|
||||
padding: 2px;
|
||||
position: relative;
|
||||
}
|
||||
.openerp td.oe_form_field_translatable,
|
||||
.openerp td.oe_form_field_many2one,
|
||||
.openerp td.oe_form_field_date,
|
||||
.openerp td.oe_form_field_datetime {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.openerp td.oe_form_field_boolean {
|
||||
|
@ -1307,6 +1337,10 @@ label.error {
|
|||
white-space: normal;
|
||||
}
|
||||
|
||||
.openerp .oe_forms .oe_form_paragraph.oe_multilines {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.openerp .oe_form_field_one2many .oe-actions h3.oe_view_title,
|
||||
.openerp .oe_form_field_one2many_list .oe-actions h3.oe_view_title{
|
||||
display: inline;
|
||||
|
@ -1319,6 +1353,9 @@ label.error {
|
|||
margin-top: -9px;
|
||||
}
|
||||
|
||||
.openerp table.oe_frame .oe-listview-content td {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* Uneditable Form View */
|
||||
.openerp .oe_form_readonly {
|
||||
|
@ -1421,10 +1458,14 @@ label.error {
|
|||
.openerp .oe_forms select{
|
||||
padding-top: 2px;
|
||||
}
|
||||
.openerp .oe_forms input[readonly],
|
||||
.openerp .oe_forms select[readonly],
|
||||
.openerp .oe_forms textarea[readonly],
|
||||
.openerp .oe_forms input[disabled],
|
||||
.openerp .oe_forms select[disabled],
|
||||
.openerp .oe_forms textarea[disabled]{
|
||||
background: #E0E0E0;
|
||||
background: #E5E5E5 !important;
|
||||
color: #666;
|
||||
}
|
||||
.openerp .oe_forms textarea {
|
||||
resize:vertical;
|
||||
|
@ -1446,15 +1487,21 @@ label.error {
|
|||
min-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.openerp .oe_forms .button {
|
||||
height: 22px;
|
||||
}
|
||||
@-moz-document url-prefix() {
|
||||
/* Strange firefox behaviour on width: 100% + white-space: nowrap */
|
||||
.openerp .oe_forms .oe_form_button .oe_button {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
/* IE Hack - for IE < 9
|
||||
* Avoids buttons overflow
|
||||
* */
|
||||
.openerp .oe_forms .oe_form_button .oe_button {
|
||||
min-width: auto\9;
|
||||
}
|
||||
.openerp .oe_forms .button {
|
||||
height: 22px;
|
||||
}
|
||||
.openerp .oe_forms .oe_button span {
|
||||
position: relative;
|
||||
vertical-align: top;
|
||||
|
@ -1888,6 +1935,7 @@ label.error {
|
|||
width: 100%;
|
||||
background-color : #FFFFFF;
|
||||
border-spacing: 0;
|
||||
|
||||
}
|
||||
.openerp .oe-treeview-table tr:hover{
|
||||
color: blue;
|
||||
|
@ -1908,14 +1956,14 @@ label.error {
|
|||
white-space: nowrap;
|
||||
display: block;
|
||||
}
|
||||
.treeview-tr:first-of-type {
|
||||
.treeview-tr.oe-treeview-first {
|
||||
background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat;
|
||||
}
|
||||
.oe-open .treeview-tr:first-of-type {
|
||||
.oe-open .treeview-tr.oe-treeview-first {
|
||||
background-image: url(/web/static/src/img/collapse.gif);
|
||||
}
|
||||
.treeview-tr:first-of-type span,
|
||||
.treeview-td:first-of-type span {
|
||||
.treeview-tr.oe-treeview-first span,
|
||||
.treeview-td.oe-treeview-first span {
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
|
@ -2031,34 +2079,31 @@ ul.oe-arrow-list li.oe-arrow-list-selected .oe-arrow-list-after {
|
|||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
.openerp .oe_view_editor {
|
||||
border-collapse: collapse;
|
||||
padding: 0;
|
||||
align: left;
|
||||
width:100%;
|
||||
border-collapse : collapse;
|
||||
margin-left: -12px;
|
||||
|
||||
width: 100%;
|
||||
background-color : white;
|
||||
border-spacing: 0;
|
||||
}
|
||||
.openerp .oe_view_editor_colum{
|
||||
.openerp .oe_view_editor td{
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
border: 1px solid #D8D8D8;
|
||||
|
||||
cursor: pointer;
|
||||
font-size: 90%;
|
||||
font-weight: normal;
|
||||
padding: 0;
|
||||
border-bottom: 1px solid #CFCCCC;
|
||||
}
|
||||
.openerp .oe_view_editor_row:hover {
|
||||
background-color: #F3F3F3;
|
||||
.openerp .oe_view_editor_field td{
|
||||
border: 0px !important;
|
||||
}
|
||||
|
||||
.openerp .oe_view_editor_tree_grid{
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
.openerp .oe_view_editor_tree_grid a:hover {
|
||||
color: blue;
|
||||
}
|
||||
.openerp .oe_view_editor_tree_grid a {
|
||||
display: block;
|
||||
.openerp .oe_view_editor tr:hover {
|
||||
background-color: #ecebf2;
|
||||
}
|
||||
|
||||
|
||||
/* Dialog traceback cases */
|
||||
.openerp .oe_error_detail{
|
||||
display: block;
|
||||
|
|
|
@ -20,17 +20,27 @@ openerp.web.Notification = openerp.web.OldWidget.extend(/** @lends openerp.web.
|
|||
expires: 2500
|
||||
});
|
||||
},
|
||||
notify: function(title, text) {
|
||||
notify: function(title, text, sticky) {
|
||||
sticky = !!sticky;
|
||||
var opts = {};
|
||||
if (sticky) {
|
||||
opts.expires = false;
|
||||
}
|
||||
this.$element.notify('create', {
|
||||
title: title,
|
||||
text: text
|
||||
});
|
||||
}, opts);
|
||||
},
|
||||
warn: function(title, text) {
|
||||
warn: function(title, text, sticky) {
|
||||
sticky = !!sticky;
|
||||
var opts = {};
|
||||
if (sticky) {
|
||||
opts.expires = false;
|
||||
}
|
||||
this.$element.notify('create', 'oe_notification_alert', {
|
||||
title: title,
|
||||
text: text
|
||||
});
|
||||
}, opts);
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -606,6 +616,10 @@ openerp.web.Login = openerp.web.OldWidget.extend(/** @lends openerp.web.Login#
|
|||
}
|
||||
var $e = this.$element;
|
||||
var db = $e.find("form [name=db]").val();
|
||||
if (!db) {
|
||||
this.do_warn("Login", "No database selected !");
|
||||
return false;
|
||||
}
|
||||
var login = $e.find("form input[name=login]").val();
|
||||
var password = $e.find("form input[name=password]").val();
|
||||
|
||||
|
@ -945,7 +959,8 @@ openerp.web.Menu = openerp.web.OldWidget.extend(/** @lends openerp.web.Menu# */
|
|||
do_menu_click: function($clicked_menu, manual) {
|
||||
var $sub_menu, $main_menu,
|
||||
active = $clicked_menu.is('.active'),
|
||||
sub_menu_visible = false;
|
||||
sub_menu_visible = false,
|
||||
has_submenu_items = false;
|
||||
|
||||
if (this.$secondary_menu.has($clicked_menu).length) {
|
||||
$sub_menu = $clicked_menu.parents('.oe_secondary_menu');
|
||||
|
@ -956,15 +971,18 @@ openerp.web.Menu = openerp.web.OldWidget.extend(/** @lends openerp.web.Menu# */
|
|||
}
|
||||
|
||||
sub_menu_visible = $sub_menu.is(':visible');
|
||||
has_submenu_items = !!$sub_menu.children().length;
|
||||
this.$secondary_menu.find('.oe_secondary_menu').hide();
|
||||
|
||||
$('.active', this.$element.add(this.$secondary_menu)).removeClass('active');
|
||||
$main_menu.add($clicked_menu).add($sub_menu).addClass('active');
|
||||
|
||||
if (!(this.folded && manual)) {
|
||||
this.do_show_secondary($sub_menu, $main_menu);
|
||||
} else {
|
||||
this.do_show_secondary();
|
||||
if (has_submenu_items) {
|
||||
if (!(this.folded && manual)) {
|
||||
this.do_show_secondary($sub_menu, $main_menu);
|
||||
} else {
|
||||
this.do_show_secondary();
|
||||
}
|
||||
}
|
||||
|
||||
if ($main_menu != $clicked_menu) {
|
||||
|
@ -980,7 +998,7 @@ openerp.web.Menu = openerp.web.OldWidget.extend(/** @lends openerp.web.Menu# */
|
|||
return true;
|
||||
}
|
||||
} else if (this.folded) {
|
||||
if (active && sub_menu_visible) {
|
||||
if ((active && sub_menu_visible) || !has_submenu_items) {
|
||||
$sub_menu.hide();
|
||||
return true;
|
||||
}
|
||||
|
@ -1147,12 +1165,14 @@ openerp.web.WebClient = openerp.web.OldWidget.extend(/** @lends openerp.web.WebC
|
|||
n.warn.apply(n, arguments);
|
||||
},
|
||||
on_logout: function() {
|
||||
this.session.session_logout();
|
||||
$(window).unbind('hashchange', this.on_hashchange);
|
||||
this.do_push_state({});
|
||||
//would be cool to be able to do this, but I think it will make addons do strange things
|
||||
//this.show_login();
|
||||
window.location.reload();
|
||||
var self = this;
|
||||
this.session.session_logout().then(function () {
|
||||
$(window).unbind('hashchange', self.on_hashchange);
|
||||
self.do_push_state({});
|
||||
//would be cool to be able to do this, but I think it will make addons do strange things
|
||||
//this.show_login();
|
||||
window.location.reload();
|
||||
});
|
||||
},
|
||||
bind_hashchange: function() {
|
||||
$(window).bind('hashchange', this.on_hashchange);
|
||||
|
|
|
@ -254,6 +254,7 @@ openerp.web.Registry = openerp.web.Class.extend( /** @lends openerp.web.Registry
|
|||
* @param {Object} mapping a mapping of keys to object-paths
|
||||
*/
|
||||
init: function (mapping) {
|
||||
this.parent = null;
|
||||
this.map = mapping || {};
|
||||
},
|
||||
/**
|
||||
|
@ -269,6 +270,9 @@ openerp.web.Registry = openerp.web.Class.extend( /** @lends openerp.web.Registry
|
|||
get_object: function (key, silent_error) {
|
||||
var path_string = this.map[key];
|
||||
if (path_string === undefined) {
|
||||
if (this.parent) {
|
||||
return this.parent.get_object(key, silent_error);
|
||||
}
|
||||
if (silent_error) { return void 'nooo'; }
|
||||
throw new openerp.web.KeyNotFound(key);
|
||||
}
|
||||
|
@ -286,6 +290,21 @@ openerp.web.Registry = openerp.web.Class.extend( /** @lends openerp.web.Registry
|
|||
}
|
||||
return object_match;
|
||||
},
|
||||
/**
|
||||
* Checks if the registry contains an object mapping for this key.
|
||||
*
|
||||
* @param {String} key key to look for
|
||||
*/
|
||||
contains: function (key) {
|
||||
if (key === undefined) { return false; }
|
||||
if (key in this.map) {
|
||||
return true
|
||||
}
|
||||
if (this.parent) {
|
||||
return this.parent.contains(key);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
/**
|
||||
* Tries a number of keys, and returns the first object matching one of
|
||||
* the keys.
|
||||
|
@ -299,7 +318,7 @@ openerp.web.Registry = openerp.web.Class.extend( /** @lends openerp.web.Registry
|
|||
get_any: function (keys) {
|
||||
for (var i=0; i<keys.length; ++i) {
|
||||
var key = keys[i];
|
||||
if (key === undefined || !(key in this.map)) {
|
||||
if (!this.contains(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -324,11 +343,22 @@ openerp.web.Registry = openerp.web.Class.extend( /** @lends openerp.web.Registry
|
|||
* Creates and returns a copy of the current mapping, with the provided
|
||||
* mapping argument added in (replacing existing keys if needed)
|
||||
*
|
||||
* Parent and child remain linked, a new key in the parent (which is not
|
||||
* overwritten by the child) will appear in the child.
|
||||
*
|
||||
* @param {Object} [mapping={}] a mapping of keys to object-paths
|
||||
*/
|
||||
extend: function (mapping) {
|
||||
var child = new openerp.web.Registry(mapping);
|
||||
child.parent = this;
|
||||
return child;
|
||||
},
|
||||
/**
|
||||
* @deprecated use Registry#extend
|
||||
*/
|
||||
clone: function (mapping) {
|
||||
return new openerp.web.Registry(
|
||||
_.extend({}, this.map, mapping || {}));
|
||||
console.warn('Registry#clone is deprecated, use Registry#extend');
|
||||
return this.extend(mapping);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -644,6 +674,7 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp.
|
|||
},
|
||||
session_logout: function() {
|
||||
this.set_cookie('session_id', '');
|
||||
return this.rpc("/web/session/destroy", {});
|
||||
},
|
||||
on_session_valid: function() {
|
||||
},
|
||||
|
@ -702,17 +733,21 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp.
|
|||
var params = { mods: all_modules, lang: lang};
|
||||
var to_load = _.difference(result, self.module_list).join(',');
|
||||
self.module_list = all_modules;
|
||||
return $.when(
|
||||
self.rpc('/web/webclient/csslist', {mods: to_load}, self.do_load_css),
|
||||
self.rpc('/web/webclient/qweblist', {mods: to_load}).pipe(self.do_load_qweb),
|
||||
self.rpc('/web/webclient/translations', params).pipe(function(trans) {
|
||||
openerp.web._t.database.set_bundle(trans);
|
||||
var file_list = ["/web/static/lib/datejs/globalization/" + lang.replace("_", "-") + ".js"];
|
||||
return self.rpc('/web/webclient/jslist', {mods: to_load}).pipe(function(files) {
|
||||
return self.do_load_js(file_list.concat(files));
|
||||
});
|
||||
})
|
||||
).then(function() {
|
||||
|
||||
var loaded = $.Deferred().resolve().promise();
|
||||
if (to_load.length) {
|
||||
loaded = $.when(
|
||||
self.rpc('/web/webclient/csslist', {mods: to_load}, self.do_load_css),
|
||||
self.rpc('/web/webclient/qweblist', {mods: to_load}).pipe(self.do_load_qweb),
|
||||
self.rpc('/web/webclient/translations', params).pipe(function(trans) {
|
||||
openerp.web._t.database.set_bundle(trans);
|
||||
var file_list = ["/web/static/lib/datejs/globalization/" + lang.replace("_", "-") + ".js"];
|
||||
return self.rpc('/web/webclient/jslist', {mods: to_load}).pipe(function(files) {
|
||||
return self.do_load_js(file_list.concat(files));
|
||||
});
|
||||
}))
|
||||
}
|
||||
return loaded.then(function() {
|
||||
self.on_modules_loaded();
|
||||
if (!no_session_valid_signal) {
|
||||
self.on_session_valid();
|
||||
|
@ -1184,9 +1219,7 @@ openerp.web.TranslationDataBase = openerp.web.Class.extend(/** @lends openerp.we
|
|||
add_module_translation: function(mod) {
|
||||
var self = this;
|
||||
_.each(mod.messages, function(message) {
|
||||
if (self.db[message.id] === undefined) {
|
||||
self.db[message.id] = message.string;
|
||||
}
|
||||
self.db[message.id] = message.string;
|
||||
});
|
||||
},
|
||||
build_translation_function: function() {
|
||||
|
|
|
@ -469,13 +469,13 @@ openerp.web.DataSet = openerp.web.OldWidget.extend( /** @lends openerp.web.Data
|
|||
* @param {String} name name to perform a search for/on
|
||||
* @param {Array} [domain=[]] filters for the objects returned, OpenERP domain
|
||||
* @param {String} [operator='ilike'] matching operator to use with the provided name value
|
||||
* @param {Number} [limit=100] maximum number of matches to return
|
||||
* @param {Number} [limit=0] maximum number of matches to return
|
||||
* @param {Function} callback function to call with name_search result
|
||||
* @returns {$.Deferred}
|
||||
*/
|
||||
name_search: function (name, domain, operator, limit, callback) {
|
||||
return this.call_and_eval('name_search',
|
||||
[name || '', domain || false, operator || 'ilike', this.get_context(), limit || 100],
|
||||
[name || '', domain || false, operator || 'ilike', this.get_context(), limit || 0],
|
||||
1, 3, callback);
|
||||
},
|
||||
/**
|
||||
|
@ -522,7 +522,13 @@ openerp.web.DataSet = openerp.web.OldWidget.extend( /** @lends openerp.web.Data
|
|||
|
||||
this._sort.unshift((reverse ? '-' : '') + field);
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
size: function () {
|
||||
return this.ids.length;
|
||||
},
|
||||
alter_ids: function(n_ids) {
|
||||
this.ids = n_ids;
|
||||
},
|
||||
});
|
||||
openerp.web.DataSetStatic = openerp.web.DataSet.extend({
|
||||
init: function(parent, model, context, ids) {
|
||||
|
@ -568,6 +574,7 @@ openerp.web.DataSetSearch = openerp.web.DataSet.extend(/** @lends openerp.web.D
|
|||
this._super(parent, model, context);
|
||||
this.domain = domain || [];
|
||||
this.offset = 0;
|
||||
this._length;
|
||||
// subset records[offset:offset+limit]
|
||||
// is it necessary ?
|
||||
this.ids = [];
|
||||
|
@ -599,6 +606,7 @@ openerp.web.DataSetSearch = openerp.web.DataSet.extend(/** @lends openerp.web.D
|
|||
}).pipe(function (result) {
|
||||
self.ids = result.ids;
|
||||
self.offset = offset;
|
||||
self._length = result.length;
|
||||
return result.records;
|
||||
});
|
||||
},
|
||||
|
@ -619,6 +627,12 @@ openerp.web.DataSetSearch = openerp.web.DataSet.extend(/** @lends openerp.web.D
|
|||
if (callback)
|
||||
callback(result);
|
||||
}, error_callback);
|
||||
},
|
||||
size: function () {
|
||||
if (this._length !== undefined) {
|
||||
return this._length;
|
||||
}
|
||||
return this._super();
|
||||
}
|
||||
});
|
||||
openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({
|
||||
|
@ -640,7 +654,6 @@ openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({
|
|||
defaults: this.last_default_get};
|
||||
this.to_create.push(_.extend(_.clone(cached), {values: _.clone(cached.values)}));
|
||||
this.cache.push(cached);
|
||||
this.on_change();
|
||||
var prom = $.Deferred().then(callback);
|
||||
prom.resolve({result: cached.id});
|
||||
return prom.promise();
|
||||
|
@ -751,7 +764,7 @@ openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({
|
|||
self.cache.push({id: id, values: record});
|
||||
} else {
|
||||
// I assume cache value is prioritary
|
||||
_.defaults(cached.values, record);
|
||||
cached.values = _.defaults(_.clone(cached.values), record);
|
||||
}
|
||||
});
|
||||
return_records();
|
||||
|
@ -774,7 +787,11 @@ openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({
|
|||
}
|
||||
}
|
||||
return this._super(method, args, callback, error_callback);
|
||||
}
|
||||
},
|
||||
alter_ids: function(n_ids) {
|
||||
this._super(n_ids);
|
||||
this.on_change();
|
||||
},
|
||||
});
|
||||
openerp.web.BufferedDataSet.virtual_id_regex = /^one2many_v_id_.*$/;
|
||||
|
||||
|
|
|
@ -109,9 +109,20 @@ openerp.web.DataImport = openerp.web.Dialog.extend({
|
|||
_(fields).each(function (field, field_name) {
|
||||
// Ignore spec for id field
|
||||
// Don't import function fields (function and related)
|
||||
if (field_name === 'id' || 'function' in field) {
|
||||
if (field_name === 'id') {
|
||||
return;
|
||||
}
|
||||
// Skip if there's no state which could disable @readonly,
|
||||
// if a field is ever always readonly we can't import it
|
||||
if (field.readonly) {
|
||||
// no states at all
|
||||
if (_.isEmpty(field.states)) { return; }
|
||||
// no state altering @readonly
|
||||
if (!_.any(field.states, function (modifiers) {
|
||||
return _(modifiers).chain().pluck(0).contains('readonly').value();
|
||||
})) { return; }
|
||||
}
|
||||
|
||||
var f = {
|
||||
id: field_name,
|
||||
name: field_name,
|
||||
|
|
|
@ -61,6 +61,28 @@ openerp.web.insert_thousand_seps = function (num) {
|
|||
return (negative ? '-' : '') + openerp.web.intersperse(
|
||||
num, _t.database.parameters.grouping, _t.database.parameters.thousands_sep);
|
||||
};
|
||||
|
||||
/**
|
||||
* removes literal (non-format) text from a date or time pattern, as datejs can
|
||||
* not deal with literal text in format strings (whatever the format), whereas
|
||||
* strftime allows for literal characters
|
||||
*
|
||||
* @param {String} value original format
|
||||
*/
|
||||
openerp.web.strip_raw_chars = function (value) {
|
||||
var isletter = /[a-zA-Z]/, output = [];
|
||||
for(var index=0; index < value.length; ++index) {
|
||||
var character = value[index];
|
||||
if(isletter.test(character) && (index === 0 || value[index-1] !== '%')) {
|
||||
continue;
|
||||
}
|
||||
output.push(character);
|
||||
}
|
||||
return output.join('');
|
||||
};
|
||||
var normalize_format = function (format) {
|
||||
return Date.normalizeFormat(openerp.web.strip_raw_chars(format));
|
||||
};
|
||||
/**
|
||||
* Formats a single atomic value based on a field descriptor
|
||||
*
|
||||
|
@ -101,7 +123,12 @@ openerp.web.format_value = function (value, descriptor, value_if_empty) {
|
|||
formatted[0] = openerp.web.insert_thousand_seps(formatted[0]);
|
||||
return formatted.join(l10n.decimal_point);
|
||||
case 'float_time':
|
||||
return _.str.sprintf("%02d:%02d",
|
||||
var pattern = '%02d:%02d';
|
||||
if (value < 0) {
|
||||
value = Math.abs(value);
|
||||
pattern = '-' + pattern;
|
||||
}
|
||||
return _.str.sprintf(pattern,
|
||||
Math.floor(value),
|
||||
Math.round((value % 1) * 60));
|
||||
case 'many2one':
|
||||
|
@ -111,16 +138,16 @@ openerp.web.format_value = function (value, descriptor, value_if_empty) {
|
|||
if (typeof(value) == "string")
|
||||
value = openerp.web.auto_str_to_date(value);
|
||||
|
||||
return value.format(l10n.date_format
|
||||
+ ' ' + l10n.time_format);
|
||||
return value.toString(normalize_format(l10n.date_format)
|
||||
+ ' ' + normalize_format(l10n.time_format));
|
||||
case 'date':
|
||||
if (typeof(value) == "string")
|
||||
value = openerp.web.auto_str_to_date(value);
|
||||
return value.format(l10n.date_format);
|
||||
return value.toString(normalize_format(l10n.date_format));
|
||||
case 'time':
|
||||
if (typeof(value) == "string")
|
||||
value = openerp.web.auto_str_to_date(value);
|
||||
return value.format(l10n.time_format);
|
||||
return value.toString(normalize_format(l10n.time_format));
|
||||
case 'selection':
|
||||
// Each choice is [value, label]
|
||||
if(_.isArray(value)) {
|
||||
|
@ -137,8 +164,8 @@ openerp.web.format_value = function (value, descriptor, value_if_empty) {
|
|||
};
|
||||
|
||||
openerp.web.parse_value = function (value, descriptor, value_if_empty) {
|
||||
var date_pattern = Date.normalizeFormat(_t.database.parameters.date_format),
|
||||
time_pattern = Date.normalizeFormat(_t.database.parameters.time_format);
|
||||
var date_pattern = normalize_format(_t.database.parameters.date_format),
|
||||
time_pattern = normalize_format(_t.database.parameters.time_format);
|
||||
switch (value) {
|
||||
case false:
|
||||
case "":
|
||||
|
@ -171,12 +198,17 @@ openerp.web.parse_value = function (value, descriptor, value_if_empty) {
|
|||
throw new Error(value + " is not a correct float");
|
||||
return parsed;
|
||||
case 'float_time':
|
||||
var factor = 1;
|
||||
if (value[0] === '-') {
|
||||
value = value.slice(1);
|
||||
factor = -1;
|
||||
}
|
||||
var float_time_pair = value.split(":");
|
||||
if (float_time_pair.length != 2)
|
||||
return openerp.web.parse_value(value, {type: "float"});
|
||||
return factor * openerp.web.parse_value(value, {type: "float"});
|
||||
var hours = openerp.web.parse_value(float_time_pair[0], {type: "integer"});
|
||||
var minutes = openerp.web.parse_value(float_time_pair[1], {type: "integer"});
|
||||
return hours + (minutes / 60);
|
||||
return factor * (hours + (minutes / 60));
|
||||
case 'progressbar':
|
||||
return openerp.web.parse_value(value, {type: "float"});
|
||||
case 'datetime':
|
||||
|
|
|
@ -154,7 +154,6 @@ openerp.web.SearchView = openerp.web.OldWidget.extend(/** @lends openerp.web.Sea
|
|||
// for extended search view
|
||||
var ext = new openerp.web.search.ExtendedSearch(this, this.model);
|
||||
lines.push([ext]);
|
||||
this.inputs.push(ext);
|
||||
this.extended_search = ext;
|
||||
|
||||
var render = QWeb.render("SearchView", {
|
||||
|
@ -187,7 +186,10 @@ openerp.web.SearchView = openerp.web.OldWidget.extend(/** @lends openerp.web.Sea
|
|||
}).then(function(result) {
|
||||
self.managed_filters = result;
|
||||
var filters = self.$element.find(".oe_search-view-filters-management");
|
||||
filters.html(QWeb.render("SearchView.managed-filters", {filters: result}));
|
||||
filters.html(QWeb.render("SearchView.managed-filters", {
|
||||
filters: result,
|
||||
disabled_filter_message: _t('Filter disabled due to invalid syntax')
|
||||
}));
|
||||
filters.change(self.on_filters_management);
|
||||
});
|
||||
},
|
||||
|
@ -425,13 +427,9 @@ openerp.web.SearchView = openerp.web.OldWidget.extend(/** @lends openerp.web.Sea
|
|||
this.$element.find('table:last').hide();
|
||||
|
||||
$('.searchview_extended_groups_list').empty();
|
||||
_.each(this.inputs, function (input) {
|
||||
if(input.datewidget && input.datewidget.value) {
|
||||
input.datewidget.set_value(false);
|
||||
}
|
||||
});
|
||||
return $.async_when().pipe(
|
||||
reload_view !== false ? this.on_clear : null);
|
||||
return $.async_when.apply(
|
||||
null, _(this.inputs).invoke('clear')).pipe(
|
||||
reload_view !== false ? this.on_clear : null);
|
||||
},
|
||||
/**
|
||||
* Triggered when the search view gets cleared
|
||||
|
@ -618,7 +616,11 @@ openerp.web.search.Input = openerp.web.search.Widget.extend( /** @lends openerp.
|
|||
}
|
||||
}
|
||||
this.attrs = attrs;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Specific clearing operations, if any
|
||||
*/
|
||||
clear: function () {}
|
||||
});
|
||||
openerp.web.search.FilterGroup = openerp.web.search.Input.extend(/** @lends openerp.web.search.FilterGroup# */{
|
||||
template: 'SearchView.filters',
|
||||
|
@ -900,6 +902,22 @@ openerp.web.search.SelectionField = openerp.web.search.Field.extend(/** @lends o
|
|||
defaults[this.attrs.name] = false;
|
||||
}
|
||||
return this._super(defaults);
|
||||
},
|
||||
clear: function () {
|
||||
var self = this, d = $.Deferred(), selection = this.attrs.selection;
|
||||
for(var index=0; index<selection.length; ++index) {
|
||||
var item = selection[index];
|
||||
if (!item[1]) {
|
||||
setTimeout(function () {
|
||||
// won't override mutable, because we immediately bail out
|
||||
//noinspection JSReferencingMutableVariableFromClosure
|
||||
self.$element.val(index);
|
||||
d.resolve();
|
||||
}, 0);
|
||||
return d.promise();
|
||||
}
|
||||
}
|
||||
return d.resolve().promise();
|
||||
}
|
||||
});
|
||||
openerp.web.search.BooleanField = openerp.web.search.SelectionField.extend(/** @lends openerp.web.search.BooleanField# */{
|
||||
|
@ -947,15 +965,20 @@ openerp.web.search.DateField = openerp.web.search.Field.extend(/** @lends opener
|
|||
template: "SearchView.date",
|
||||
start: function () {
|
||||
this._super();
|
||||
// FIXME: this insanity puts a div inside a span
|
||||
this.datewidget = new openerp.web.DateWidget(this);
|
||||
this.datewidget.prependTo(this.$element);
|
||||
this.datewidget.$element.find("input").attr("size", 15);
|
||||
this.datewidget.$element.find("input").attr("autofocus",
|
||||
this.attrs.default_focus === '1' ? 'autofocus' : undefined);
|
||||
this.datewidget.$element.find("input")
|
||||
.attr("size", 15)
|
||||
.attr("autofocus", this.attrs.default_focus === '1' ? 'autofocus' : null)
|
||||
.removeAttr('style');
|
||||
this.datewidget.set_value(this.defaults[this.attrs.name] || false);
|
||||
},
|
||||
get_value: function () {
|
||||
return this.datewidget.get_value() || null;
|
||||
},
|
||||
clear: function () {
|
||||
this.datewidget.set_value(false);
|
||||
}
|
||||
});
|
||||
/**
|
||||
|
@ -1051,7 +1074,7 @@ openerp.web.search.ManyToOneField = openerp.web.search.CharField.extend({
|
|||
}
|
||||
});
|
||||
|
||||
openerp.web.search.ExtendedSearch = openerp.web.search.Widget.extend({
|
||||
openerp.web.search.ExtendedSearch = openerp.web.search.Input.extend({
|
||||
template: 'SearchView.extended_search',
|
||||
init: function (parent, model) {
|
||||
this._super(parent);
|
||||
|
|
|
@ -27,6 +27,7 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
|
|||
type: 'ir.actions.act_window',
|
||||
target: "current",
|
||||
limit: this.dataset.limit || 80,
|
||||
auto_search : true,
|
||||
flags: {
|
||||
sidebar: false,
|
||||
deletable: false,
|
||||
|
@ -45,9 +46,10 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
|
|||
{text: _t("Create"), click: function() { self.on_create_view(); }},
|
||||
{text: _t("Edit"), click: function() { self.xml_element_id = 0; self.get_arch(); }},
|
||||
{text: _t("Remove"), click: function() { self.do_delete_view(); }},
|
||||
{text: _t("Close"), click: function() { self.view_edit_dialog.close(); }}
|
||||
{text: _t("Close"), click: function() { self.view_edit_dialog.close(); window.location.reload(); }}
|
||||
]
|
||||
}).open();
|
||||
this.view_edit_dialog.on_close.add_last(function(){window.location.reload();});
|
||||
this.main_view_id = this.parent.fields_view.view_id;
|
||||
this.action_manager = new openerp.web.ActionManager(this);
|
||||
this.action_manager.appendTo(this.view_edit_dialog);
|
||||
|
@ -162,11 +164,12 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
|
|||
}
|
||||
},
|
||||
do_delete_view: function() {
|
||||
var self = this;
|
||||
if (confirm(_t("Do you really want to remove this view?"))) {
|
||||
var controller = this.action_manager.inner_viewmanager.views[this.action_manager.inner_viewmanager.active_view].controller;
|
||||
this.dataset.unlink([this.main_view_id]).then(function() {
|
||||
controller.reload_content();
|
||||
this.main_view_id = self.parent.fields_view.view_id;
|
||||
self.main_view_id = self.parent.fields_view.view_id;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -227,14 +230,14 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
|
|||
get_arch: function() {
|
||||
var self = this;
|
||||
var view_arch_list = [];
|
||||
this.dataset.read_ids([parseInt(self.main_view_id)], ['arch', 'type']).then(function(arch) {
|
||||
this.dataset.read_ids([parseInt(self.main_view_id)], ['arch', 'type','priority']).then(function(arch) {
|
||||
if (arch.length) {
|
||||
var arch_object = self.parse_xml(arch[0].arch, self.main_view_id);
|
||||
self.main_view_type = arch[0].type == 'tree'? 'list': arch[0].type;
|
||||
view_arch_list.push({"view_id": self.main_view_id, "arch": arch[0].arch});
|
||||
view_arch_list.push({"view_id": self.main_view_id, "arch": arch[0].arch,"priority":arch[0].priority});
|
||||
self.dataset.read_slice([], {domain: [['inherit_id','=', parseInt(self.main_view_id)]]}).then(function(result) {
|
||||
_.each(result, function(res) {
|
||||
view_arch_list.push({"view_id": res.id, "arch": res.arch});
|
||||
view_arch_list.push({"view_id": res.id, "arch": res.arch,"priority":res.priority});
|
||||
self.inherit_view(arch_object, res);
|
||||
});
|
||||
return self.edit_view({"main_object": arch_object,
|
||||
|
@ -303,7 +306,7 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
|
|||
case 3:
|
||||
//for field[@name='type']
|
||||
obj = _.detect(arch_object, function(element){
|
||||
if ((_.intersection(_.flatten(element.att_list), _.uniq(check))).length == check.length) {
|
||||
if ((_.intersection(_.flatten(element.att_list), _.uniq(check))).length == _.uniq(check).length) {
|
||||
return element;
|
||||
}
|
||||
});
|
||||
|
@ -361,6 +364,20 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
|
|||
title: _.str.sprintf(_t("View Editor %d - %s"), self.main_view_id, self.model),
|
||||
height: '90%',
|
||||
buttons: [
|
||||
{text: _t("Inherited View"), click: function(){
|
||||
var selected_row = self.edit_xml_dialog.$element.find('.ui-selected');
|
||||
if (selected_row.length) {
|
||||
if(selected_row.find('a').text().search("field") != -1){
|
||||
if (confirm(_t("Do you really wants to create an inherited view here?"))) {
|
||||
self.inherited_view(selected_row);
|
||||
}
|
||||
}else{
|
||||
alert("Can't Update View");
|
||||
}
|
||||
}else{
|
||||
alert("Select an element");
|
||||
}
|
||||
}},
|
||||
{text: _t("Preview"), click: function() {
|
||||
var action = {
|
||||
context: self.session.user_context,
|
||||
|
@ -368,6 +385,7 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
|
|||
views: [[self.main_view_id, self.main_view_type]],
|
||||
type: 'ir.actions.act_window',
|
||||
target: "new",
|
||||
auto_search: true,
|
||||
flags: {
|
||||
sidebar: false,
|
||||
views_switcher: false,
|
||||
|
@ -378,6 +396,7 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
|
|||
action_manager.do_action(action);
|
||||
}},
|
||||
{text: _t("Close"), click: function(){
|
||||
self.action_manager.inner_viewmanager.views[self.action_manager.inner_viewmanager.active_view].controller.reload_content();
|
||||
self.edit_xml_dialog.close();
|
||||
}}
|
||||
]
|
||||
|
@ -397,6 +416,53 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
|
|||
self.on_select_img(this);
|
||||
});
|
||||
},
|
||||
inherited_view: function(selected_row){
|
||||
var self = this;
|
||||
var row_id = parseInt((selected_row.attr('id')).split('-')[1]);
|
||||
var obj = self.get_object_by_id(row_id,self.one_object['main_object'], [])[0];
|
||||
var view_name = this.model + '.inherit_' + Math.round(Math.random() * 1000);
|
||||
var view_find = selected_row;
|
||||
var view_id;
|
||||
var min_level = parseInt(selected_row.attr('level'));
|
||||
while (1) {
|
||||
view_find = view_find.prev();
|
||||
if (view_find.length == 0 ||
|
||||
self.edit_xml_dialog.$element.find(view_find).find('a').text().search("view_id") != -1 &&
|
||||
parseInt(view_find.attr('level')) < min_level ) {
|
||||
view_id = parseInt($(view_find).find('a').text().replace(/[^0-9]+/g, ''));
|
||||
break;
|
||||
}
|
||||
if (view_find.attr('level') < min_level) {
|
||||
min_level = parseInt(view_find.attr('level'));
|
||||
}
|
||||
}
|
||||
var val = _.detect(obj.att_list, function(val) {return val[0] == "name";});
|
||||
var priority = _.detect(self.one_object['arch'], function(val) {return val.view_id == view_id;});
|
||||
var arch = _.str.sprintf("<?xml version='1.0'?>\n\t <field name='%s' position='after'> </field>", val[1]);
|
||||
var vals = {'model': self.model, 'name': view_name, 'priority': priority.priority + 1, 'type': "form", 'arch': arch,'inherit_id':self.main_view_id};
|
||||
this.dataset.create(vals, function(suc) {
|
||||
var arch_to_obj = self.parse_xml(arch,suc.result);
|
||||
obj.child_id.push(arch_to_obj[0]);
|
||||
self.one_object['parent_child_id'] = self.parent_child_list(self.one_object['main_object'],[]);
|
||||
self.one_object['arch'].push({'view_id':suc.result,"arch":arch,'priority': priority.priority + 1});
|
||||
self.increase_level(arch_to_obj[0],obj.level+1);
|
||||
self.render_inherited_view(selected_row,arch_to_obj[0]);
|
||||
});
|
||||
},
|
||||
render_inherited_view: function(selected_row,obj){
|
||||
var self = this,row_id = parseInt((selected_row.attr('id')).split('-')[1]);
|
||||
var clone = this.create_clone(selected_row.clone(),obj);
|
||||
if (selected_row.find("img[id^='parentimg-']").length == 0) {
|
||||
($(selected_row.find('a').parent()).siblings('td'))
|
||||
.append($('<img width="16" height="16"></img>').attr('src', '/web/static/src/img/collapse.gif').
|
||||
attr('id','parentimg-'+ row_id).click(function(){
|
||||
self.do_parent_img_hide_show(this);
|
||||
}));
|
||||
}
|
||||
self.edit_xml_dialog.$element.
|
||||
find("tr[id='viewedit-"+row_id+"']").after(clone.removeClass('ui-selected'));
|
||||
_.each(obj.child_id,function(obj){self.render_inherited_view(clone,obj);});
|
||||
},
|
||||
on_select_img: function(element_img) {
|
||||
var self = this;
|
||||
var side = $(element_img).closest("tr[id^='viewedit-']");
|
||||
|
@ -449,7 +515,7 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
|
|||
},
|
||||
do_node_add: function(side){
|
||||
var self = this;
|
||||
var tr = $(side).find('a').text();
|
||||
var tr = self.get_object_by_id(this.one_object.clicked_tr_id, this.one_object['main_object'], [])[0].att_list[0];
|
||||
var parent_tr = ($(side).prevAll("tr[level=" + String(this.one_object.clicked_tr_level - 1) + "]"))[0];
|
||||
var field_dataset = new openerp.web.DataSetSearch(this, this.model, null, null);
|
||||
parent_tr = $(parent_tr).find('a').text();
|
||||
|
@ -562,13 +628,13 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
|
|||
arch.arch = _.detect(children, function(xml_child) {
|
||||
var temp_obj = self.create_View_Node(xml_child),
|
||||
insert = _.intersection(_.flatten(temp_obj.att_list),_.uniq(check_list));
|
||||
if (insert.length == check_list.length ) {return xml_child;}
|
||||
if (insert.length == _.uniq(check_list).length ) {return xml_child;}
|
||||
});
|
||||
}
|
||||
arch_to_pass = _.filter($(arch.arch), function (child) {
|
||||
return child.nodeType == 1;
|
||||
});
|
||||
return self.do_save_xml(arch_to_pass[0], obj[0].child_id[0],[], move_direct, update_values,arch);
|
||||
return self.do_save_xml(arch_to_pass[0], obj[0].child_id[0],obj[0].child_id, move_direct, update_values,arch);
|
||||
},
|
||||
get_object_by_id: function(id, one_object, result) {
|
||||
var self = this;
|
||||
|
@ -583,7 +649,7 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
|
|||
}
|
||||
return result;
|
||||
},
|
||||
create_clone: function(clone, new_node_obj, position){
|
||||
create_clone: function(clone, new_node_obj){
|
||||
var self = this;
|
||||
clone.find('a').text(new_node_obj.name);
|
||||
($(clone.find('a').parent()).siblings('td')).css( "padding-left", 20 * new_node_obj.level);
|
||||
|
@ -599,7 +665,8 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
|
|||
return clone;
|
||||
},
|
||||
do_save_xml: function(arch1, obj, child_list, move_direct, update_values, arch){
|
||||
var self = this, children_list = $(arch1).children(), list_obj_xml = _.zip(children_list, obj.child_id);
|
||||
var self = this, children_list = $(arch1).children(),list_obj_xml;
|
||||
try{list_obj_xml = _.zip(children_list, obj.child_id);}catch(err){return;}
|
||||
if (this.one_object.clicked_tr_id) {
|
||||
if (obj.id == this.one_object.clicked_tr_id) {
|
||||
var parent = false, index = _.indexOf(child_list, obj);
|
||||
|
@ -823,6 +890,7 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
|
|||
var value = _.detect(arch_val[0]['att_list'],function(res) {
|
||||
return res instanceof Array? _.include(res, widget.name): false;
|
||||
});
|
||||
|
||||
value = value instanceof Array ? value[1] : value;
|
||||
self.edit_node_dialog.$element.find('table[id=rec_table]').append('<tr><td align="right">' + widget.string + ':</td>' + type_widget.render() + '</tr>');
|
||||
type_widget.start();
|
||||
|
@ -845,7 +913,7 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
|
|||
res_groups.read_slice([], {}).done(function (res_grp) {
|
||||
_.each(res_grp, function (res) {
|
||||
var key = res.id;
|
||||
group_names[key] = res.name;
|
||||
group_names[key]=res.full_name;
|
||||
group_ids.push(res.id);
|
||||
});
|
||||
model_data.read_slice([], {domain: [
|
||||
|
@ -933,16 +1001,16 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({
|
|||
var action_manager = new openerp.web.ActionManager(self);
|
||||
$.when(action_manager.do_action(action)).then(function() {
|
||||
var controller = action_manager.dialog_viewmanager.views['form'].controller;
|
||||
// TODO NIV: use page view
|
||||
controller.do_set_readonly.add_last(function(){
|
||||
controller.on_button_cancel.add_last(function(){
|
||||
action_manager.stop()
|
||||
});
|
||||
controller.do_save.add_last(function(){
|
||||
action_manager.stop();
|
||||
new_fields_name = new openerp.web.DataSetSearch(self,'ir.model.fields', null, null);
|
||||
new_fields_name.read_ids([controller.datarecord.id], ['name']).then(function(result) {
|
||||
self.add_node_dialog.$element.find('select[id=field_value]').append($("<option selected></option>").attr("value", result[0].name).text(result[0].name));
|
||||
var value =controller.fields.name.value;
|
||||
self.add_node_dialog.$element.find('select[id=field_value]').append($("<option selected></option>").attr("value",value).text(value));
|
||||
_.detect(self.add_widget,function(widget){
|
||||
widget.name == "field_value"? widget.selection.push(result[0].name): false;
|
||||
widget.name == "field_value"? widget.selection.push(value): false;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1039,7 +1107,7 @@ openerp.web.ViewEditor.FieldSelect = openerp.web.ViewEditor.Field.extend({
|
|||
var index = 0;
|
||||
value = value === null? false: value;
|
||||
for (var i = 0, ii = this.selection.length; i < ii; i++) {
|
||||
if ((this.selection[i] instanceof Array && this.selection[i][1] === value) || this.selection[i] === value) index = i;
|
||||
if ((this.selection[i] instanceof Array && this.selection[i][0] === value) || this.selection[i] === value) index = i;
|
||||
}
|
||||
this.$element.find("select[id=" + this.name + "]")[0].selectedIndex = index;
|
||||
},
|
||||
|
@ -1092,10 +1160,10 @@ var _CHILDREN = {
|
|||
'calendar': ['field'],
|
||||
'notebook': ['page'],
|
||||
'page': ['notebook', 'group', 'field', 'label', 'button', 'newline', 'separator'],
|
||||
'group': ['field', 'label', 'button', 'separator', 'newline'],
|
||||
'group': ['field', 'label', 'button', 'separator', 'newline','group'],
|
||||
'board': ['column'],
|
||||
'action': [],
|
||||
'field': ['form', 'tree', 'graph'],
|
||||
'field': ['form', 'tree', 'graph','field'],
|
||||
'label': [],
|
||||
'button' : [],
|
||||
'newline': [],
|
||||
|
|
|
@ -121,6 +121,15 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
|
|||
this.sidebar.attachments = new openerp.web.form.SidebarAttachments(this.sidebar, this);
|
||||
this.sidebar.add_toolbar(this.fields_view.toolbar);
|
||||
this.set_common_sidebar_sections(this.sidebar);
|
||||
|
||||
this.sidebar.add_section(_t('Customize'), 'customize');
|
||||
this.sidebar.add_items('customize', [{
|
||||
label: _t('Set Default'),
|
||||
form: this,
|
||||
callback: function (item) {
|
||||
item.form.open_defaults_dialog();
|
||||
}
|
||||
}]);
|
||||
}
|
||||
this.has_been_loaded.resolve();
|
||||
},
|
||||
|
@ -140,6 +149,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
|
|||
do_show: function () {
|
||||
var self = this;
|
||||
this.$element.show().css('visibility', 'hidden');
|
||||
this.$element.removeClass('oe_form_dirty');
|
||||
return this.has_been_loaded.pipe(function() {
|
||||
var result;
|
||||
if (self.dataset.index === null) {
|
||||
|
@ -168,7 +178,8 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
|
|||
on_record_loaded: function(record) {
|
||||
var self = this, set_values = [];
|
||||
if (!record) {
|
||||
throw new Error("Form: No record received");
|
||||
this.do_warn("Form", "The record could not be found in the database.", true);
|
||||
return $.Deferred().reject();
|
||||
}
|
||||
this.datarecord = record;
|
||||
|
||||
|
@ -204,6 +215,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
|
|||
if (record.id) {
|
||||
self.do_push_state({id:record.id});
|
||||
}
|
||||
self.$element.removeClass('oe_form_dirty');
|
||||
});
|
||||
},
|
||||
on_form_changed: function() {
|
||||
|
@ -216,6 +228,9 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
|
|||
w.update_dom();
|
||||
}
|
||||
},
|
||||
do_notify_change: function() {
|
||||
this.$element.addClass('oe_form_dirty');
|
||||
},
|
||||
on_pager_action: function(action) {
|
||||
if (this.can_be_discarded()) {
|
||||
switch (action) {
|
||||
|
@ -437,7 +452,9 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
|
|||
});
|
||||
},
|
||||
on_button_cancel: function() {
|
||||
return this.do_prev_view({'default': 'page'});
|
||||
if (this.can_be_discarded()) {
|
||||
return this.do_prev_view({'default': 'page'});
|
||||
}
|
||||
},
|
||||
on_button_new: function() {
|
||||
var self = this;
|
||||
|
@ -459,8 +476,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
|
|||
return def.promise();
|
||||
},
|
||||
can_be_discarded: function() {
|
||||
return true; // FIXME: Disabled until the page view and button refactoring is done
|
||||
return !this.is_dirty() || confirm(_t("Warning, the record has been modified, your changes will be discarded."));
|
||||
return !this.$element.is('.oe_form_dirty') || confirm(_t("Warning, the record has been modified, your changes will be discarded."));
|
||||
},
|
||||
/**
|
||||
* Triggers saving the form's record. Chooses between creating a new
|
||||
|
@ -559,10 +575,10 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
|
|||
} else {
|
||||
this.datarecord.id = r.result;
|
||||
if (!prepend_on_create) {
|
||||
this.dataset.ids.push(this.datarecord.id);
|
||||
this.dataset.alter_ids(this.dataset.ids.concat([this.datarecord.id]));
|
||||
this.dataset.index = this.dataset.ids.length - 1;
|
||||
} else {
|
||||
this.dataset.ids.unshift(this.datarecord.id);
|
||||
this.dataset.alter_ids([this.datarecord.id].concat(this.dataset.ids));
|
||||
this.dataset.index = 0;
|
||||
}
|
||||
this.do_update_pager();
|
||||
|
@ -631,6 +647,82 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
|
|||
},
|
||||
sidebar_context: function () {
|
||||
return this.do_save().pipe(_.bind(function() {return this.get_fields_values();}, this));
|
||||
},
|
||||
open_defaults_dialog: function () {
|
||||
var self = this;
|
||||
var fields = _.chain(this.fields)
|
||||
.map(function (field, name) {
|
||||
var value = field.get_value();
|
||||
// ignore fields which are empty, invisible, readonly, o2m
|
||||
// or m2m
|
||||
if (!value
|
||||
|| field.invisible
|
||||
|| field.readonly
|
||||
|| field.field.type === 'one2many'
|
||||
|| field.field.type === 'many2many') {
|
||||
return false;
|
||||
}
|
||||
var displayed;
|
||||
switch(field.field.type) {
|
||||
case 'selection':
|
||||
displayed = _(field.values).find(function (option) {
|
||||
return option[0] === value;
|
||||
})[1];
|
||||
break;
|
||||
case 'many2one':
|
||||
displayed = field.value[1] || value;
|
||||
break;
|
||||
default:
|
||||
displayed = value;
|
||||
}
|
||||
|
||||
return {
|
||||
name: name,
|
||||
string: field.string,
|
||||
value: value,
|
||||
displayed: displayed,
|
||||
// convert undefined to false
|
||||
change_default: !!field.field.change_default
|
||||
}
|
||||
})
|
||||
.compact()
|
||||
.sortBy(function (field) { return field.string; })
|
||||
.value();
|
||||
var conditions = _.chain(fields)
|
||||
.filter(function (field) { return field.change_default; })
|
||||
.value();
|
||||
|
||||
var d = new openerp.web.Dialog(this, {
|
||||
title: _t("Set Default"),
|
||||
args: {
|
||||
fields: fields,
|
||||
conditions: conditions
|
||||
},
|
||||
buttons: [
|
||||
{text: _t("Close"), click: function () { d.close(); }},
|
||||
{text: _t("Save default"), click: function () {
|
||||
var $defaults = d.$element.find('#formview_default_fields');
|
||||
var field_to_set = $defaults.val();
|
||||
if (!field_to_set) {
|
||||
$defaults.parent().addClass('invalid');
|
||||
return;
|
||||
}
|
||||
var condition = d.$element.find('#formview_default_conditions').val(),
|
||||
all_users = d.$element.find('#formview_default_all').is(':checked');
|
||||
new openerp.web.DataSet(self, 'ir.values').call(
|
||||
'set_default', [
|
||||
self.dataset.model,
|
||||
field_to_set,
|
||||
self.fields[field_to_set].get_value(),
|
||||
all_users,
|
||||
false,
|
||||
condition || false
|
||||
]).then(function () { d.close(); });
|
||||
}}
|
||||
]
|
||||
});
|
||||
d.template = 'FormView.set_default';
|
||||
d.open();
|
||||
}
|
||||
});
|
||||
openerp.web.FormDialog = openerp.web.Dialog.extend({
|
||||
|
@ -831,7 +923,7 @@ openerp.web.form.Widget = openerp.web.OldWidget.extend(/** @lends openerp.web.fo
|
|||
},
|
||||
stop: function() {
|
||||
this._super.apply(this, arguments);
|
||||
$('div.tipsy').stop().remove();
|
||||
$.fn.tipsy.clear();
|
||||
},
|
||||
process_modifiers: function() {
|
||||
var compute_domain = openerp.web.form.compute_domain;
|
||||
|
@ -861,7 +953,7 @@ openerp.web.form.Widget = openerp.web.OldWidget.extend(/** @lends openerp.web.fo
|
|||
debug: openerp.connection.debug,
|
||||
widget: widget
|
||||
})},
|
||||
gravity: $.fn.tipsy.autoBounds(50, 'n'),
|
||||
gravity: $.fn.tipsy.autoBounds(50, 'nw'),
|
||||
html: true,
|
||||
opacity: 0.85,
|
||||
trigger: 'hover'
|
||||
|
@ -1219,6 +1311,11 @@ openerp.web.form.WidgetLabel = openerp.web.form.Widget.extend({
|
|||
|
||||
this._super(view, node);
|
||||
|
||||
if (this.node.tag == 'label' && !this.string && this.node.children.length) {
|
||||
this.string = this.node.children[0];
|
||||
this.align = 'left';
|
||||
}
|
||||
|
||||
if (this.node.tag == 'label' && (this.align === 'left' || this.node.attrs.colspan || (this.string && this.string.length > 32))) {
|
||||
this.form_template = "WidgetParagraph";
|
||||
this.colspan = parseInt(this.node.attrs.colspan || 1, 10);
|
||||
|
@ -1227,6 +1324,8 @@ openerp.web.form.WidgetLabel = openerp.web.form.Widget.extend({
|
|||
if (isNaN(parseFloat(this.node.attrs.align))) {
|
||||
this.align = 'left';
|
||||
}
|
||||
|
||||
this.multilines = this.string && _.str.lines(this.string).length > 1;
|
||||
} else {
|
||||
this.colspan = 1;
|
||||
this.width = '1%';
|
||||
|
@ -1293,6 +1392,7 @@ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.f
|
|||
this._super.apply(this, arguments);
|
||||
if (this.field.translate) {
|
||||
this.view.translatable_fields.push(this);
|
||||
this.$element.addClass('oe_form_field_translatable');
|
||||
this.$element.find('.oe_field_translate').click(this.on_translate);
|
||||
}
|
||||
if (this.nolabel && openerp.connection.debug) {
|
||||
|
@ -1344,7 +1444,8 @@ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.f
|
|||
if (this.is_valid()) {
|
||||
this.set_value_from_ui();
|
||||
this.view.do_onchange(this);
|
||||
this.view.on_form_changed();
|
||||
this.view.on_form_changed(true);
|
||||
this.view.do_notify_change();
|
||||
} else {
|
||||
this.update_dom(true);
|
||||
}
|
||||
|
@ -1389,7 +1490,7 @@ openerp.web.form.FieldChar = openerp.web.form.Field.extend({
|
|||
},
|
||||
update_dom: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.$element.find('input').prop('disabled', this.readonly);
|
||||
this.$element.find('input').prop('readonly', this.readonly);
|
||||
},
|
||||
set_value_from_ui: function() {
|
||||
this.value = openerp.web.parse_value(this.$element.find('input').val(), this);
|
||||
|
@ -1412,7 +1513,7 @@ openerp.web.form.FieldChar = openerp.web.form.Field.extend({
|
|||
openerp.web.form.FieldID = openerp.web.form.FieldChar.extend({
|
||||
update_dom: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.$element.find('input').prop('disabled', true);
|
||||
this.$element.find('input').prop('readonly', true);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1490,7 +1591,7 @@ openerp.web.DateTimeWidget = openerp.web.OldWidget.extend({
|
|||
showButtonPanel: true
|
||||
});
|
||||
this.$element.find('img.oe_datepicker_trigger').click(function() {
|
||||
if (!self.readonly) {
|
||||
if (!self.readonly && !self.picker('widget').is(':visible')) {
|
||||
self.picker('setDate', self.value ? openerp.web.auto_str_to_date(self.value) : new Date());
|
||||
self.$input_picker.show();
|
||||
self.picker('show');
|
||||
|
@ -1520,7 +1621,7 @@ openerp.web.DateTimeWidget = openerp.web.OldWidget.extend({
|
|||
},
|
||||
set_readonly: function(readonly) {
|
||||
this.readonly = readonly;
|
||||
this.$input.prop('disabled', this.readonly);
|
||||
this.$input.prop('readonly', this.readonly);
|
||||
this.$element.find('img.oe_datepicker_trigger').toggleClass('oe_input_icon_disabled', readonly);
|
||||
},
|
||||
is_valid: function(required) {
|
||||
|
@ -1609,7 +1710,7 @@ openerp.web.form.FieldText = openerp.web.form.Field.extend({
|
|||
},
|
||||
update_dom: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.$element.find('textarea').prop('disabled', this.readonly);
|
||||
this.$element.find('textarea').prop('readonly', this.readonly);
|
||||
},
|
||||
set_value_from_ui: function() {
|
||||
this.value = openerp.web.parse_value(this.$element.find('textarea').val(), this);
|
||||
|
@ -2126,7 +2227,7 @@ openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({
|
|||
},
|
||||
update_dom: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.$input.prop('disabled', this.readonly);
|
||||
this.$input.prop('readonly', this.readonly);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -2248,7 +2349,7 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
|
|||
|
||||
this.viewmanager = new openerp.web.ViewManager(this, this.dataset, views, {});
|
||||
this.viewmanager.template = 'One2Many.viewmanager';
|
||||
this.viewmanager.registry = openerp.web.views.clone({
|
||||
this.viewmanager.registry = openerp.web.views.extend({
|
||||
list: 'openerp.web.form.One2ManyListView',
|
||||
form: 'openerp.web.form.One2ManyFormView',
|
||||
page: 'openerp.web.PageView'
|
||||
|
@ -2326,13 +2427,13 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
|
|||
obj['id'] = _.uniqueId(self.dataset.virtual_id_prefix);
|
||||
obj.defaults = {};
|
||||
self.dataset.to_create.push(obj);
|
||||
self.dataset.cache.push(_.clone(obj));
|
||||
self.dataset.cache.push(_.extend(_.clone(obj), {values: _.clone(command[2])}));
|
||||
ids.push(obj.id);
|
||||
return;
|
||||
case commands.UPDATE:
|
||||
obj['id'] = command[1];
|
||||
self.dataset.to_write.push(obj);
|
||||
self.dataset.cache.push(_.clone(obj));
|
||||
self.dataset.cache.push(_.extend(_.clone(obj), {values: _.clone(command[2])}));
|
||||
ids.push(obj.id);
|
||||
return;
|
||||
case commands.DELETE:
|
||||
|
@ -2539,6 +2640,13 @@ openerp.web.form.One2ManyFormView = openerp.web.FormView.extend({
|
|||
this.$form_header.find('button.oe_form_button_create').click(function() {
|
||||
self.do_save().then(self.on_button_new);
|
||||
});
|
||||
},
|
||||
do_notify_change: function() {
|
||||
if (this.dataset.parent_view) {
|
||||
this.dataset.parent_view.do_notify_change();
|
||||
} else {
|
||||
this._super.apply(this, arguments);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -3151,7 +3259,7 @@ openerp.web.form.FieldBinaryFile = openerp.web.form.FieldBinary.extend({
|
|||
update_dom: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.$element.find('.oe-binary-file-set, .oe-binary-file-clear').toggle(!this.readonly);
|
||||
this.$element.find('input[type=text]').prop('disabled', this.readonly);
|
||||
this.$element.find('input[type=text]').prop('readonly', this.readonly);
|
||||
},
|
||||
set_value: function(value) {
|
||||
this._super.apply(this, arguments);
|
||||
|
|
|
@ -246,7 +246,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
|
|||
self.page = 0; break;
|
||||
case 'last':
|
||||
self.page = Math.floor(
|
||||
self.dataset.ids.length / self.limit());
|
||||
self.dataset.size() / self.limit());
|
||||
break;
|
||||
case 'next':
|
||||
self.page += 1; break;
|
||||
|
@ -293,7 +293,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
|
|||
this.dataset.ids = dataset.ids;
|
||||
|
||||
var limit = this.limit(),
|
||||
total = dataset.ids.length,
|
||||
total = dataset.size(),
|
||||
first = (this.page * limit),
|
||||
last;
|
||||
if (!limit || (total - first) < limit) {
|
||||
|
@ -1317,11 +1317,11 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L
|
|||
if (!self.datagroup.openable) {
|
||||
view.configure_pager(dataset);
|
||||
} else {
|
||||
if (dataset.ids.length == records.length) {
|
||||
if (dataset.size() == records.length) {
|
||||
// only one page
|
||||
self.$row.find('td.oe-group-pagination').empty();
|
||||
} else {
|
||||
var pages = Math.ceil(dataset.ids.length / limit);
|
||||
var pages = Math.ceil(dataset.size() / limit);
|
||||
self.$row
|
||||
.find('.oe-pager-state')
|
||||
.text(_.str.sprintf(_t("%(page)d/%(page_count)d"), {
|
||||
|
|
|
@ -386,7 +386,7 @@ openerp.web.list_editable = function (openerp) {
|
|||
template: 'ListView.row.frame'
|
||||
});
|
||||
var form_widgets = openerp.web.form.widgets;
|
||||
openerp.web.list.form.widgets = form_widgets.clone({
|
||||
openerp.web.list.form.widgets = form_widgets.extend({
|
||||
'frame': 'openerp.web.list.form.WidgetFrame'
|
||||
});
|
||||
// All form widgets inherit a problematic behavior from
|
||||
|
@ -395,7 +395,7 @@ openerp.web.list_editable = function (openerp) {
|
|||
// former should completely remove the cell. We need to override update_dom
|
||||
// on all widgets since we can't just hit on widget itself (I think)
|
||||
var list_form_widgets = openerp.web.list.form.widgets;
|
||||
_(list_form_widgets.map).each(function (widget_path, key) {
|
||||
_(form_widgets.map).each(function (widget_path, key) {
|
||||
if (key === 'frame') { return; }
|
||||
var new_path = 'openerp.web.list.form.' + key;
|
||||
|
||||
|
|
|
@ -92,11 +92,13 @@ openerp.web.page = function (openerp) {
|
|||
openerp.web.page.FieldURIReadonly = openerp.web.page.FieldCharReadonly.extend({
|
||||
form_template: 'FieldURI.readonly',
|
||||
scheme: null,
|
||||
format_value: function (value) {
|
||||
return value;
|
||||
},
|
||||
set_value: function (value) {
|
||||
var displayed = this._super.apply(this, arguments);
|
||||
this.$element.find('a')
|
||||
.attr('href', this.scheme + ':' + displayed)
|
||||
.text(displayed);
|
||||
.attr('href', this.scheme + ':' + value)
|
||||
.text(this.format_value(value));
|
||||
}
|
||||
});
|
||||
openerp.web.page.FieldEmailReadonly = openerp.web.page.FieldURIReadonly.extend({
|
||||
|
@ -105,9 +107,10 @@ openerp.web.page = function (openerp) {
|
|||
openerp.web.page.FieldUrlReadonly = openerp.web.page.FieldURIReadonly.extend({
|
||||
set_value: function (value) {
|
||||
var s = /(\w+):(.+)/.exec(value);
|
||||
if (!s || !(s[1] === 'http' || s[1] === 'https')) { return; }
|
||||
this.scheme = s[1];
|
||||
this._super(s[2]);
|
||||
if (!s) {
|
||||
value = "http://" + value;
|
||||
}
|
||||
this.$element.find('a').attr('href', value).text(value);
|
||||
}
|
||||
});
|
||||
openerp.web.page.FieldBooleanReadonly = openerp.web.form.FieldBoolean.extend({
|
||||
|
@ -242,7 +245,7 @@ openerp.web.page = function (openerp) {
|
|||
}
|
||||
}
|
||||
});
|
||||
openerp.web.page.readonly = openerp.web.form.widgets.clone({
|
||||
openerp.web.page.readonly = openerp.web.form.widgets.extend({
|
||||
'frame': 'openerp.web.page.WidgetFrameReadonly',
|
||||
'char': 'openerp.web.page.FieldCharReadonly',
|
||||
'id': 'openerp.web.page.FieldCharReadonly',
|
||||
|
|
|
@ -602,16 +602,6 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner
|
|||
width: '95%'}, $root).open();
|
||||
});
|
||||
break;
|
||||
case 'customize_object':
|
||||
this.rpc('/web/dataset/search_read', {
|
||||
model: 'ir.model',
|
||||
fields: ['id'],
|
||||
domain: [['model', '=', this.dataset.model]]
|
||||
}, function (result) {
|
||||
self.do_edit_resource('ir.model', result.ids[0], {
|
||||
name : _t("Customize Object") });
|
||||
});
|
||||
break;
|
||||
case 'manage_views':
|
||||
if (current_view.fields_view && current_view.fields_view.arch) {
|
||||
var view_editor = new session.web.ViewEditor(current_view, current_view.$element, this.dataset, current_view.fields_view.arch);
|
||||
|
@ -765,16 +755,21 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner
|
|||
var $logs_list = $logs.find('ul').empty();
|
||||
$logs.toggleClass('oe-has-more', log_records.length > cutoff);
|
||||
_(log_records.reverse()).each(function (record) {
|
||||
var context = {};
|
||||
if (record.context) {
|
||||
try { context = py.eval(record.context).toJSON(); }
|
||||
catch (e) { /* TODO: what do I do now? */ }
|
||||
}
|
||||
$(_.str.sprintf('<li><a href="#">%s</a></li>', record.name))
|
||||
.appendTo($logs_list)
|
||||
.delegate('a', 'click', function (e) {
|
||||
.delegate('a', 'click', function () {
|
||||
self.do_action({
|
||||
type: 'ir.actions.act_window',
|
||||
res_model: record.res_model,
|
||||
res_id: record.res_id,
|
||||
// TODO: need to have an evaluated context here somehow
|
||||
//context: record.context,
|
||||
views: [[false, 'form']]
|
||||
context: context,
|
||||
views: [[context.view_id || false, 'form']]
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
@ -821,10 +816,6 @@ session.web.Sidebar = session.web.OldWidget.extend({
|
|||
}, {
|
||||
label: _t("Export"),
|
||||
callback: view.on_sidebar_export
|
||||
}, {
|
||||
label: _t("View Log"),
|
||||
callback: view.on_sidebar_view_log,
|
||||
classname: 'oe_hide oe_sidebar_view_log'
|
||||
}
|
||||
]);
|
||||
},
|
||||
|
@ -863,18 +854,32 @@ session.web.Sidebar = session.web.OldWidget.extend({
|
|||
}
|
||||
return $section;
|
||||
},
|
||||
|
||||
/**
|
||||
* For each item added to the section:
|
||||
*
|
||||
* ``label``
|
||||
* will be used as the item's name in the sidebar
|
||||
*
|
||||
* ``action``
|
||||
* descriptor for the action which will be executed, ``action`` and
|
||||
* ``callback`` should be exclusive
|
||||
*
|
||||
* ``callback``
|
||||
* function to call when the item is clicked in the sidebar, called
|
||||
* with the item descriptor as its first argument (so information
|
||||
* can be stored as additional keys on the object passed to
|
||||
* ``add_items``)
|
||||
*
|
||||
* ``classname`` (optional)
|
||||
* ``@class`` set on the sidebar serialization of the item
|
||||
*
|
||||
* ``title`` (optional)
|
||||
* will be set as the item's ``@title`` (tooltip)
|
||||
*
|
||||
* @param {String} section_code
|
||||
* @param {Array<{label, action | callback[, classname][, title]}>} items
|
||||
*/
|
||||
add_items: function(section_code, items) {
|
||||
// An item is a dictonary : {
|
||||
// label: label to be displayed for the link,
|
||||
// action: action to be launch when the link is clicked,
|
||||
// callback: a function to be executed when the link is clicked,
|
||||
// classname: optional dom class name for the line,
|
||||
// title: optional title for the link
|
||||
// }
|
||||
// Note: The item should have one action or/and a callback
|
||||
//
|
||||
|
||||
var self = this,
|
||||
$section = this.add_section(_.str.titleize(section_code.replace('_', ' ')), section_code),
|
||||
section_id = $section.attr('id');
|
||||
|
@ -1038,7 +1043,8 @@ session.web.TranslateDialog = session.web.Dialog.extend({
|
|||
},
|
||||
on_button_Save: function() {
|
||||
var trads = {},
|
||||
self = this;
|
||||
self = this,
|
||||
trads_mutex = new $.Mutex();
|
||||
self.$fields_form.find('.oe_trad_field.touched').each(function() {
|
||||
var field = $(this).attr('name').split('-');
|
||||
if (!trads[field[0]]) {
|
||||
|
@ -1051,9 +1057,10 @@ session.web.TranslateDialog = session.web.Dialog.extend({
|
|||
_.each(data, function(value, field) {
|
||||
self.view.fields[field].set_value(value);
|
||||
});
|
||||
} else {
|
||||
self.view.dataset.write(self.view.datarecord.id, data, { 'lang': code });
|
||||
}
|
||||
trads_mutex.exec(function() {
|
||||
return self.view.dataset.write(self.view.datarecord.id, data, { context : { 'lang': code } });
|
||||
});
|
||||
});
|
||||
this.close();
|
||||
},
|
||||
|
@ -1222,8 +1229,6 @@ session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{
|
|||
view_mode : "list"
|
||||
});
|
||||
},
|
||||
on_sidebar_view_log: function() {
|
||||
},
|
||||
sidebar_context: function () {
|
||||
return $.when();
|
||||
},
|
||||
|
|
|
@ -484,7 +484,6 @@
|
|||
<option t-if="view_manager.searchview" value="edit" data-model="ir.ui.view" t-att-data-id="view_manager.searchview.view_id">Edit SearchView</option>
|
||||
<option t-if="view_manager.action" value="edit" t-att-data-model="view_manager.action.type" t-att-data-id="view_manager.action.id">Edit Action</option>
|
||||
<option value="edit_workflow">Edit Workflow</option>
|
||||
<option value="customize_object">Customize Object</option>
|
||||
</t>
|
||||
</t>
|
||||
<t t-name="ViewManagerDebugViewLog">
|
||||
|
@ -529,11 +528,11 @@
|
|||
</div>
|
||||
</t>
|
||||
<t t-name="Sidebar.section.items">
|
||||
<li t-foreach="items" t-as="item" t-att-class="item.classname">
|
||||
<a class="oe_sidebar_action_a" t-att-id="item.element_id" t-att-title="item.title" href="#">
|
||||
<t t-esc="item.label"/>
|
||||
</a>
|
||||
</li>
|
||||
<li t-foreach="items" t-as="item" t-att-class="item.classname">
|
||||
<a class="oe_sidebar_action_a" t-att-id="item.element_id" t-att-title="item.title" href="#">
|
||||
<t t-esc="item.label"/>
|
||||
</a>
|
||||
</li>
|
||||
</t>
|
||||
|
||||
<t t-name="TranslateDialog">
|
||||
|
@ -580,20 +579,21 @@
|
|||
t-att-data-id="record.id" t-att-data-level="level + 1">
|
||||
<t t-set="children" t-value="record[children_field]"/>
|
||||
<t t-set="class" t-value="children and children.length ? 'treeview-tr' : 'treeview-td'"/>
|
||||
<t t-set="rank" t-value="'oe-treeview-first'"/>
|
||||
<t t-set="style" t-value="'background-position: ' + 19*level + 'px; padding-left: ' + 19*level + 'px;'"/>
|
||||
|
||||
<td t-foreach="fields_view" t-as="field"
|
||||
t-if="!field.attrs.modifiers.tree_invisible"
|
||||
t-att-data-id="record.id"
|
||||
t-att-style="color_for(record) + style "
|
||||
t-att-class="(fields[field.attrs.name].type === 'float') or (fields[field.attrs.name].type === 'integer')
|
||||
? (class +' ' +'oe-number') : class">
|
||||
t-attf-class="#{class} #{rank} #{(fields[field.attrs.name].type === 'float') or (fields[field.attrs.name].type === 'integer') ? 'oe-number' : ''}">
|
||||
|
||||
<span t-if="!field.attrs.modifiers.invisible" >
|
||||
<t t-esc="render(record[field.attrs.name], fields[field.attrs.name])" />
|
||||
</span>
|
||||
|
||||
<t t-set="class" t-value="'treeview-td'"/>
|
||||
<t t-set="rank" t-value="''"/>
|
||||
<t t-set="style" t-value="''"/>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -791,6 +791,62 @@
|
|||
</li>
|
||||
</ul>
|
||||
</t>
|
||||
<form t-name="FormView.set_default" class="oe_forms oe_frame">
|
||||
<t t-set="args" t-value="widget.dialog_options.args"/>
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td>
|
||||
<label for="formview_default_fields"
|
||||
class="oe_label oe_align_right">
|
||||
Default:
|
||||
</label>
|
||||
</td>
|
||||
<td class="required">
|
||||
<select id="formview_default_fields">
|
||||
<option value=""/>
|
||||
<option t-foreach="args.fields" t-as="field"
|
||||
t-att-value="field.name">
|
||||
<t t-esc="field.string"/> = <t t-esc="field.displayed"/>
|
||||
</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr t-if="args.conditions.length">
|
||||
<td>
|
||||
<label for="formview_default_conditions"
|
||||
class="oe_label oe_align_right">
|
||||
Condition:
|
||||
</label>
|
||||
</td>
|
||||
<td>
|
||||
<select id="formview_default_conditions">
|
||||
<option value=""/>
|
||||
<option t-foreach="args.conditions" t-as="cond"
|
||||
t-att-value="cond.name + '=' + cond.value">
|
||||
<t t-esc="cond.string"/>=<t t-esc="cond.displayed"/>
|
||||
</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<input type="radio" id="formview_default_self"
|
||||
value="self" name="scope" checked="checked"/>
|
||||
<label for="formview_default_self" class="oe_label"
|
||||
style="display: inline;">
|
||||
Only you
|
||||
</label>
|
||||
<br/>
|
||||
<input type="radio" id="formview_default_all"
|
||||
value="all" name="scope"/>
|
||||
<label for="formview_default_all" class="oe_label"
|
||||
style="display: inline;">
|
||||
All users
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<t t-name="Widget">
|
||||
Unhandled widget
|
||||
<t t-js="dict">console.warn('Unhandled widget', dict.widget);</t>
|
||||
|
@ -906,6 +962,10 @@
|
|||
<span class="oe_tooltip_technical_title">Modifiers:</span>
|
||||
<t t-esc="widget.node.attrs.modifiers"/>
|
||||
</li>
|
||||
<li t-if="widget.field and widget.field.change_default" data-item="change_default">
|
||||
<span class="oe_tooltip_technical_title">Change default:</span>
|
||||
Yes
|
||||
</li>
|
||||
<li t-if="widget.node.attrs.on_change" data-item="on_change">
|
||||
<span class="oe_tooltip_technical_title">On change:</span>
|
||||
<t t-esc="widget.node.attrs.on_change"/>
|
||||
|
@ -927,7 +987,7 @@
|
|||
</ul>
|
||||
</t>
|
||||
<t t-name="WidgetParagraph">
|
||||
<p t-attf-class="oe_form_paragraph oe_align_#{widget.align}"><t t-esc="widget.string"/></p>
|
||||
<p t-attf-class="oe_form_paragraph oe_align_#{widget.align} #{widget.multilines ? 'oe_multilines' : ''}"><t t-esc="widget.string"/></p>
|
||||
</t>
|
||||
<t t-name="FieldChar">
|
||||
<input t-att-type="widget.password ? 'password' : 'text'" size="1"
|
||||
|
@ -945,7 +1005,7 @@
|
|||
</t>
|
||||
<t t-name="FieldURI.readonly">
|
||||
<div>
|
||||
<a href="#" class="oe_form_uri">#</a>
|
||||
<a href="#" class="oe_form_uri"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="FieldEmail">
|
||||
|
@ -1217,7 +1277,11 @@
|
|||
<option class="oe-filters-title" value="">Filters</option>
|
||||
<optgroup label="-- Filters --">
|
||||
<t t-foreach="filters" t-as="filter">
|
||||
<option t-attf-value="get:#{filter_index}"><t t-esc="filter.name"/></option>
|
||||
<option t-attf-value="get:#{filter_index}"
|
||||
t-att-disabled="filter.disabled and 'disabled'"
|
||||
t-att-title="filter.disabled and disabled_filter_message">
|
||||
<t t-esc="filter.name"/>
|
||||
</option>
|
||||
</t>
|
||||
</optgroup>
|
||||
<optgroup label="-- Actions --">
|
||||
|
@ -1293,7 +1357,7 @@
|
|||
<span t-if="attrs.help">?</span>
|
||||
</label>
|
||||
<div t-att-style="style">
|
||||
<span t-att-id="element_id"></span>
|
||||
<span t-att-id="element_id"/>
|
||||
<t t-if="filters.length" t-raw="filters.render(defaults)"/>
|
||||
</div>
|
||||
</t>
|
||||
|
@ -1479,9 +1543,9 @@
|
|||
</table>
|
||||
</t>
|
||||
<t t-name="view_editor.row">
|
||||
<tr class="oe_view_editor_row" t-att-id="'viewedit-' + rec.id" t-att-level="rec.level" t-foreach="data" t-as="rec">
|
||||
<td class="oe_view_editor_colum" width="85%">
|
||||
<table class="oe_view_editor_tree_grid">
|
||||
<tr t-att-id="'viewedit-' + rec.id" t-att-level="rec.level" t-foreach="data" t-as="rec">
|
||||
<td width="90%">
|
||||
<table class="oe_view_editor_field">
|
||||
<tr>
|
||||
<td width="16px" t-att-style="'background-position: ' + 20*rec.level + 'px; padding-left: ' + 20*rec.level + 'px'">
|
||||
<img t-if="rec.child_id.length" t-att-id="'parentimg-' + rec.id"
|
||||
|
@ -1495,30 +1559,24 @@
|
|||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td align="left" class="oe_view_editor_colum" width="15%">
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td width="20%">
|
||||
<img t-if="rec.att_list.length"
|
||||
id="side-add" src="/web/static/src/img/icons/gtk-add.png" style="cursor: pointer;"/>
|
||||
</td>
|
||||
<td width="20%">
|
||||
<img id="side-remove" src="/web/static/src/img/icons/gtk-remove.png" style="cursor: pointer;"/>
|
||||
</td>
|
||||
<td width="20%">
|
||||
<img t-if="rec.att_list.length and !_.include(no_properties, rec.att_list[0])"
|
||||
id="side-edit" src="/web/static/src/img/icons/gtk-edit.png" style="cursor: pointer;"/>
|
||||
</td>
|
||||
<td width="20%">
|
||||
<img t-if="rec.att_list.length"
|
||||
id="side-up" src="/web/static/src/img/icons/gtk-go-up.png" style="cursor: pointer;"/>
|
||||
</td>
|
||||
<td width="20%">
|
||||
<img t-if="rec.att_list.length"
|
||||
id="side-down" src="/web/static/src/img/icons/gtk-go-down.png" style="cursor: pointer;"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<td width="2%">
|
||||
<img t-if="rec.att_list.length"
|
||||
id="side-add" src="/web/static/src/img/icons/gtk-add.png" style="cursor: pointer;"/>
|
||||
</td>
|
||||
<td width="2%">
|
||||
<img id="side-remove" src="/web/static/src/img/icons/gtk-remove.png" style="cursor: pointer;"/>
|
||||
</td>
|
||||
<td width="2%">
|
||||
<img t-if="rec.att_list.length and !_.include(no_properties, rec.att_list[0])"
|
||||
id="side-edit" src="/web/static/src/img/icons/gtk-edit.png" style="cursor: pointer;"/>
|
||||
</td>
|
||||
<td width="2%">
|
||||
<img t-if="rec.att_list.length"
|
||||
id="side-up" src="/web/static/src/img/icons/gtk-go-up.png" style="cursor: pointer;"/>
|
||||
</td>
|
||||
<td width="2%">
|
||||
<img t-if="rec.att_list.length"
|
||||
id="side-down" src="/web/static/src/img/icons/gtk-go-down.png" style="cursor: pointer;"/>
|
||||
</td>
|
||||
<t t-if="rec.child_id.length">
|
||||
<t t-set="data" t-value="rec.child_id"/>
|
||||
|
|
|
@ -71,6 +71,15 @@ $(document).ready(function () {
|
|||
strictEqual(
|
||||
openerp.web.format_value(0.0085, {type:'float', widget:'float_time'}),
|
||||
'00:01');
|
||||
strictEqual(
|
||||
openerp.web.format_value(-1.0, {type:'float', widget:'float_time'}),
|
||||
'-01:00');
|
||||
strictEqual(
|
||||
openerp.web.format_value(-0.9853, {type:'float', widget:'float_time'}),
|
||||
'-00:59');
|
||||
strictEqual(
|
||||
openerp.web.format_value(-0.0085, {type:'float', widget:'float_time'}),
|
||||
'-00:01');
|
||||
});
|
||||
test("format_float", function () {
|
||||
var fl = 12.1234;
|
||||
|
@ -195,4 +204,29 @@ $(document).ready(function () {
|
|||
equal(openerp.web.format_value(6000, {type: 'float'}),
|
||||
'6.000,00');
|
||||
});
|
||||
module('custom-date-formats', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init();
|
||||
window.openerp.web.core(openerp);
|
||||
window.openerp.web.dates(openerp);
|
||||
window.openerp.web.formats(openerp);
|
||||
}
|
||||
});
|
||||
test('format stripper', function () {
|
||||
strictEqual(openerp.web.strip_raw_chars('%a, %Y %b %d'), '%a, %Y %b %d');
|
||||
strictEqual(openerp.web.strip_raw_chars('%a, %Y.eko %bren %da'), '%a, %Y. %b %d');
|
||||
});
|
||||
test('ES date format', function () {
|
||||
openerp.web._t.database.parameters.date_format = '%a, %Y %b %d';
|
||||
var date = openerp.web.str_to_date("2009-05-04");
|
||||
strictEqual(openerp.web.format_value(date, {type:"date"}), 'Mon, 2009 May 04');
|
||||
strictEqual(openerp.web.parse_value('Mon, 2009 May 04', {type: 'date'}), '2009-05-04');
|
||||
});
|
||||
test('extended ES date format', function () {
|
||||
openerp.web._t.database.parameters.date_format = '%a, %Y.eko %bren %da';
|
||||
var date = openerp.web.str_to_date("2009-05-04");
|
||||
strictEqual(openerp.web.format_value(date, {type:"date"}), 'Mon, 2009. May 04');
|
||||
strictEqual(openerp.web.parse_value('Mon, 2009. May 04', {type: 'date'}), '2009-05-04');
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -6,6 +6,7 @@ $(document).ready(function () {
|
|||
window.openerp.web.core(openerp);
|
||||
openerp.web.Foo = {};
|
||||
openerp.web.Bar = {};
|
||||
openerp.web.Foo2 = {};
|
||||
}
|
||||
});
|
||||
test('key fetch', function () {
|
||||
|
@ -30,4 +31,43 @@ $(document).ready(function () {
|
|||
.add('bar', 'openerp.web.Bar');
|
||||
strictEqual(reg.get_object('bar'), openerp.web.Bar);
|
||||
});
|
||||
test('extension', function () {
|
||||
var reg = new openerp.web.Registry({
|
||||
foo: 'openerp.web.Foo',
|
||||
bar: 'openerp.web.Bar'
|
||||
});
|
||||
|
||||
var reg2 = reg.extend({ 'foo': 'openerp.web.Foo2' });
|
||||
strictEqual(reg.get_object('foo'), openerp.web.Foo);
|
||||
strictEqual(reg2.get_object('foo'), openerp.web.Foo2);
|
||||
});
|
||||
test('remain-linked', function () {
|
||||
var reg = new openerp.web.Registry({
|
||||
foo: 'openerp.web.Foo',
|
||||
bar: 'openerp.web.Bar'
|
||||
});
|
||||
|
||||
var reg2 = reg.extend();
|
||||
reg.add('foo2', 'openerp.web.Foo2');
|
||||
strictEqual(reg.get_object('foo2'), openerp.web.Foo2);
|
||||
strictEqual(reg2.get_object('foo2'), openerp.web.Foo2);
|
||||
});
|
||||
test('multiget', function () {
|
||||
var reg = new openerp.web.Registry({
|
||||
foo: 'openerp.web.Foo',
|
||||
bar: 'openerp.web.Bar'
|
||||
});
|
||||
|
||||
strictEqual(reg.get_any(['qux', 'grault', 'bar', 'foo']),
|
||||
openerp.web.Bar);
|
||||
});
|
||||
test('extended-multiget', function () {
|
||||
var reg = new openerp.web.Registry({
|
||||
foo: 'openerp.web.Foo',
|
||||
bar: 'openerp.web.Bar'
|
||||
});
|
||||
var reg2 = reg.extend();
|
||||
strictEqual(reg2.get_any(['qux', 'grault', 'bar', 'foo']),
|
||||
openerp.web.Bar);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
<!-- jquery -->
|
||||
<script src="/web/static/lib/jquery/jquery-1.6.4.js"></script>
|
||||
<script src="/web/static/lib/jquery.ui/js/jquery-ui-1.8.9.custom.min.js"></script>
|
||||
<script src="/web/static/lib/jquery.ui/js/jquery-ui-1.8.17.custom.min.js"></script>
|
||||
<script src="/web/static/lib/jquery.ba-bbq/jquery.ba-bbq.js"></script>
|
||||
|
||||
<script src="/web/static/lib/datejs/globalization/en-US.js"></script>
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# English (United Kingdom) translation for openerp-web
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openerp-web package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openerp-web\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-02-06 17:33+0100\n"
|
||||
"PO-Revision-Date: 2012-02-09 11:36+0000\n"
|
||||
"Last-Translator: John Bradshaw <Unknown>\n"
|
||||
"Language-Team: English (United Kingdom) <en_GB@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-10 05:09+0000\n"
|
||||
"X-Generator: Launchpad (build 14771)\n"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:11
|
||||
msgid "Calendar"
|
||||
msgstr "Calendar"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:466
|
||||
msgid "Responsible"
|
||||
msgstr "Responsible"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:504
|
||||
msgid "Navigator"
|
||||
msgstr "Navigator"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:5
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:6
|
||||
msgid " "
|
||||
msgstr " "
|
|
@ -8,29 +8,29 @@ msgstr ""
|
|||
"Project-Id-Version: openerp-web\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-02-06 17:33+0100\n"
|
||||
"PO-Revision-Date: 2011-10-18 10:41+0000\n"
|
||||
"Last-Translator: Amós Oviedo <Unknown>\n"
|
||||
"PO-Revision-Date: 2012-02-13 12:43+0000\n"
|
||||
"Last-Translator: luis tobar <Unknown>\n"
|
||||
"Language-Team: Spanish <es@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-07 04:59+0000\n"
|
||||
"X-Generator: Launchpad (build 14747)\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-14 06:19+0000\n"
|
||||
"X-Generator: Launchpad (build 14781)\n"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:11
|
||||
msgid "Calendar"
|
||||
msgstr ""
|
||||
msgstr "Calendario"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:466
|
||||
msgid "Responsible"
|
||||
msgstr ""
|
||||
msgstr "Responsable"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:504
|
||||
msgid "Navigator"
|
||||
msgstr ""
|
||||
msgstr "Navegador"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:5
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
# Spanish translation for openerp-web
|
||||
# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
|
||||
# This file is distributed under the same license as the openerp-web package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openerp-web\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2012-02-06 17:33+0100\n"
|
||||
"PO-Revision-Date: 2012-02-16 21:34+0000\n"
|
||||
"Last-Translator: Carlos Vásquez (CLEARCORP) "
|
||||
"<carlos.vasquez@clearcorp.co.cr>\n"
|
||||
"Language-Team: Spanish <es@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n"
|
||||
"X-Generator: Launchpad (build 14814)\n"
|
||||
"Language: es\n"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:11
|
||||
msgid "Calendar"
|
||||
msgstr "Calendario"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:466
|
||||
msgid "Responsible"
|
||||
msgstr "Responsable"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:504
|
||||
msgid "Navigator"
|
||||
msgstr "Navegador"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:5
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:6
|
||||
msgid " "
|
||||
msgstr " "
|
|
@ -0,0 +1,39 @@
|
|||
# Basque translation for openerp-web
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openerp-web package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openerp-web\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-02-06 17:33+0100\n"
|
||||
"PO-Revision-Date: 2012-02-08 07:27+0000\n"
|
||||
"Last-Translator: Daniel Campos <Unknown>\n"
|
||||
"Language-Team: Basque <eu@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-09 07:27+0000\n"
|
||||
"X-Generator: Launchpad (build 14763)\n"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:11
|
||||
msgid "Calendar"
|
||||
msgstr "Egutegia"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:466
|
||||
msgid "Responsible"
|
||||
msgstr "Arduraduna"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:504
|
||||
msgid "Navigator"
|
||||
msgstr "Nabigatzailea"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:5
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:6
|
||||
msgid " "
|
||||
msgstr " "
|
|
@ -8,29 +8,29 @@ msgstr ""
|
|||
"Project-Id-Version: openerp-web\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-02-06 17:33+0100\n"
|
||||
"PO-Revision-Date: 2011-10-23 12:12+0000\n"
|
||||
"PO-Revision-Date: 2012-02-15 10:37+0000\n"
|
||||
"Last-Translator: Fabrice (OpenERP) <Unknown>\n"
|
||||
"Language-Team: French <fr@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-07 04:59+0000\n"
|
||||
"X-Generator: Launchpad (build 14747)\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-16 05:21+0000\n"
|
||||
"X-Generator: Launchpad (build 14781)\n"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:11
|
||||
msgid "Calendar"
|
||||
msgstr ""
|
||||
msgstr "Calendrier"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:466
|
||||
msgid "Responsible"
|
||||
msgstr ""
|
||||
msgstr "Responsable"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:504
|
||||
msgid "Navigator"
|
||||
msgstr ""
|
||||
msgstr "Navigateur"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:5
|
||||
|
|
|
@ -8,29 +8,29 @@ msgstr ""
|
|||
"Project-Id-Version: openerp-web\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-02-06 17:33+0100\n"
|
||||
"PO-Revision-Date: 2011-10-19 10:25+0000\n"
|
||||
"Last-Translator: Amós Oviedo <Unknown>\n"
|
||||
"PO-Revision-Date: 2012-02-09 14:24+0000\n"
|
||||
"Last-Translator: Vicente <jviares@gmail.com>\n"
|
||||
"Language-Team: Galician <gl@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-07 04:59+0000\n"
|
||||
"X-Generator: Launchpad (build 14747)\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-10 05:09+0000\n"
|
||||
"X-Generator: Launchpad (build 14771)\n"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:11
|
||||
msgid "Calendar"
|
||||
msgstr ""
|
||||
msgstr "Calendario"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:466
|
||||
msgid "Responsible"
|
||||
msgstr ""
|
||||
msgstr "Responsable"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:504
|
||||
msgid "Navigator"
|
||||
msgstr ""
|
||||
msgstr "Navegador"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:5
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# Indonesian translation for openerp-web
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openerp-web package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openerp-web\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-02-06 17:33+0100\n"
|
||||
"PO-Revision-Date: 2012-02-08 14:59+0000\n"
|
||||
"Last-Translator: Budi Iskandar <Unknown>\n"
|
||||
"Language-Team: Indonesian <id@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-09 07:27+0000\n"
|
||||
"X-Generator: Launchpad (build 14763)\n"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:11
|
||||
msgid "Calendar"
|
||||
msgstr "Kalender"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:466
|
||||
msgid "Responsible"
|
||||
msgstr "Yang Bertanggung Jawab"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:504
|
||||
msgid "Navigator"
|
||||
msgstr "Pengarah"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:5
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:6
|
||||
msgid " "
|
||||
msgstr " "
|
|
@ -8,29 +8,29 @@ msgstr ""
|
|||
"Project-Id-Version: openerp-web\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-02-06 17:33+0100\n"
|
||||
"PO-Revision-Date: 2011-10-08 13:39+0000\n"
|
||||
"Last-Translator: Nicola Riolini - Micronaet <Unknown>\n"
|
||||
"PO-Revision-Date: 2012-02-16 21:55+0000\n"
|
||||
"Last-Translator: Davide Corio - agilebg.com <davide.corio@agilebg.com>\n"
|
||||
"Language-Team: Italian <it@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-07 04:59+0000\n"
|
||||
"X-Generator: Launchpad (build 14747)\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n"
|
||||
"X-Generator: Launchpad (build 14814)\n"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:11
|
||||
msgid "Calendar"
|
||||
msgstr ""
|
||||
msgstr "Calendario"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:466
|
||||
msgid "Responsible"
|
||||
msgstr ""
|
||||
msgstr "Responsabile"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:504
|
||||
msgid "Navigator"
|
||||
msgstr ""
|
||||
msgstr "Navigatore"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:5
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# Macedonian translation for openerp-web
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openerp-web package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openerp-web\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-02-06 17:33+0100\n"
|
||||
"PO-Revision-Date: 2012-02-08 11:05+0000\n"
|
||||
"Last-Translator: Nikola Stojanoski <nstojanoski@vion.mk>\n"
|
||||
"Language-Team: Macedonian <mk@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-09 07:27+0000\n"
|
||||
"X-Generator: Launchpad (build 14763)\n"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:11
|
||||
msgid "Calendar"
|
||||
msgstr "Календар"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:466
|
||||
msgid "Responsible"
|
||||
msgstr "Одговорен"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:504
|
||||
msgid "Navigator"
|
||||
msgstr "Навигатор"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:5
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:6
|
||||
msgid " "
|
||||
msgstr " "
|
|
@ -8,19 +8,19 @@ msgstr ""
|
|||
"Project-Id-Version: openerp-web\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-02-06 17:33+0100\n"
|
||||
"PO-Revision-Date: 2011-12-06 11:46+0000\n"
|
||||
"Last-Translator: Douwe Wullink (Dypalio) <Unknown>\n"
|
||||
"PO-Revision-Date: 2012-02-16 14:02+0000\n"
|
||||
"Last-Translator: Erwin <Unknown>\n"
|
||||
"Language-Team: Dutch <nl@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-07 04:59+0000\n"
|
||||
"X-Generator: Launchpad (build 14747)\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n"
|
||||
"X-Generator: Launchpad (build 14814)\n"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:11
|
||||
msgid "Calendar"
|
||||
msgstr ""
|
||||
msgstr "Agenda"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:466
|
||||
|
|
|
@ -8,29 +8,29 @@ msgstr ""
|
|||
"Project-Id-Version: openerp-web\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-02-06 17:33+0100\n"
|
||||
"PO-Revision-Date: 2011-10-07 09:05+0000\n"
|
||||
"Last-Translator: Niels Huylebroeck <Unknown>\n"
|
||||
"PO-Revision-Date: 2012-02-08 16:46+0000\n"
|
||||
"Last-Translator: Els Van Vossel (Agaplan) <Unknown>\n"
|
||||
"Language-Team: Dutch (Belgium) <nl_BE@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-07 04:59+0000\n"
|
||||
"X-Generator: Launchpad (build 14747)\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-09 07:27+0000\n"
|
||||
"X-Generator: Launchpad (build 14763)\n"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:11
|
||||
msgid "Calendar"
|
||||
msgstr ""
|
||||
msgstr "Kalender"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:466
|
||||
msgid "Responsible"
|
||||
msgstr ""
|
||||
msgstr "Verantwoordelijke"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:504
|
||||
msgid "Navigator"
|
||||
msgstr ""
|
||||
msgstr "Navigator"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:5
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# Polish translation for openerp-web
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openerp-web package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openerp-web\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-02-06 17:33+0100\n"
|
||||
"PO-Revision-Date: 2012-02-08 11:19+0000\n"
|
||||
"Last-Translator: drygal <Unknown>\n"
|
||||
"Language-Team: Polish <pl@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-09 07:27+0000\n"
|
||||
"X-Generator: Launchpad (build 14763)\n"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:11
|
||||
msgid "Calendar"
|
||||
msgstr "Kalendarz"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:466
|
||||
msgid "Responsible"
|
||||
msgstr "Odpowiedzialny"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:504
|
||||
msgid "Navigator"
|
||||
msgstr "Nawigator"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:5
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:6
|
||||
msgid " "
|
||||
msgstr " "
|
|
@ -0,0 +1,39 @@
|
|||
# Serbian Latin translation for openerp-web
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openerp-web package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openerp-web\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-02-06 17:33+0100\n"
|
||||
"PO-Revision-Date: 2012-02-09 20:58+0000\n"
|
||||
"Last-Translator: zmmaj <Unknown>\n"
|
||||
"Language-Team: Serbian Latin <sr@latin@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-02-10 05:09+0000\n"
|
||||
"X-Generator: Launchpad (build 14771)\n"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:11
|
||||
msgid "Calendar"
|
||||
msgstr "Kalendar"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:466
|
||||
msgid "Responsible"
|
||||
msgstr "Odgovorni"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:504
|
||||
msgid "Navigator"
|
||||
msgstr "Navigator"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:5
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:6
|
||||
msgid " "
|
||||
msgstr " "
|
|
@ -214,7 +214,7 @@
|
|||
background-color:white;
|
||||
}
|
||||
.openerp .oe_cal_month .dhx_cal_data {
|
||||
overflow-y: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -350,7 +350,8 @@ openerp.web_calendar.CalendarView = openerp.web.View.extend({
|
|||
event_obj['end_date'] = new Date(event_obj['start_date']);
|
||||
event_obj['end_date'].addHours(1);
|
||||
} else {
|
||||
event_obj['end_date'].addSeconds(-1);
|
||||
event_obj['start_date'].addHours(8);
|
||||
event_obj['end_date'].addHours(-4);
|
||||
}
|
||||
this.do_create_event_with_formdialog(event_id, event_obj);
|
||||
// return false;
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
import controllers
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"name": "Web Chat",
|
||||
"category": "Hidden",
|
||||
"description":
|
||||
"""
|
||||
OpenERP Web chat module.
|
||||
""",
|
||||
"version": "2.0",
|
||||
"depends": ['web'],
|
||||
"js": [
|
||||
'static/lib/AjaxIM/js/jquery.jsonp-1.1.0.js',
|
||||
'static/lib/AjaxIM/js/jquery.jstore-all-min.js',
|
||||
'static/lib/AjaxIM/js/jquery.md5.js',
|
||||
'static/lib/AjaxIM/js/im.js',
|
||||
'static/src/js/web_chat.js'
|
||||
],
|
||||
"css": [],
|
||||
'active': False,
|
||||
'installable': False,
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
import main
|
|
@ -1,215 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import time
|
||||
|
||||
import simplejson
|
||||
import web.common.http as openerpweb
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
#----------------------------------------------------------
|
||||
# OpenERP Web ajaxim Controllers
|
||||
#----------------------------------------------------------
|
||||
class PollServerMessageQueue(object):
|
||||
def __init__(self):
|
||||
# message queue
|
||||
self.messages = []
|
||||
# online users
|
||||
self.users = {}
|
||||
# should contains: {
|
||||
# 'user1234' : { s:1, m:"status message", timestamp: last_contact_timestamp }
|
||||
# }
|
||||
def userlist(self, req):
|
||||
userlist = [users for users in req.applicationsession['users']]
|
||||
|
||||
# userlist = [
|
||||
# {"u": "Guest130205108745.47", "s": {"s": 1, "m": ""}, "g": "Users"},
|
||||
# {"u": "Guest130209838956.76", "s": {"s": 1, "m": ""}, "g": "Users"},
|
||||
# ]
|
||||
|
||||
return userlist
|
||||
|
||||
def write(self, m_type, m_from, m_to, m_message, m_group):
|
||||
self.messages.append({'type': m_type, 'from': m_from, 'to': m_to, 'message': m_message, 'group': m_group})
|
||||
# when status message update users
|
||||
pass
|
||||
|
||||
def read(self, recipient, timestamp):
|
||||
for msg in self.messages:
|
||||
if msg['to'] == recipient:
|
||||
return self.messages
|
||||
|
||||
def gc(self):
|
||||
# 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())
|
||||
mq.messages = []
|
||||
|
||||
#r = 'logged in'
|
||||
#u = generate random.randint(0,2**32)
|
||||
#f = mq.userlist()
|
||||
|
||||
# username = 'Guest'+ str(random.randint(0, 2**32))
|
||||
#
|
||||
# if not req.applicationsession.get('users'):
|
||||
# req.applicationsession['users'] = [{'u': username, 's':{'s':1, 'm':''}, 'g':'Users'}]
|
||||
# else:
|
||||
# req.applicationsession['users'].append({'u': username, 's':{'s':1, 'm':''}, 'g':'Users'})
|
||||
req.applicationsession['users'] = [{'u': 'Guest1', 's':{'s':1, 'm':'111'}, 'g':'Users'},
|
||||
{'u': 'Guest2', 's':{'s':1, 'm':'222'}, 'g':'Users'},
|
||||
{'u': 'Guest3', 's':{'s':1, 'm':'333'}, 'g':'Users'}]
|
||||
|
||||
# Temporary Guest1 is my current user
|
||||
req.applicationsession['current_user'] = 'Guest1'
|
||||
|
||||
|
||||
return simplejson.dumps({'r': 'logged in', 'u': 'Guest1', 's': 'f9e1811536f19ad5b9e00376f9ff1532',
|
||||
'f': [{'u': 'Guest1', 's':{'s':1, 'm':'111'}, 'g':'Users'},
|
||||
{'u': 'Guest2', 's':{'s':1, 'm':'222'}, 'g':'Users'},
|
||||
{'u': 'Guest3', 's':{'s':1, 'm':'333'}, '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":"xxxxxx"}]);
|
||||
|
||||
('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>'
|
||||
|
||||
"""
|
||||
mq = req.applicationsession.setdefault("web_chat", PollServerMessageQueue())
|
||||
|
||||
# Method: Long Poll
|
||||
|
||||
|
||||
msg = '[]'
|
||||
|
||||
for i in range(5):
|
||||
received_msg = mq.read('Guest1', i)
|
||||
if received_msg:
|
||||
msg = self._pollParseMessages(received_msg)
|
||||
mq.messages = []
|
||||
return '%s'%kw.get('callback', '') + '(' + str(msg) + ');'
|
||||
else:
|
||||
msg = '[]'
|
||||
time.sleep(2)
|
||||
return '%s'%kw.get('callback', '') + '(' + str(msg) + ');'
|
||||
|
||||
@openerpweb.httprequest
|
||||
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');
|
||||
|
||||
"""
|
||||
|
||||
to = kw.get('to')
|
||||
message = kw.get('message')
|
||||
|
||||
mq = req.applicationsession.setdefault("web_chat", PollServerMessageQueue())
|
||||
|
||||
|
||||
if not req.applicationsession['current_user']:
|
||||
return dict(r='error', e='no session found')
|
||||
|
||||
if not to:
|
||||
return dict(r='error', e='no_recipient')
|
||||
|
||||
if message:
|
||||
mq.write(m_type="m", m_from=req.applicationsession['current_user'], m_to=to, m_message=message, m_group="Users")
|
||||
return '%s'%kw.get('callback', '') + '(' + simplejson.dumps({'r': 'sent'}) + ')'
|
||||
else:
|
||||
return {'r': 'error', 'e': 'send error'}
|
||||
|
||||
@openerpweb.httprequest
|
||||
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');
|
||||
"""
|
||||
mq = req.applicationsession.setdefault("web_chat", PollServerMessageQueue())
|
||||
|
||||
_logger.debug("======== chat status ======== %s", kw)
|
||||
# mq.write()
|
||||
return {"action": ""}
|
||||
|
||||
def _pollParseMessages(self, messages):
|
||||
msg_arr = []
|
||||
for msg in messages:
|
||||
msg_arr.append({"t": str(msg['type']), "s": str(msg['from']), "r": str(msg['to']), "m": str(msg['message'])})
|
||||
|
||||
return msg_arr
|
||||
|
||||
def _sanitize(self, message):
|
||||
return message.replace('>', '>').replace('<', '<').replace('&', '&');
|
||||
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
# Translations template for PROJECT.
|
||||
# Copyright (C) 2012 ORGANIZATION
|
||||
# This file is distributed under the same license as the PROJECT project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2012-02-06 17:33+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 0.9.6\n"
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
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.
|
|
@ -1,79 +0,0 @@
|
|||
// 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();
|
||||
};
|
||||
})();
|
|
@ -1,19 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||
<head>
|
||||
<title>Flash External Object</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<script type="text/javascript">
|
||||
/**
|
||||
* This function captures the flash_ready event. We need to relay this
|
||||
* back to the parent so it knows flash is ready.
|
||||
*/
|
||||
function flash_ready(){
|
||||
parent.flash_ready();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#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>
|
|
@ -1,269 +0,0 @@
|
|||
/*
|
||||
* 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);
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* jStore - Persistent Client-Side Storage
|
||||
*
|
||||
* Copyright (c) 2009 Eric Garside (http://eric.garside.name)
|
||||
*
|
||||
* Dual licensed under:
|
||||
* MIT: http://www.opensource.org/licenses/mit-license.php
|
||||
* GPLv3: http://www.opensource.org/licenses/gpl-3.0.html
|
||||
*/
|
||||
/*
|
||||
* 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);
|
|
@ -1,963 +0,0 @@
|
|||
/*!
|
||||
* jStore - Persistent Client-Side Storage
|
||||
*
|
||||
* Copyright (c) 2009 Eric Garside (http://eric.garside.name)
|
||||
*
|
||||
* Dual licensed under:
|
||||
* MIT: http://www.opensource.org/licenses/mit-license.php
|
||||
* GPLv3: http://www.opensource.org/licenses/gpl-3.0.html
|
||||
*/
|
||||
/*!
|
||||
* 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);
|
|
@ -1,230 +0,0 @@
|
|||
|
||||
/**
|
||||
* 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);
|
|
@ -1,8 +0,0 @@
|
|||
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
|
||||
----------------------------------------------------------
|
Before Width: | Height: | Size: 868 B |
Before Width: | Height: | Size: 814 B |
Before Width: | Height: | Size: 853 B |
Before Width: | Height: | Size: 853 B |
Before Width: | Height: | Size: 850 B |
Before Width: | Height: | Size: 843 B |
Before Width: | Height: | Size: 860 B |
Before Width: | Height: | Size: 846 B |