[MERGE] changes from trunk
bzr revid: xmo@openerp.com-20110905075537-j2qn6i8xzg92x73m
This commit is contained in:
@@ -1 +1,6 @@
|
||||
import common
|
||||
import controllers
|
||||
|
||||
# TODO
|
||||
# if we detect that we are imported from the openerp server register common.Root() as a wsgi entry point
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/python
|
||||
# TODO if from openerpserver use backendlocal
|
||||
# from backendlocal import *
|
||||
from backendrpc import *
|
||||
from dispatch import *
|
||||
@@ -0,0 +1,23 @@
|
||||
#----------------------------------------------------------
|
||||
# OpenERPSession local openerp backend access
|
||||
#----------------------------------------------------------
|
||||
class OpenERPUnboundException(Exception):
|
||||
pass
|
||||
|
||||
class OpenERPConnector(object):
|
||||
pass
|
||||
|
||||
class OpenERPAuth(object):
|
||||
pass
|
||||
|
||||
class OpenERPModel(object):
|
||||
def __init__(self, session, model):
|
||||
self._session = session
|
||||
self._model = model
|
||||
|
||||
def __getattr__(self, name):
|
||||
return lambda *l:self._session.execute(self._model, name, *l)
|
||||
|
||||
class OpenERPSession(object):
|
||||
def __init__(self, model_factory=OpenERPModel):
|
||||
pass
|
||||
@@ -0,0 +1,199 @@
|
||||
#!/usr/bin/python
|
||||
import datetime
|
||||
import dateutil.relativedelta
|
||||
import time
|
||||
import xmlrpclib
|
||||
|
||||
import nonliterals
|
||||
#----------------------------------------------------------
|
||||
# OpenERPSession RPC openerp backend access
|
||||
#----------------------------------------------------------
|
||||
class OpenERPUnboundException(Exception):
|
||||
pass
|
||||
|
||||
class OpenERPConnector(object):
|
||||
pass
|
||||
|
||||
class OpenERPAuth(object):
|
||||
pass
|
||||
|
||||
class OpenERPModel(object):
|
||||
def __init__(self, session, model):
|
||||
self._session = session
|
||||
self._model = model
|
||||
|
||||
def __getattr__(self, name):
|
||||
return lambda *l:self._session.execute(self._model, name, *l)
|
||||
|
||||
class OpenERPSession(object):
|
||||
"""
|
||||
An OpenERP RPC session, a given user can own multiple such sessions
|
||||
in a web session.
|
||||
|
||||
.. attribute:: context
|
||||
|
||||
The session context, a ``dict``. Can be reloaded by calling
|
||||
:meth:`openerpweb.openerpweb.OpenERPSession.get_context`
|
||||
|
||||
.. attribute:: domains_store
|
||||
|
||||
A ``dict`` matching domain keys to evaluable (but non-literal) domains.
|
||||
|
||||
Used to store references to non-literal domains which need to be
|
||||
round-tripped to the client browser.
|
||||
"""
|
||||
def __init__(self, server='127.0.0.1', port=8069, model_factory=OpenERPModel):
|
||||
self._server = server
|
||||
self._port = port
|
||||
self._db = False
|
||||
self._uid = False
|
||||
self._login = False
|
||||
self._password = False
|
||||
self.model_factory = model_factory
|
||||
self._locale = 'en_US'
|
||||
self.context = {}
|
||||
self.contexts_store = {}
|
||||
self.domains_store = {}
|
||||
self._lang = {}
|
||||
self.remote_timezone = 'utc'
|
||||
self.client_timezone = False
|
||||
|
||||
def proxy(self, service):
|
||||
s = xmlrpclib.ServerProxy('http://%s:%s/xmlrpc/%s' % (self._server, self._port, service))
|
||||
return s
|
||||
|
||||
def bind(self, db, uid, password):
|
||||
self._db = db
|
||||
self._uid = uid
|
||||
self._password = password
|
||||
|
||||
def login(self, db, login, password):
|
||||
uid = self.proxy('common').login(db, login, password)
|
||||
self.bind(db, uid, password)
|
||||
self._login = login
|
||||
|
||||
if uid: self.get_context()
|
||||
return uid
|
||||
|
||||
def assert_valid(self):
|
||||
"""
|
||||
Ensures this session is valid (logged into the openerp server)
|
||||
"""
|
||||
if not (self._db and self._uid and self._password):
|
||||
raise OpenERPUnboundException()
|
||||
|
||||
def execute(self, model, func, *l, **d):
|
||||
self.assert_valid()
|
||||
r = self.proxy('object').execute(self._db, self._uid, self._password, model, func, *l, **d)
|
||||
return r
|
||||
|
||||
def exec_workflow(self, model, id, signal):
|
||||
self.assert_valid()
|
||||
r = self.proxy('object').exec_workflow(self._db, self._uid, self._password, model, signal, id)
|
||||
return r
|
||||
|
||||
def model(self, model):
|
||||
""" Get an RPC proxy for the object ``model``, bound to this session.
|
||||
|
||||
:param model: an OpenERP model name
|
||||
:type model: str
|
||||
:rtype: :class:`openerpweb.openerpweb.OpenERPModel`
|
||||
"""
|
||||
return self.model_factory(self, model)
|
||||
|
||||
def get_context(self):
|
||||
""" Re-initializes the current user's session context (based on
|
||||
his preferences) by calling res.users.get_context() with the old
|
||||
context
|
||||
|
||||
:returns: the new context
|
||||
"""
|
||||
assert self._uid, "The user needs to be logged-in to initialize his context"
|
||||
self.context = self.model('res.users').context_get(self.context)
|
||||
self.context = self.context or {}
|
||||
|
||||
self.client_timezone = self.context.get("tz", False)
|
||||
# invalid code, anyway we decided the server will be in UTC
|
||||
#if self.client_timezone:
|
||||
# self.remote_timezone = self.execute('common', 'timezone_get')
|
||||
|
||||
self._locale = self.context.get('lang','en_US')
|
||||
lang_ids = self.execute('res.lang','search', [('code', '=', self._locale)])
|
||||
if lang_ids:
|
||||
self._lang = self.execute('res.lang', 'read',lang_ids[0], [])
|
||||
return self.context
|
||||
|
||||
@property
|
||||
def base_eval_context(self):
|
||||
""" Default evaluation context for the session.
|
||||
|
||||
Used to evaluate contexts and domains.
|
||||
"""
|
||||
base = dict(
|
||||
uid=self._uid,
|
||||
current_date=datetime.date.today().strftime('%Y-%m-%d'),
|
||||
time=time,
|
||||
datetime=datetime,
|
||||
relativedelta=dateutil.relativedelta.relativedelta
|
||||
)
|
||||
base.update(self.context)
|
||||
return base
|
||||
|
||||
def evaluation_context(self, context=None):
|
||||
""" Returns the session's evaluation context, augmented with the
|
||||
provided context if any.
|
||||
|
||||
:param dict context: to add merge in the session's base eval context
|
||||
:returns: the augmented context
|
||||
:rtype: dict
|
||||
"""
|
||||
d = dict(self.base_eval_context)
|
||||
if context:
|
||||
d.update(context)
|
||||
d['context'] = d
|
||||
return d
|
||||
|
||||
def eval_context(self, context_to_eval, context=None):
|
||||
""" Evaluates the provided context_to_eval in the context (haha) of
|
||||
the context. Also merges the evaluated context with the session's context.
|
||||
|
||||
:param context_to_eval: a context to evaluate. Must be a dict or a
|
||||
non-literal context. If it's a dict, will be
|
||||
returned as-is
|
||||
:type context_to_eval: openerpweb.nonliterals.Context
|
||||
:returns: the evaluated context
|
||||
:rtype: dict
|
||||
|
||||
:raises: ``TypeError`` if ``context_to_eval`` is neither a dict nor
|
||||
a Context
|
||||
"""
|
||||
ctx = dict(
|
||||
self.base_eval_context,
|
||||
**(context or {}))
|
||||
|
||||
# adding the context of the session to send to the openerp server
|
||||
ccontext = nonliterals.CompoundContext(self.context, context_to_eval or {})
|
||||
ccontext.session = self
|
||||
return ccontext.evaluate(ctx)
|
||||
|
||||
def eval_domain(self, domain, context=None):
|
||||
""" Evaluates the provided domain using the provided context
|
||||
(merged with the session's evaluation context)
|
||||
|
||||
:param domain: an OpenERP domain as a list or as a
|
||||
:class:`openerpweb.nonliterals.Domain` instance
|
||||
|
||||
In the second case, it will be evaluated and returned.
|
||||
:type domain: openerpweb.nonliterals.Domain
|
||||
:param dict context: the context to use in the evaluation, if any.
|
||||
:returns: the evaluated domain
|
||||
:rtype: list
|
||||
|
||||
:raises: ``TypeError`` if ``domain`` is neither a list nor a Domain
|
||||
"""
|
||||
if isinstance(domain, list):
|
||||
return domain
|
||||
|
||||
cdomain = nonliterals.CompoundDomain(domain)
|
||||
cdomain.session = self
|
||||
return cdomain.evaluate(context or {})
|
||||
@@ -0,0 +1,426 @@
|
||||
#!/usr/bin/python
|
||||
from __future__ import with_statement
|
||||
|
||||
import functools
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
import uuid
|
||||
import xmlrpclib
|
||||
|
||||
import simplejson
|
||||
import werkzeug.datastructures
|
||||
import werkzeug.exceptions
|
||||
import werkzeug.urls
|
||||
import werkzeug.utils
|
||||
import werkzeug.wrappers
|
||||
import werkzeug.wsgi
|
||||
|
||||
import ast
|
||||
import nonliterals
|
||||
import http
|
||||
# import backendlocal as backend
|
||||
import backendrpc as backend
|
||||
|
||||
__all__ = ['Root', 'jsonrequest', 'httprequest', 'Controller',
|
||||
'WebRequest', 'JsonRequest', 'HttpRequest']
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# Globals (wont move into a pool)
|
||||
#-----------------------------------------------------------
|
||||
|
||||
applicationsession = {}
|
||||
addons_module = {}
|
||||
addons_manifest = {}
|
||||
controllers_class = {}
|
||||
controllers_object = {}
|
||||
controllers_path = {}
|
||||
|
||||
#----------------------------------------------------------
|
||||
# OpenERP Web RequestHandler
|
||||
#----------------------------------------------------------
|
||||
class WebRequest(object):
|
||||
""" Parent class for all OpenERP Web request types, mostly deals with
|
||||
initialization and setup of the request object (the dispatching itself has
|
||||
to be handled by the subclasses)
|
||||
|
||||
:param request: a wrapped werkzeug Request object
|
||||
:type request: :class:`werkzeug.wrappers.BaseRequest`
|
||||
:param config: configuration object
|
||||
|
||||
.. attribute:: applicationsession
|
||||
|
||||
an application-wide :class:`~collections.Mapping`
|
||||
|
||||
.. attribute:: httprequest
|
||||
|
||||
the original :class:`werkzeug.wrappers.Request` object provided to the
|
||||
request
|
||||
|
||||
.. attribute:: httpsession
|
||||
|
||||
a :class:`~collections.Mapping` holding the HTTP session data for the
|
||||
current http session
|
||||
|
||||
.. attribute:: config
|
||||
|
||||
config parameter provided to the request object
|
||||
|
||||
.. attribute:: params
|
||||
|
||||
:class:`~collections.Mapping` of request parameters, not generally
|
||||
useful as they're provided directly to the handler method as keyword
|
||||
arguments
|
||||
|
||||
.. attribute:: session_id
|
||||
|
||||
opaque identifier for the :class:`backend.OpenERPSession` instance of
|
||||
the current request
|
||||
|
||||
.. attribute:: session
|
||||
|
||||
:class:`~backend.OpenERPSession` instance for the current request
|
||||
|
||||
.. attribute:: context
|
||||
|
||||
:class:`~collections.Mapping` of context values for the current request
|
||||
|
||||
.. attribute:: debug
|
||||
|
||||
``bool``, indicates whether the debug mode is active on the client
|
||||
"""
|
||||
def __init__(self, request, config):
|
||||
self.applicationsession = applicationsession
|
||||
self.httprequest = request
|
||||
self.httpresponse = None
|
||||
self.httpsession = request.session
|
||||
self.config = config
|
||||
def init(self, params):
|
||||
self.params = dict(params)
|
||||
# OpenERP session setup
|
||||
self.session_id = self.params.pop("session_id", None) or uuid.uuid4().hex
|
||||
self.session = self.httpsession.setdefault(
|
||||
self.session_id, backend.OpenERPSession(
|
||||
self.config.server_host, self.config.server_port))
|
||||
self.context = self.params.pop('context', None)
|
||||
self.debug = self.params.pop('debug', False) != False
|
||||
|
||||
class JsonRequest(WebRequest):
|
||||
""" JSON-RPC2 over HTTP.
|
||||
|
||||
Sucessful request::
|
||||
|
||||
--> {"jsonrpc": "2.0",
|
||||
"method": "call",
|
||||
"params": {"session_id": "SID",
|
||||
"context": {},
|
||||
"arg1": "val1" },
|
||||
"id": null}
|
||||
|
||||
<-- {"jsonrpc": "2.0",
|
||||
"result": { "res1": "val1" },
|
||||
"id": null}
|
||||
|
||||
Request producing a error::
|
||||
|
||||
--> {"jsonrpc": "2.0",
|
||||
"method": "call",
|
||||
"params": {"session_id": "SID",
|
||||
"context": {},
|
||||
"arg1": "val1" },
|
||||
"id": null}
|
||||
|
||||
<-- {"jsonrpc": "2.0",
|
||||
"error": {"code": 1,
|
||||
"message": "End user error message.",
|
||||
"data": {"code": "codestring",
|
||||
"debug": "traceback" } },
|
||||
"id": null}
|
||||
|
||||
"""
|
||||
|
||||
def dispatch(self, controller, method, requestf=None, request=None):
|
||||
""" Calls the method asked for by the JSON-RPC2 request
|
||||
|
||||
:param controller: the instance of the controller which received the request
|
||||
:param method: the method which received the request
|
||||
:param requestf: a file-like object containing an encoded JSON-RPC2 request
|
||||
:param request: a JSON-RPC2 request
|
||||
|
||||
:returns: an utf8 encoded JSON-RPC2 reply
|
||||
"""
|
||||
response = {"jsonrpc": "2.0" }
|
||||
error = None
|
||||
try:
|
||||
# Read POST content or POST Form Data named "request"
|
||||
if requestf:
|
||||
self.jsonrequest = simplejson.load(requestf, object_hook=nonliterals.non_literal_decoder)
|
||||
else:
|
||||
self.jsonrequest = simplejson.loads(request, object_hook=nonliterals.non_literal_decoder)
|
||||
self.init(self.jsonrequest.get("params", {}))
|
||||
if self.debug or 1:
|
||||
print "--> %s.%s %s" % (controller.__class__.__name__, method.__name__, self.jsonrequest)
|
||||
response['id'] = self.jsonrequest.get('id')
|
||||
response["result"] = method(controller, self, **self.params)
|
||||
except backend.OpenERPUnboundException:
|
||||
error = {
|
||||
'code': 100,
|
||||
'message': "OpenERP Session Invalid",
|
||||
'data': {
|
||||
'type': 'session_invalid',
|
||||
'debug': traceback.format_exc()
|
||||
}
|
||||
}
|
||||
except xmlrpclib.Fault, e:
|
||||
error = {
|
||||
'code': 200,
|
||||
'message': "OpenERP Server Error",
|
||||
'data': {
|
||||
'type': 'server_exception',
|
||||
'fault_code': e.faultCode,
|
||||
'debug': "Client %s\nServer %s" % (
|
||||
"".join(traceback.format_exception("", None, sys.exc_traceback)), e.faultString)
|
||||
}
|
||||
}
|
||||
except Exception:
|
||||
logging.getLogger('openerp.JSONRequest.dispatch').exception\
|
||||
("An error occured while handling a json request")
|
||||
error = {
|
||||
'code': 300,
|
||||
'message': "OpenERP WebClient Error",
|
||||
'data': {
|
||||
'type': 'client_exception',
|
||||
'debug': "Client %s" % traceback.format_exc()
|
||||
}
|
||||
}
|
||||
if error:
|
||||
response["error"] = error
|
||||
|
||||
if self.debug or 1:
|
||||
print "<--", response
|
||||
print
|
||||
|
||||
content = simplejson.dumps(response, cls=nonliterals.NonLiteralEncoder)
|
||||
return werkzeug.wrappers.Response(
|
||||
content, headers=[('Content-Type', 'application/json'),
|
||||
('Content-Length', len(content))])
|
||||
|
||||
def jsonrequest(f):
|
||||
""" Decorator marking the decorated method as being a handler for a
|
||||
JSON-RPC request (the exact request path is specified via the
|
||||
``$(Controller._cp_path)/$methodname`` combination.
|
||||
|
||||
If the method is called, it will be provided with a :class:`JsonRequest`
|
||||
instance and all ``params`` sent during the JSON-RPC request, apart from
|
||||
the ``session_id``, ``context`` and ``debug`` keys (which are stripped out
|
||||
beforehand)
|
||||
"""
|
||||
@functools.wraps(f)
|
||||
def json_handler(controller, request, config):
|
||||
return JsonRequest(request, config).dispatch(
|
||||
controller, f, requestf=request.stream)
|
||||
json_handler.exposed = True
|
||||
return json_handler
|
||||
|
||||
class HttpRequest(WebRequest):
|
||||
""" Regular GET/POST request
|
||||
"""
|
||||
def dispatch(self, controller, method):
|
||||
self.init(dict(self.httprequest.args, **self.httprequest.form))
|
||||
akw = {}
|
||||
for key, value in self.httprequest.args.iteritems():
|
||||
if isinstance(value, basestring) and len(value) < 1024:
|
||||
akw[key] = value
|
||||
else:
|
||||
akw[key] = type(value)
|
||||
if self.debug or 1:
|
||||
print "%s --> %s.%s %r" % (self.httprequest.method, controller.__class__.__name__, method.__name__, akw)
|
||||
r = method(controller, self, **self.params)
|
||||
if self.debug or 1:
|
||||
if isinstance(r, werkzeug.wrappers.BaseResponse):
|
||||
print '<--', r
|
||||
else:
|
||||
print "<--", 'size:', len(r)
|
||||
print
|
||||
return r
|
||||
|
||||
def make_response(self, data, headers=None, cookies=None):
|
||||
""" Helper for non-HTML responses, or HTML responses with custom
|
||||
response headers or cookies.
|
||||
|
||||
While handlers can just return the HTML markup of a page they want to
|
||||
send as a string if non-HTML data is returned they need to create a
|
||||
complete response object, or the returned data will not be correctly
|
||||
interpreted by the clients.
|
||||
|
||||
:param basestring data: response body
|
||||
:param headers: HTTP headers to set on the response
|
||||
:type headers: ``[(name, value)]``
|
||||
:param collections.Mapping cookies: cookies to set on the client
|
||||
"""
|
||||
response = werkzeug.wrappers.Response(data, headers=headers)
|
||||
if cookies:
|
||||
for k, v in cookies.iteritems():
|
||||
response.set_cookie(k, v)
|
||||
return response
|
||||
|
||||
def not_found(self, description=None):
|
||||
""" Helper for 404 response, return its result from the method
|
||||
"""
|
||||
return werkzeug.exceptions.NotFound(description)
|
||||
|
||||
def httprequest(f):
|
||||
""" Decorator marking the decorated method as being a handler for a
|
||||
normal HTTP request (the exact request path is specified via the
|
||||
``$(Controller._cp_path)/$methodname`` combination.
|
||||
|
||||
If the method is called, it will be provided with a :class:`HttpRequest`
|
||||
instance and all ``params`` sent during the request (``GET`` and ``POST``
|
||||
merged in the same dictionary), apart from the ``session_id``, ``context``
|
||||
and ``debug`` keys (which are stripped out beforehand)
|
||||
"""
|
||||
@functools.wraps(f)
|
||||
def http_handler(controller, request, config):
|
||||
return HttpRequest(request, config).dispatch(controller, f)
|
||||
http_handler.exposed = True
|
||||
return http_handler
|
||||
|
||||
class ControllerType(type):
|
||||
def __init__(cls, name, bases, attrs):
|
||||
super(ControllerType, cls).__init__(name, bases, attrs)
|
||||
controllers_class["%s.%s" % (cls.__module__, cls.__name__)] = cls
|
||||
|
||||
class Controller(object):
|
||||
__metaclass__ = ControllerType
|
||||
|
||||
class Root(object):
|
||||
"""Root WSGI application for the OpenERP Web Client.
|
||||
|
||||
:param options: mandatory initialization options object, must provide
|
||||
the following attributes:
|
||||
|
||||
``server_host`` (``str``)
|
||||
hostname of the OpenERP server to dispatch RPC to
|
||||
``server_port`` (``int``)
|
||||
RPC port of the OpenERP server
|
||||
``serve_static`` (``bool | None``)
|
||||
whether this application should serve the various
|
||||
addons's static files
|
||||
``storage_path`` (``str``)
|
||||
filesystem path where HTTP session data will be stored
|
||||
``dbfilter`` (``str``)
|
||||
only used in case the list of databases is requested
|
||||
by the server, will be filtered by this pattern
|
||||
"""
|
||||
def __init__(self, options):
|
||||
self.root = werkzeug.urls.Href('/base/webclient/home')
|
||||
self.config = options
|
||||
|
||||
self.session_cookie = 'sessionid'
|
||||
self.addons = {}
|
||||
|
||||
static_dirs = self._load_addons()
|
||||
if options.serve_static:
|
||||
self.dispatch = werkzeug.wsgi.SharedDataMiddleware(
|
||||
self.dispatch, static_dirs)
|
||||
|
||||
if options.session_storage:
|
||||
if not os.path.exists(options.session_storage):
|
||||
os.mkdir(options.session_storage, 0700)
|
||||
self.session_storage = options.session_storage
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
""" Handle a WSGI request
|
||||
"""
|
||||
return self.dispatch(environ, start_response)
|
||||
|
||||
def dispatch(self, environ, start_response):
|
||||
"""
|
||||
Performs the actual WSGI dispatching for the application, may be
|
||||
wrapped during the initialization of the object.
|
||||
|
||||
Call the object directly.
|
||||
"""
|
||||
request = werkzeug.wrappers.Request(environ)
|
||||
request.parameter_storage_class = werkzeug.datastructures.ImmutableDict
|
||||
|
||||
if request.path == '/':
|
||||
return werkzeug.utils.redirect(
|
||||
self.root(request.args), 301)(
|
||||
environ, start_response)
|
||||
elif request.path == '/mobile':
|
||||
return werkzeug.utils.redirect(
|
||||
'/web_mobile/static/src/web_mobile.html', 301)(
|
||||
environ, start_response)
|
||||
|
||||
handler = self.find_handler(*(request.path.split('/')[1:]))
|
||||
|
||||
if not handler:
|
||||
response = werkzeug.exceptions.NotFound()
|
||||
else:
|
||||
with http.session(request, self.session_storage, self.session_cookie) as session:
|
||||
result = handler(
|
||||
request, self.config)
|
||||
|
||||
if isinstance(result, basestring):
|
||||
response = werkzeug.wrappers.Response(
|
||||
result, headers=[('Content-Type', 'text/html; charset=utf-8'),
|
||||
('Content-Length', len(result))])
|
||||
else:
|
||||
response = result
|
||||
|
||||
response.set_cookie(self.session_cookie, session.sid)
|
||||
|
||||
return response(environ, start_response)
|
||||
|
||||
def _load_addons(self):
|
||||
"""
|
||||
Loads all addons at the specified addons path, returns a mapping of
|
||||
static URLs to the corresponding directories
|
||||
"""
|
||||
statics = {}
|
||||
addons_path = self.config.addons_path
|
||||
if addons_path not in sys.path:
|
||||
sys.path.insert(0, addons_path)
|
||||
for module in os.listdir(addons_path):
|
||||
if module not in addons_module:
|
||||
manifest_path = os.path.join(addons_path, module, '__openerp__.py')
|
||||
if os.path.isfile(manifest_path):
|
||||
manifest = ast.literal_eval(open(manifest_path).read())
|
||||
print "Loading", module
|
||||
m = __import__(module)
|
||||
addons_module[module] = m
|
||||
addons_manifest[module] = manifest
|
||||
|
||||
statics['/%s/static' % module] = \
|
||||
os.path.join(addons_path, module, 'static')
|
||||
for k, v in controllers_class.items():
|
||||
if k not in controllers_object:
|
||||
o = v()
|
||||
controllers_object[k] = o
|
||||
if hasattr(o, '_cp_path'):
|
||||
controllers_path[o._cp_path] = o
|
||||
return statics
|
||||
|
||||
def find_handler(self, *l):
|
||||
"""
|
||||
Tries to discover the controller handling the request for the path
|
||||
specified by the provided parameters
|
||||
|
||||
:param l: path sections to a controller or controller method
|
||||
:returns: a callable matching the path sections, or ``None``
|
||||
:rtype: ``Controller | None``
|
||||
"""
|
||||
if len(l) > 1:
|
||||
for i in range(len(l), 1, -1):
|
||||
ps = "/" + "/".join(l[0:i])
|
||||
if ps in controllers_path:
|
||||
c = controllers_path[ps]
|
||||
rest = l[i:] or ['index']
|
||||
meth = rest[0]
|
||||
m = getattr(c, meth)
|
||||
if getattr(m, 'exposed', False):
|
||||
print "Dispatching to", ps, c, meth, m
|
||||
return m
|
||||
return None
|
||||
@@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import contextlib
|
||||
|
||||
import werkzeug.contrib.sessions
|
||||
|
||||
STORES = {}
|
||||
|
||||
@contextlib.contextmanager
|
||||
def session(request, storage_path, session_cookie='sessionid'):
|
||||
session_store = STORES.get(storage_path)
|
||||
if not session_store:
|
||||
session_store = werkzeug.contrib.sessions.FilesystemSessionStore(
|
||||
storage_path)
|
||||
STORES[storage_path] = session_store
|
||||
|
||||
sid = request.cookies.get(session_cookie)
|
||||
if sid:
|
||||
request.session = session_store.get(sid)
|
||||
else:
|
||||
request.session = session_store.new()
|
||||
|
||||
yield request.session
|
||||
|
||||
session_store.save(request.session)
|
||||
@@ -7,8 +7,6 @@ can't be sent there themselves).
|
||||
import binascii
|
||||
import hashlib
|
||||
import simplejson.encoder
|
||||
import time
|
||||
import datetime
|
||||
|
||||
__all__ = ['Domain', 'Context', 'NonLiteralEncoder, non_literal_decoder', 'CompoundDomain', 'CompoundContext']
|
||||
|
||||
@@ -9,17 +9,20 @@ import re
|
||||
import simplejson
|
||||
import textwrap
|
||||
import xmlrpclib
|
||||
import time
|
||||
from xml.etree import ElementTree
|
||||
from cStringIO import StringIO
|
||||
|
||||
import cherrypy
|
||||
|
||||
import openerpweb
|
||||
import openerpweb.ast
|
||||
import openerpweb.nonliterals
|
||||
import base.common.dispatch as openerpweb
|
||||
import base.common.ast
|
||||
import base.common.nonliterals
|
||||
openerpweb.ast = base.common.ast
|
||||
openerpweb.nonliterals = base.common.nonliterals
|
||||
|
||||
from babel.messages.pofile import read_po
|
||||
|
||||
_REPORT_POLLER_DELAY = 0.05
|
||||
|
||||
# Should move to openerpweb.Xml2Json
|
||||
class Xml2Json:
|
||||
# xml2json-direct
|
||||
@@ -63,16 +66,16 @@ class Xml2Json:
|
||||
# OpenERP Web base Controllers
|
||||
#----------------------------------------------------------
|
||||
|
||||
def manifest_glob(addons, key):
|
||||
def manifest_glob(addons_path, addons, key):
|
||||
files = []
|
||||
for addon in addons:
|
||||
globlist = openerpweb.addons_manifest.get(addon, {}).get(key, [])
|
||||
for pattern in globlist:
|
||||
for path in glob.glob(os.path.join(openerpweb.path_addons, addon, pattern)):
|
||||
files.append(path[len(openerpweb.path_addons):])
|
||||
for path in glob.glob(os.path.join(addons_path, addon, pattern)):
|
||||
files.append(path[len(addons_path):])
|
||||
return files
|
||||
|
||||
def concat_files(file_list):
|
||||
def concat_files(addons_path, file_list):
|
||||
""" Concatenate file content
|
||||
return (concat,timestamp)
|
||||
concat: concatenation of file content
|
||||
@@ -81,13 +84,13 @@ def concat_files(file_list):
|
||||
files_content = []
|
||||
files_timestamp = 0
|
||||
for i in file_list:
|
||||
fname = os.path.join(openerpweb.path_addons, i[1:])
|
||||
fname = os.path.join(addons_path, i[1:])
|
||||
ftime = os.path.getmtime(fname)
|
||||
if ftime > files_timestamp:
|
||||
files_timestamp = ftime
|
||||
files_content.append(open(fname).read())
|
||||
files_concat = "".join(files_content)
|
||||
return (files_concat,files_timestamp)
|
||||
return files_concat,files_timestamp
|
||||
|
||||
home_template = textwrap.dedent("""<!DOCTYPE html>
|
||||
<html style="height: 100%%">
|
||||
@@ -117,40 +120,38 @@ class WebClient(openerpweb.Controller):
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def csslist(self, req, mods='base'):
|
||||
return manifest_glob(mods.split(','), 'css')
|
||||
return manifest_glob(req.config.addons_path, mods.split(','), 'css')
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def jslist(self, req, mods='base'):
|
||||
return manifest_glob(mods.split(','), 'js')
|
||||
return manifest_glob(req.config.addons_path, mods.split(','), 'js')
|
||||
|
||||
@openerpweb.httprequest
|
||||
def css(self, req, mods='base'):
|
||||
req.httpresponse.headers['Content-Type'] = 'text/css'
|
||||
files = manifest_glob(mods.split(','), 'css')
|
||||
content,timestamp = concat_files(files)
|
||||
files = manifest_glob(req.config.addons_path, mods.split(','), 'css')
|
||||
content,timestamp = concat_files(req.config.addons_path, files)
|
||||
# TODO request set the Date of last modif and Etag
|
||||
return content
|
||||
return req.make_response(content, [('Content-Type', 'text/css')])
|
||||
|
||||
@openerpweb.httprequest
|
||||
def js(self, req, mods='base'):
|
||||
req.httpresponse.headers['Content-Type'] = 'application/javascript'
|
||||
files = manifest_glob(mods.split(','), 'js')
|
||||
content,timestamp = concat_files(files)
|
||||
files = manifest_glob(req.config.addons_path, mods.split(','), 'js')
|
||||
content,timestamp = concat_files(req.config.addons_path, files)
|
||||
# TODO request set the Date of last modif and Etag
|
||||
return content
|
||||
return req.make_response(content, [('Content-Type', 'application/javascript')])
|
||||
|
||||
@openerpweb.httprequest
|
||||
def home(self, req, s_action=None, **kw):
|
||||
# script tags
|
||||
jslist = ['/base/webclient/js']
|
||||
if req.debug:
|
||||
jslist = manifest_glob(['base'], 'js')
|
||||
jslist = manifest_glob(req.config.addons_path, ['base'], 'js')
|
||||
js = "\n ".join(['<script type="text/javascript" src="%s"></script>'%i for i in jslist])
|
||||
|
||||
# css tags
|
||||
csslist = ['/base/webclient/css']
|
||||
if req.debug:
|
||||
csslist = manifest_glob(['base'], 'css')
|
||||
csslist = manifest_glob(req.config.addons_path, ['base'], 'css')
|
||||
css = "\n ".join(['<link rel="stylesheet" href="%s">'%i for i in csslist])
|
||||
r = home_template % {
|
||||
'javascript': js,
|
||||
@@ -180,7 +181,7 @@ class WebClient(openerpweb.Controller):
|
||||
transl = {"messages":[]}
|
||||
transs[addon_name] = transl
|
||||
for l in langs:
|
||||
f_name = os.path.join(openerpweb.path_addons, addon_name, "po", l + ".po")
|
||||
f_name = os.path.join(req.config.addons_path, addon_name, "po", l + ".po")
|
||||
if not os.path.exists(f_name):
|
||||
continue
|
||||
try:
|
||||
@@ -203,7 +204,7 @@ class Database(openerpweb.Controller):
|
||||
dbs = proxy.list()
|
||||
h = req.httprequest.headers['Host'].split(':')[0]
|
||||
d = h.split('.')[0]
|
||||
r = cherrypy.config['openerp.dbfilter'].replace('%h', h).replace('%d', d)
|
||||
r = req.config.dbfilter.replace('%h', h).replace('%d', d)
|
||||
dbs = [i for i in dbs if re.match(r, i)]
|
||||
return {"db_list": dbs}
|
||||
|
||||
@@ -248,11 +249,11 @@ class Database(openerpweb.Controller):
|
||||
try:
|
||||
db_dump = base64.decodestring(
|
||||
req.session.proxy("db").dump(backup_pwd, backup_db))
|
||||
req.httpresponse.headers['Content-Type'] = "application/octet-stream; charset=binary"
|
||||
req.httpresponse.headers['Content-Disposition'] = 'attachment; filename="' + backup_db + '.dump"'
|
||||
req.httpresponse.cookie['fileToken'] = int(token)
|
||||
req.httpresponse.cookie['fileToken']['path'] = '/'
|
||||
return db_dump
|
||||
return req.make_response(db_dump,
|
||||
[('Content-Type', 'application/octet-stream; charset=binary'),
|
||||
('Content-Disposition', 'attachment; filename="' + backup_db + '.dump"')],
|
||||
{'fileToken': int(token)}
|
||||
)
|
||||
except xmlrpclib.Fault, e:
|
||||
if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
|
||||
return 'Backup Database|' + e.faultCode
|
||||
@@ -293,7 +294,21 @@ class Session(openerpweb.Controller):
|
||||
"uid": req.session._uid,
|
||||
"context": ctx
|
||||
}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def change_password (self,req,fields):
|
||||
old_password, new_password,confirm_password = operator.itemgetter('old_pwd', 'new_password','confirm_pwd')(
|
||||
dict(map(operator.itemgetter('name', 'value'), fields)))
|
||||
if not (old_password.strip() and new_password.strip() and confirm_password.strip()):
|
||||
return {'error':'All passwords have to be filled.','title': 'Change Password'}
|
||||
if new_password != confirm_password:
|
||||
return {'error': 'The new password and its confirmation must be identical.','title': 'Change Password'}
|
||||
try:
|
||||
if req.session.model('res.users').change_password(
|
||||
old_password, new_password):
|
||||
return {'new_password':new_password}
|
||||
except:
|
||||
return {'error': 'Original password incorrect, your password was not changed.', 'title': 'Change Password'}
|
||||
return {'error': 'Error, password not changed !', 'title': 'Change Password'}
|
||||
@openerpweb.jsonrequest
|
||||
def sc_list(self, req):
|
||||
return req.session.model('ir.ui.view_sc').get_sc(
|
||||
@@ -955,9 +970,9 @@ class Binary(openerpweb.Controller):
|
||||
res = Model.read([int(id)], [field], context)[0].get(field, '')
|
||||
return base64.decodestring(res)
|
||||
except: # TODO: what's the exception here?
|
||||
return self.placeholder()
|
||||
def placeholder(self):
|
||||
return open(os.path.join(openerpweb.path_addons, 'base', 'static', 'src', 'img', 'placeholder.png'), 'rb').read()
|
||||
return self.placeholder(req)
|
||||
def placeholder(self, req):
|
||||
return open(os.path.join(req.addons_path, 'base', 'static', 'src', 'img', 'placeholder.png'), 'rb').read()
|
||||
|
||||
@openerpweb.httprequest
|
||||
def saveas(self, req, model, id, field, fieldname, **kw):
|
||||
@@ -966,18 +981,17 @@ class Binary(openerpweb.Controller):
|
||||
res = Model.read([int(id)], [field, fieldname], context)[0]
|
||||
filecontent = res.get(field, '')
|
||||
if not filecontent:
|
||||
raise cherrypy.NotFound
|
||||
return req.not_found()
|
||||
else:
|
||||
req.httpresponse.headers['Content-Type'] = 'application/octet-stream'
|
||||
filename = '%s_%s' % (model.replace('.', '_'), id)
|
||||
if fieldname:
|
||||
filename = res.get(fieldname, '') or filename
|
||||
req.httpresponse.headers['Content-Disposition'] = 'attachment; filename=' + filename
|
||||
return base64.decodestring(filecontent)
|
||||
return req.make_response(filecontent,
|
||||
[('Content-Type', 'application/octet-stream'),
|
||||
('Content-Disposition', 'attachment; filename=' + filename)])
|
||||
|
||||
@openerpweb.httprequest
|
||||
def upload(self, req, callback, ufile=None):
|
||||
cherrypy.response.timeout = 500
|
||||
headers = {}
|
||||
for key, val in req.httprequest.headers.iteritems():
|
||||
headers[key.lower()] = val
|
||||
@@ -1004,7 +1018,6 @@ class Binary(openerpweb.Controller):
|
||||
|
||||
@openerpweb.httprequest
|
||||
def upload_attachment(self, req, callback, model, id, ufile=None):
|
||||
cherrypy.response.timeout = 500
|
||||
context = req.session.eval_context(req.context)
|
||||
Model = req.session.model('ir.attachment')
|
||||
try:
|
||||
|
||||
@@ -365,7 +365,7 @@ msgid "(Any existing filter with the same name will be replaced)"
|
||||
msgstr ""
|
||||
|
||||
#: addons/base/static/src/xml/base.xml:0
|
||||
msgid "(?)"
|
||||
msgid "?"
|
||||
msgstr ""
|
||||
|
||||
#: addons/base/static/src/xml/base.xml:0
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
if(!menu) {
|
||||
menu=$('<div id="jqContextMenu"></div>').hide().css({
|
||||
position:'absolute',
|
||||
zIndex:'500'
|
||||
zIndex:'2000'
|
||||
}).appendTo('body').bind('click', function(e) {
|
||||
e.stopPropagation()
|
||||
})
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
// TODO: t-set + t-value + children node == scoped variable ?
|
||||
var QWeb2 = {
|
||||
expressions_cache: {},
|
||||
reserved_words: 'true,false,NaN,null,undefined,debugger,in,instanceof,new,function,return,this,typeof,eval,Math,RegExp,Array,Object,Date'.split(','),
|
||||
actions_precedence: 'foreach,if,call,set,esc,escf,raw,rawf,js,debug,log'.split(','),
|
||||
word_replacement: {
|
||||
RESERVED_WORDS: 'true,false,NaN,null,undefined,debugger,in,instanceof,new,function,return,this,typeof,eval,Math,RegExp,Array,Object,Date'.split(','),
|
||||
ACTIONS_PRECEDENCE: 'foreach,if,call,set,esc,escf,raw,rawf,js,debug,log'.split(','),
|
||||
WORD_REPLACEMENT: {
|
||||
'and': '&&',
|
||||
'or': '||',
|
||||
'gt': '>',
|
||||
@@ -204,6 +204,9 @@ QWeb2.Engine = (function() {
|
||||
this.dict = {};
|
||||
this.tools = QWeb2.tools;
|
||||
this.jQuery = window.jQuery;
|
||||
this.reserved_words = QWeb2.RESERVED_WORDS.slice(0);
|
||||
this.actions_precedence = QWeb2.ACTIONS_PRECEDENCE.slice(0);
|
||||
this.word_replacement = QWeb2.tools.extend({}, QWeb2.WORD_REPLACEMENT);
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
this.add_template(arguments[i]);
|
||||
}
|
||||
@@ -290,6 +293,9 @@ QWeb2.Engine = (function() {
|
||||
xDoc.loadXML(s);
|
||||
return xDoc;
|
||||
},
|
||||
has_template : function(template) {
|
||||
return !!this.templates[template];
|
||||
},
|
||||
get_xhr : function() {
|
||||
if (window.XMLHttpRequest) {
|
||||
return new window.XMLHttpRequest();
|
||||
@@ -519,8 +525,8 @@ QWeb2.Element = (function() {
|
||||
continue;
|
||||
} else if (c.match(/\W/) && invar.length) {
|
||||
// TODO: Should check for possible spaces before dot
|
||||
if (chars[invar_pos - 1] !== '.' && QWeb2.tools.arrayIndexOf(QWeb2.reserved_words, invar) < 0) {
|
||||
invar = QWeb2.word_replacement[invar] || ("dict['" + invar + "']");
|
||||
if (chars[invar_pos - 1] !== '.' && QWeb2.tools.arrayIndexOf(this.engine.reserved_words, invar) < 0) {
|
||||
invar = this.engine.word_replacement[invar] || ("dict['" + invar + "']");
|
||||
}
|
||||
r += invar;
|
||||
invar = '';
|
||||
@@ -579,15 +585,18 @@ QWeb2.Element = (function() {
|
||||
return this._bottom.unshift(this.get_indent() + "//@string=" + this.engine.tools.js_escape(s, true) + '\n');
|
||||
},
|
||||
compile_element : function() {
|
||||
for (var i = 0, ilen = QWeb2.actions_precedence.length; i < ilen; i++) {
|
||||
var a = QWeb2.actions_precedence[i];
|
||||
for (var i = 0, ilen = this.engine.actions_precedence.length; i < ilen; i++) {
|
||||
var a = this.engine.actions_precedence[i];
|
||||
if (a in this.actions) {
|
||||
var value = this.actions[a];
|
||||
var key = 'compile_action_' + a;
|
||||
if (!this[key]) {
|
||||
if (this[key]) {
|
||||
this[key](value);
|
||||
} else if (this.engine[key]) {
|
||||
this.engine[key].call(this, value);
|
||||
} else {
|
||||
this.engine.tools.exception("No handler method for action '" + a + "'");
|
||||
}
|
||||
this[key](value);
|
||||
}
|
||||
}
|
||||
if (this.tag !== this.engine.prefix) {
|
||||
|
||||
@@ -597,13 +597,13 @@ label.error {
|
||||
background-color: #ccc;
|
||||
}
|
||||
.openerp .searchview_group.folded .searchview_group_string {
|
||||
background: url("../img/ui/group-folded.png") no-repeat scroll 0 50%;
|
||||
background: url("/base/static/src/img/ui/group-folded.png") no-repeat scroll 0 50%;
|
||||
}
|
||||
.openerp .searchview_group.folded .searchview_group_content {
|
||||
display: none;
|
||||
}
|
||||
.openerp .searchview_group.expanded .searchview_group_string {
|
||||
background: url("../img/ui/group-expanded.png") no-repeat scroll 0 50%;
|
||||
background: url("/base/static/src/img/ui/group-expanded.png") no-repeat scroll 0 50%;
|
||||
}
|
||||
.openerp .searchview_group.expanded .searchview_group_content {
|
||||
display: block;
|
||||
@@ -635,13 +635,13 @@ label.error {
|
||||
}
|
||||
|
||||
.openerp .oe_search-view-custom-filter-btn span {
|
||||
background: url(../img/icons/gtk-add.png) repeat-y;
|
||||
background: url(/base/static/src/img/icons/gtk-add.png) repeat-y;
|
||||
padding-left: 18px;
|
||||
}
|
||||
|
||||
.openerp .searchview_extended_add_proposition span {
|
||||
font-size: 0.9em;
|
||||
background: url(../img/icons/gtk-add.png) repeat-y;
|
||||
background: url(/base/static/src/img/icons/gtk-add.png) repeat-y;
|
||||
padding-left: 18px;
|
||||
}
|
||||
|
||||
@@ -657,7 +657,7 @@ label.error {
|
||||
.openerp .searchview_extended_delete_group span,
|
||||
.openerp .searchview_extended_delete_prop span {
|
||||
font-size: 0.9em;
|
||||
background: url(../img/icons/gtk-close.png) repeat-y;
|
||||
background: url(/base/static/src/img/icons/gtk-close.png) repeat-y;
|
||||
padding-left: 18px;
|
||||
}
|
||||
/* List */
|
||||
@@ -832,15 +832,17 @@ label.error {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.openerp label.oe_form_label_help {
|
||||
.openerp label.oe_label_help, .openerp label.oe_label {
|
||||
display: block;
|
||||
}
|
||||
.openerp label.oe_label_help {
|
||||
cursor: help;
|
||||
}
|
||||
.openerp label.oe_form_label, .openerp label.oe_form_label_help {
|
||||
display: block;
|
||||
.openerp .oe_form_field label.oe_label, .openerp .oe_form_field label.oe_label_help {
|
||||
text-align: right;
|
||||
margin: 3px 0 0 10px;
|
||||
}
|
||||
.openerp label.oe_form_label_help span {
|
||||
.openerp label.oe_label_help span {
|
||||
font-size: 80%;
|
||||
color: darkgreen;
|
||||
vertical-align:top;
|
||||
@@ -895,6 +897,9 @@ label.error {
|
||||
position: relative;
|
||||
top: 4px;
|
||||
}
|
||||
.openerp .oe_trad_field.touched {
|
||||
border: 1px solid green !important;
|
||||
}
|
||||
|
||||
/* http://www.quirksmode.org/dom/inputfile.html
|
||||
* http://stackoverflow.com/questions/2855589/replace-input-type-file-by-an-image
|
||||
@@ -928,6 +933,9 @@ label.error {
|
||||
margin: 3px 4px 3px 1px;
|
||||
height: 15px;
|
||||
}
|
||||
.openerp .oe_form_frame_cell.oe_form_separator_vertical {
|
||||
border-left: 1px solid #666;
|
||||
}
|
||||
.openerp td.required input, .openerp td.required select {
|
||||
background-color: #D2D2FF !important;
|
||||
}
|
||||
@@ -1088,7 +1096,7 @@ label.error {
|
||||
cursor: pointer;
|
||||
border: 1px solid #D2CFCF;
|
||||
display: block;
|
||||
background: url(../img/toggle-a-bg.png);
|
||||
background: url(/base/static/src/img/toggle-a-bg.png);
|
||||
width: 21px;
|
||||
height: 21px;
|
||||
z-index: 10;
|
||||
@@ -1103,7 +1111,7 @@ label.error {
|
||||
}
|
||||
.openerp li.oe_sidebar_print {
|
||||
padding-left: 20px;
|
||||
background: 1px 3px url(../img/icons/gtk-print.png) no-repeat;
|
||||
background: 1px 3px url(/base/static/src/img/icons/gtk-print.png) no-repeat;
|
||||
}
|
||||
|
||||
.openerp.kitten-mode-activated .main_table {
|
||||
|
||||
@@ -50,7 +50,9 @@
|
||||
|
||||
openerp.base = function(instance) {
|
||||
openerp.base.core(instance);
|
||||
openerp.base.dates(instance);
|
||||
if (openerp.base.dates) {
|
||||
openerp.base.dates(instance);
|
||||
}
|
||||
openerp.base.formats(instance);
|
||||
openerp.base.chrome(instance);
|
||||
openerp.base.data(instance);
|
||||
|
||||
@@ -440,8 +440,6 @@ openerp.base.Login = openerp.base.Widget.extend({
|
||||
this.selected_login = localStorage.getItem('last_login_login_success');
|
||||
}
|
||||
if (jQuery.deparam(jQuery.param.querystring()).debug != undefined) {
|
||||
this.selected_db = this.selected_db || "trunk";
|
||||
this.selected_login = this.selected_login || "admin";
|
||||
this.selected_password = this.selected_password || "a";
|
||||
}
|
||||
},
|
||||
@@ -525,22 +523,26 @@ openerp.base.Login = openerp.base.Widget.extend({
|
||||
});
|
||||
|
||||
openerp.base.Header = openerp.base.Widget.extend({
|
||||
init: function(parent, element_id) {
|
||||
this._super(parent, element_id);
|
||||
if (jQuery.deparam(jQuery.param.querystring()).debug !== undefined) {
|
||||
this.qs = '?debug'
|
||||
} else {
|
||||
this.qs = ''
|
||||
}
|
||||
template: "Header",
|
||||
identifier_prefix: 'oe-app-header-',
|
||||
init: function(parent) {
|
||||
this._super(parent);
|
||||
this.qs = "?" + jQuery.param.querystring();
|
||||
this.$content = $();
|
||||
},
|
||||
start: function() {
|
||||
return this.do_update();
|
||||
this._super();
|
||||
},
|
||||
do_update: function () {
|
||||
this.$element.html(QWeb.render("Header", this));
|
||||
this.$content = $(QWeb.render("Header-content", {widget: this}));
|
||||
this.$content.appendTo(this.$element);
|
||||
this.$element.find(".logout").click(this.on_logout);
|
||||
this.$element.find("a.preferences").click(this.on_preferences);
|
||||
return this.shortcut_load();
|
||||
},
|
||||
do_reset: function() {
|
||||
this.$content.remove();
|
||||
},
|
||||
shortcut_load :function(){
|
||||
var self = this,
|
||||
sc = self.session.shortcuts,
|
||||
@@ -594,9 +596,98 @@ openerp.base.Header = openerp.base.Widget.extend({
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
on_action: function(action) {
|
||||
},
|
||||
|
||||
on_preferences: function(){
|
||||
var self = this;
|
||||
var action_manager = new openerp.base.ActionManager(this);
|
||||
var dataset = new openerp.base.DataSet (this,'res.users',this.context);
|
||||
dataset.call ('action_get','',function (result){
|
||||
self.rpc('/base/action/load', {action_id:result}, function(result){
|
||||
action_manager.do_action(_.extend(result['result'], {
|
||||
res_id: self.session.uid,
|
||||
res_model: 'res.users',
|
||||
flags: {
|
||||
action_buttons: false,
|
||||
search_view: false,
|
||||
sidebar: false,
|
||||
views_switcher: false,
|
||||
pager: false
|
||||
}
|
||||
}));
|
||||
});
|
||||
});
|
||||
this.dialog = new openerp.base.Dialog(this,{
|
||||
modal: true,
|
||||
title: 'Preferences',
|
||||
width: 600,
|
||||
height: 500,
|
||||
buttons: {
|
||||
"Change password": function(){
|
||||
self.change_password();
|
||||
},
|
||||
Cancel: function(){
|
||||
$(this).dialog('destroy');
|
||||
},
|
||||
Save: function(){
|
||||
var inner_viewmanager = action_manager.inner_viewmanager;
|
||||
inner_viewmanager.views[inner_viewmanager.active_view].controller.do_save(function(){
|
||||
inner_viewmanager.start();
|
||||
});
|
||||
$(this).dialog('destroy')
|
||||
}
|
||||
}
|
||||
});
|
||||
this.dialog.start().open();
|
||||
action_manager.appendTo(this.dialog);
|
||||
action_manager.render(this.dialog);
|
||||
},
|
||||
|
||||
change_password :function() {
|
||||
var self = this;
|
||||
this.dialog = new openerp.base.Dialog(this,{
|
||||
modal : true,
|
||||
title : 'Change Password',
|
||||
width : 'auto',
|
||||
height : 'auto'
|
||||
});
|
||||
this.dialog.start().open();
|
||||
this.dialog.$element.html(QWeb.render("Change_Pwd", self));
|
||||
this.dialog.$element.find("form[name=change_password_form]").validate({
|
||||
submitHandler: function (form) {
|
||||
self.rpc("/base/session/change_password",{
|
||||
'fields': $(form).serializeArray()
|
||||
}, function(result) {
|
||||
if (result.error) {
|
||||
self.display_error(result);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (result.new_password) {
|
||||
self.session.password = result.new_password;
|
||||
var session = new openerp.base.Session(self.session.server, self.session.port);
|
||||
session.start();
|
||||
session.session_login(self.session.db, self.session.login, self.session.password)
|
||||
}
|
||||
}
|
||||
self.notification.notify("Changed Password", "Password has been changed successfully");
|
||||
self.dialog.close();
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
display_error: function (error) {
|
||||
return $('<div>').dialog({
|
||||
modal: true,
|
||||
title: error.title,
|
||||
buttons: {
|
||||
Ok: function() {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}
|
||||
}).html(error.error);
|
||||
},
|
||||
on_logout: function() {
|
||||
this.$element.find('.oe-shortcuts ul').empty();
|
||||
}
|
||||
@@ -710,21 +801,23 @@ openerp.base.WebClient = openerp.base.Widget.extend({
|
||||
// Do you autorize this ? will be replaced by notify() in controller
|
||||
openerp.base.Widget.prototype.notification = new openerp.base.Notification(this, "oe_notification");
|
||||
|
||||
this.header = new openerp.base.Header(this, "oe_header");
|
||||
|
||||
this.header = new openerp.base.Header(this);
|
||||
this.login = new openerp.base.Login(this, "oe_login");
|
||||
this.header.on_logout.add(this.login.on_logout);
|
||||
this.header.on_action.add(this.on_menu_action);
|
||||
|
||||
this.session.on_session_invalid.add(this.login.do_ask_login);
|
||||
this.session.on_session_valid.add_last(this.header.do_update);
|
||||
this.session.on_session_invalid.add_last(this.header.do_reset);
|
||||
this.session.on_session_valid.add_last(this.on_logged);
|
||||
|
||||
this.menu = new openerp.base.Menu(this, "oe_menu", "oe_secondary_menu");
|
||||
this.menu.on_action.add(this.on_menu_action);
|
||||
this.header.on_action.add(this.on_menu_action);
|
||||
},
|
||||
start: function() {
|
||||
this.header.appendTo($("#oe_header"));
|
||||
this.session.start();
|
||||
this.header.start();
|
||||
this.login.start();
|
||||
this.menu.start();
|
||||
this.notification.notify("OpenERP Client", "The openerp client has been initialized.");
|
||||
|
||||
@@ -355,12 +355,13 @@ openerp.base.DataSet = openerp.base.Widget.extend( /** @lends openerp.base.Data
|
||||
* @param {Function} error_callback function called in case of write error
|
||||
* @returns {$.Deferred}
|
||||
*/
|
||||
write: function (id, data, callback, error_callback) {
|
||||
write: function (id, data, options, callback, error_callback) {
|
||||
var options = options || {};
|
||||
return this.rpc('/base/dataset/save', {
|
||||
model: this.model,
|
||||
id: id,
|
||||
data: data,
|
||||
context: this.get_context()
|
||||
context: this.get_context(options.context)
|
||||
}, callback, error_callback);
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -83,9 +83,11 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
|
||||
this.$form_header.find('button.oe_form_button_cancel').click(this.do_cancel);
|
||||
this.$form_header.find('button.oe_form_button_new').click(this.on_button_new);
|
||||
|
||||
this.$form_header.find('button.oe_get_xml_view').click(function() {
|
||||
$('<xmp>' + openerp.base.json_node_to_xml(self.fields_view.arch, true) + '</xmp>').dialog({ width: '95%', height: 600});
|
||||
});
|
||||
if (this.session.debug) {
|
||||
this.$form_header.find('button.oe_get_xml_view').click(function() {
|
||||
$('<xmp>' + openerp.base.json_node_to_xml(self.fields_view.arch, true) + '</xmp>').dialog({ width: '95%', height: 600});
|
||||
});
|
||||
}
|
||||
|
||||
if (this.options.sidebar && this.options.sidebar_id) {
|
||||
this.sidebar = new openerp.base.Sidebar(this, this.options.sidebar_id);
|
||||
@@ -157,6 +159,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
|
||||
this.do_update_pager(record.id == null);
|
||||
if (this.sidebar) {
|
||||
this.sidebar.attachments.do_update();
|
||||
this.sidebar.$element.find('.oe_sidebar_translate').toggleClass('oe_hide', !record.id);
|
||||
}
|
||||
if (this.default_focus_field && !this.embedded_view) {
|
||||
this.default_focus_field.focus();
|
||||
@@ -342,7 +345,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
|
||||
self.on_created(r, success, prepend_on_create);
|
||||
});
|
||||
} else {
|
||||
return this.dataset.write(this.datarecord.id, values, function(r) {
|
||||
return this.dataset.write(this.datarecord.id, values, {}, function(r) {
|
||||
self.on_saved(r, success);
|
||||
});
|
||||
}
|
||||
@@ -576,17 +579,23 @@ openerp.base.form.Widget = openerp.base.Widget.extend({
|
||||
|
||||
this.view.widgets[this.element_id] = this;
|
||||
this.children = node.children;
|
||||
this.colspan = parseInt(node.attrs.colspan || 1);
|
||||
this.colspan = parseInt(node.attrs.colspan || 1, 10);
|
||||
this.decrease_max_width = 0;
|
||||
|
||||
this.string = this.string || node.attrs.string;
|
||||
this.help = this.help || node.attrs.help;
|
||||
this.invisible = this.modifiers['invisible'] === true;
|
||||
this.classname = 'oe_form_' + this.type;
|
||||
|
||||
this.width = this.node.attrs.width;
|
||||
},
|
||||
start: function() {
|
||||
this.$element = $('#' + this.element_id);
|
||||
},
|
||||
stop: function() {
|
||||
this.$element.remove();
|
||||
if (this.$element) {
|
||||
this.$element.remove();
|
||||
}
|
||||
},
|
||||
process_modifiers: function() {
|
||||
var compute_domain = openerp.base.form.compute_domain;
|
||||
@@ -607,7 +616,7 @@ openerp.base.form.WidgetFrame = openerp.base.form.Widget.extend({
|
||||
template: 'WidgetFrame',
|
||||
init: function(view, node) {
|
||||
this._super(view, node);
|
||||
this.columns = node.attrs.col || 4;
|
||||
this.columns = parseInt(node.attrs.col || 4, 10);
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.table = [];
|
||||
@@ -633,15 +642,21 @@ openerp.base.form.WidgetFrame = openerp.base.form.Widget.extend({
|
||||
return row;
|
||||
},
|
||||
set_row_cells_with: function(row) {
|
||||
var bypass = 0,
|
||||
max_width = 100;
|
||||
for (var i = 0; i < row.length; i++) {
|
||||
bypass += row[i].width === undefined ? 0 : 1;
|
||||
max_width -= row[i].decrease_max_width;
|
||||
}
|
||||
var size_unit = Math.round(max_width / (this.columns - bypass)),
|
||||
colspan_sum = 0;
|
||||
for (var i = 0; i < row.length; i++) {
|
||||
var w = row[i];
|
||||
if (w.is_field_label) {
|
||||
w.width = "1%";
|
||||
if (row[i + 1]) {
|
||||
row[i + 1].width = Math.round((100 / this.columns) * (w.colspan + 1) - 1) + '%';
|
||||
}
|
||||
} else if (w.width === undefined) {
|
||||
w.width = Math.round((100 / this.columns) * w.colspan) + '%';
|
||||
colspan_sum += w.colspan;
|
||||
if (w.width === undefined) {
|
||||
var width = (i === row.length - 1 && colspan_sum === this.columns) ? max_width : Math.round(size_unit * w.colspan);
|
||||
max_width -= width;
|
||||
w.width = width + '%';
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -731,6 +746,11 @@ openerp.base.form.WidgetSeparator = openerp.base.form.Widget.extend({
|
||||
init: function(view, node) {
|
||||
this._super(view, node);
|
||||
this.template = "WidgetSeparator";
|
||||
this.orientation = node.attrs.orientation || 'horizontal';
|
||||
if (this.orientation === 'vertical') {
|
||||
this.width = '1';
|
||||
}
|
||||
this.classname += '_' + this.orientation;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -794,14 +814,15 @@ openerp.base.form.WidgetLabel = openerp.base.form.Widget.extend({
|
||||
this._super(view, node);
|
||||
|
||||
// TODO fme: support for attrs.align
|
||||
if (this.node.tag == 'label' && this.node.attrs.colspan) {
|
||||
this.is_field_label = false;
|
||||
if (this.node.tag == 'label' && (this.node.attrs.colspan || (this.string && this.string.length > 32))) {
|
||||
this.template = "WidgetParagraph";
|
||||
this.colspan = this.node.attrs.colspan;
|
||||
this.colspan = parseInt(this.node.attrs.colspan || 1, 10);
|
||||
} else {
|
||||
this.is_field_label = true;
|
||||
this.template = "WidgetLabel";
|
||||
this.colspan = 1;
|
||||
this.width = '1%';
|
||||
this.decrease_max_width = 1;
|
||||
this.nowrap = true;
|
||||
}
|
||||
},
|
||||
render: function () {
|
||||
@@ -843,6 +864,8 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({
|
||||
this.required = this.modifiers['required'] === true;
|
||||
this.invalid = false;
|
||||
this.dirty = false;
|
||||
|
||||
this.classname = 'oe_form_field_' + this.type;
|
||||
},
|
||||
start: function() {
|
||||
this._super.apply(this, arguments);
|
||||
@@ -879,6 +902,9 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({
|
||||
},
|
||||
update_dom: function() {
|
||||
this._super.apply(this, arguments);
|
||||
if (this.field.translate) {
|
||||
this.$element.find('.oe_field_translate').toggle(!!this.view.datarecord.id);
|
||||
}
|
||||
if (!this.disable_utility_classes) {
|
||||
this.$element.toggleClass('disabled', this.readonly);
|
||||
this.$element.toggleClass('required', this.required);
|
||||
@@ -1080,17 +1106,17 @@ openerp.base.form.FieldDatetime = openerp.base.form.Field.extend({
|
||||
focus: function() {
|
||||
this.$element.find('input').focus();
|
||||
},
|
||||
parse: openerp.base.str_to_datetime,
|
||||
format: openerp.base.datetime_to_str
|
||||
parse: openerp.base.auto_str_to_date,
|
||||
format: function(val) {
|
||||
return openerp.base.auto_date_to_str(val, this.field.type);
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.form.FieldDate = openerp.base.form.FieldDatetime.extend({
|
||||
init: function(view, node) {
|
||||
this._super(view, node);
|
||||
this.jqueryui_object = 'datepicker';
|
||||
},
|
||||
parse: openerp.base.str_to_date,
|
||||
format: openerp.base.date_to_str
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.form.FieldText = openerp.base.form.Field.extend({
|
||||
@@ -1519,12 +1545,14 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
|
||||
},
|
||||
set_value: function(value) {
|
||||
value = value || null;
|
||||
this.invalid = false;
|
||||
var self = this;
|
||||
var _super = this._super;
|
||||
this.tmp_value = value;
|
||||
self.update_dom();
|
||||
self.on_value_changed();
|
||||
var real_set_value = function(rval) {
|
||||
self.tmp_value = undefined;
|
||||
_super.apply(self, rval);
|
||||
self.value = rval;
|
||||
self.original_value = undefined;
|
||||
self._change_int_ext_value(rval);
|
||||
};
|
||||
@@ -1550,7 +1578,8 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
|
||||
},
|
||||
validate: function() {
|
||||
this.invalid = false;
|
||||
if (this.value === null) {
|
||||
var val = this.tmp_value !== undefined ? this.tmp_value : this.value;
|
||||
if (val === null) {
|
||||
this.invalid = this.required;
|
||||
}
|
||||
},
|
||||
@@ -1558,14 +1587,16 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
|
||||
var self = this;
|
||||
if (!self.value)
|
||||
return;
|
||||
self.rpc("/base/action/load", {
|
||||
action_id: related[2].id,
|
||||
context: {
|
||||
var additional_context = {
|
||||
active_id: self.value[0],
|
||||
active_ids: [self.value[0]],
|
||||
active_model: self.field.relation
|
||||
}
|
||||
};
|
||||
self.rpc("/base/action/load", {
|
||||
action_id: related[2].id,
|
||||
context: additional_context
|
||||
}, function(result) {
|
||||
result.result.context = _.extend(result.result.context || {}, additional_context);
|
||||
self.do_action(result.result);
|
||||
});
|
||||
}
|
||||
@@ -1863,10 +1894,13 @@ openerp.base.form.One2ManyListView = openerp.base.ListView.extend({
|
||||
pop.show_element(self.o2m.field.relation, id, self.o2m.build_context(),{
|
||||
auto_write: false,
|
||||
alternative_form_view: self.o2m.field.views ? self.o2m.field.views["form"] : undefined,
|
||||
parent_view: self.o2m.view
|
||||
parent_view: self.o2m.view,
|
||||
read_function: function() {
|
||||
return self.o2m.dataset.read_ids.apply(self.o2m.dataset, arguments);
|
||||
}
|
||||
});
|
||||
pop.on_write.add(function(id, data) {
|
||||
self.o2m.dataset.write(id, data, function(r) {
|
||||
self.o2m.dataset.write(id, data, {}, function(r) {
|
||||
self.o2m.reload_current_view();
|
||||
});
|
||||
});
|
||||
@@ -2135,6 +2169,7 @@ openerp.base.form.FormOpenPopup = openerp.base.OldWidget.extend({
|
||||
* options:
|
||||
* - alternative_form_view
|
||||
* - auto_write (default true)
|
||||
* - read_function
|
||||
* - parent_view
|
||||
*/
|
||||
show_element: function(model, row_id, context, options) {
|
||||
@@ -2150,7 +2185,8 @@ openerp.base.form.FormOpenPopup = openerp.base.OldWidget.extend({
|
||||
},
|
||||
start: function() {
|
||||
this._super();
|
||||
this.dataset = new openerp.base.ReadOnlyDataSetSearch(this, this.model, this.context);
|
||||
this.dataset = new openerp.base.form.FormOpenDataset(this, this.model, this.context);
|
||||
this.dataset.fop = this;
|
||||
this.dataset.ids = [this.row_id];
|
||||
this.dataset.index = 0;
|
||||
this.dataset.parent_view = this.options.parent_view;
|
||||
@@ -2163,7 +2199,7 @@ openerp.base.form.FormOpenPopup = openerp.base.OldWidget.extend({
|
||||
var self = this;
|
||||
var wdataset = new openerp.base.DataSetSearch(this, this.model, this.context, this.domain);
|
||||
wdataset.parent_view = this.options.parent_view;
|
||||
wdataset.write(id, data, function(r) {
|
||||
wdataset.write(id, data, {}, function(r) {
|
||||
self.on_write_completed();
|
||||
});
|
||||
},
|
||||
@@ -2192,6 +2228,16 @@ openerp.base.form.FormOpenPopup = openerp.base.OldWidget.extend({
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.form.FormOpenDataset = openerp.base.ReadOnlyDataSetSearch.extend({
|
||||
read_ids: function() {
|
||||
if (this.fop.options.read_function) {
|
||||
return this.fop.options.read_function.apply(null, arguments);
|
||||
} else {
|
||||
return this._super.apply(this, arguments);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
openerp.base.form.FieldReference = openerp.base.form.Field.extend({
|
||||
init: function(view, node) {
|
||||
this._super(view, node);
|
||||
|
||||
@@ -28,8 +28,10 @@ openerp.base.format_value = function (value, descriptor, value_if_empty) {
|
||||
case 'float':
|
||||
var precision = descriptor.digits ? descriptor.digits[1] : 2;
|
||||
var int_part = Math.floor(value);
|
||||
var dec_part = Math.floor((value % 1) * Math.pow(10, precision));
|
||||
return _.sprintf('%d' + openerp.base._t.database.parameters.decimal_point + '%d', int_part, dec_part);
|
||||
var dec_part = Math.abs(Math.floor((value % 1) * Math.pow(10, precision)));
|
||||
return _.sprintf('%d%s%d',
|
||||
int_part,
|
||||
openerp.base._t.database.parameters.decimal_point, dec_part);
|
||||
case 'float_time':
|
||||
return _.sprintf("%02d:%02d",
|
||||
Math.floor(value),
|
||||
@@ -43,9 +45,9 @@ openerp.base.format_value = function (value, descriptor, value_if_empty) {
|
||||
return value[1];
|
||||
case 'datetime':
|
||||
if (typeof(value) == "string")
|
||||
value = openerp.base.str_to_datetime(value);
|
||||
value = openerp.base.auto_str_to_date(value);
|
||||
try {
|
||||
return value.toString(_.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate,
|
||||
return value.toString(_.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate,
|
||||
Date.CultureInfo.formatPatterns.longTime));
|
||||
} catch (e) {
|
||||
return value.format("%m/%d/%Y %H:%M:%S");
|
||||
@@ -53,7 +55,7 @@ openerp.base.format_value = function (value, descriptor, value_if_empty) {
|
||||
return value;
|
||||
case 'date':
|
||||
if (typeof(value) == "string")
|
||||
value = openerp.base.str_to_date(value);
|
||||
value = openerp.base.auto_str_to_date(value);
|
||||
try {
|
||||
return value.toString(Date.CultureInfo.formatPatterns.shortDate);
|
||||
} catch (e) {
|
||||
@@ -61,7 +63,7 @@ openerp.base.format_value = function (value, descriptor, value_if_empty) {
|
||||
}
|
||||
case 'time':
|
||||
if (typeof(value) == "string")
|
||||
value = openerp.base.str_to_time(value);
|
||||
value = openerp.base.auto_str_to_date(value);
|
||||
try {
|
||||
return value.toString(Date.CultureInfo.formatPatterns.longTime);
|
||||
} catch (e) {
|
||||
@@ -108,7 +110,7 @@ openerp.base.parse_value = function (value, descriptor, value_if_empty) {
|
||||
case 'progressbar':
|
||||
return openerp.base.parse_value(value, {type: "float"});
|
||||
case 'datetime':
|
||||
var tmp = Date.parseExact(value, _.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate,
|
||||
var tmp = Date.parseExact(value, _.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate,
|
||||
Date.CultureInfo.formatPatterns.longTime));
|
||||
if (tmp !== null)
|
||||
return tmp;
|
||||
@@ -117,7 +119,7 @@ openerp.base.parse_value = function (value, descriptor, value_if_empty) {
|
||||
return tmp;
|
||||
throw value + " is not a valid datetime";
|
||||
case 'date':
|
||||
var tmp = Date.parseExact(Date.CultureInfo.formatPatterns.shortDate);
|
||||
var tmp = Date.parseExact(value, Date.CultureInfo.formatPatterns.shortDate);
|
||||
if (tmp !== null)
|
||||
return tmp;
|
||||
tmp = Date.parse(value);
|
||||
@@ -125,7 +127,7 @@ openerp.base.parse_value = function (value, descriptor, value_if_empty) {
|
||||
return tmp;
|
||||
throw value + " is not a valid date";
|
||||
case 'time':
|
||||
var tmp = Date.parseExact(Date.CultureInfo.formatPatterns.longTime);
|
||||
var tmp = Date.parseExact(value, Date.CultureInfo.formatPatterns.longTime);
|
||||
if (tmp !== null)
|
||||
return tmp;
|
||||
tmp = Date.parse(value);
|
||||
@@ -136,6 +138,32 @@ openerp.base.parse_value = function (value, descriptor, value_if_empty) {
|
||||
return value;
|
||||
};
|
||||
|
||||
openerp.base.auto_str_to_date = function(value, type) {
|
||||
try {
|
||||
return openerp.base.str_to_datetime(value);
|
||||
} catch(e) {}
|
||||
try {
|
||||
return openerp.base.str_to_date(value);
|
||||
} catch(e) {}
|
||||
try {
|
||||
return openerp.base.str_to_time(value);
|
||||
} catch(e) {}
|
||||
throw "'" + value + "' is not a valid date, datetime nor time"
|
||||
};
|
||||
|
||||
openerp.base.auto_date_to_str = function(value, type) {
|
||||
switch(type) {
|
||||
case 'datetime':
|
||||
return openerp.base.datetime_to_str(value);
|
||||
case 'date':
|
||||
return openerp.base.date_to_str(value);
|
||||
case 'time':
|
||||
return openerp.base.time_to_str(value);
|
||||
default:
|
||||
throw type + " is not convertible to date, datetime nor time"
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats a provided cell based on its field type
|
||||
*
|
||||
|
||||
@@ -314,16 +314,25 @@ openerp.base.SearchView = openerp.base.Widget.extend({
|
||||
on_invalid: function (errors) {
|
||||
this.notification.notify("Invalid Search", "triggered from search view");
|
||||
},
|
||||
do_clear: function (e) {
|
||||
if (e && e.preventDefault) { e.preventDefault(); }
|
||||
this.on_clear();
|
||||
do_clear: function () {
|
||||
$('.filter_label').removeClass('enabled');
|
||||
var string = $('a.searchview_group_string');
|
||||
_.each(string, function(str){
|
||||
$(str).closest('div.searchview_group').removeClass("expanded").addClass('folded');
|
||||
});
|
||||
this.$element.find('table:last').hide();
|
||||
|
||||
$('.searchview_extended_groups_list').empty();
|
||||
setTimeout(this.on_clear);
|
||||
},
|
||||
/**
|
||||
* Triggered when the search view gets cleared
|
||||
*
|
||||
* @event
|
||||
*/
|
||||
on_clear: function () { },
|
||||
on_clear: function () {
|
||||
this.do_search();
|
||||
},
|
||||
/**
|
||||
* Called by a filter propagating its state changes
|
||||
*
|
||||
|
||||
@@ -123,6 +123,14 @@ openerp.base.ActionManager = openerp.base.Widget.extend({
|
||||
this.content_stop();
|
||||
var ClientWidget = openerp.base.client_actions.get_object(action.tag);
|
||||
(this.client_widget = new ClientWidget(this, action.params)).appendTo(this);
|
||||
},
|
||||
ir_actions_report_xml: function(action) {
|
||||
this.rpc('/base/report/get_report', {
|
||||
action: action,
|
||||
context: {}
|
||||
}).then(function(result) {
|
||||
debugger;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -438,14 +446,17 @@ openerp.base.Sidebar = openerp.base.Widget.extend({
|
||||
//TODO niv: maybe show a warning?
|
||||
return false;
|
||||
}
|
||||
var additional_context = {
|
||||
active_id: ids[0],
|
||||
active_ids: ids,
|
||||
active_model: self.widget_parent.dataset.model
|
||||
};
|
||||
self.rpc("/base/action/load", {
|
||||
action_id: item.action.id,
|
||||
context: {
|
||||
active_id: ids[0],
|
||||
active_ids: ids,
|
||||
active_model: self.widget_parent.dataset.model
|
||||
}
|
||||
context: additional_context
|
||||
}, function(result) {
|
||||
result.result.context = _.extend(result.result.context || {},
|
||||
additional_context);
|
||||
result.result.flags = result.result.flags || {};
|
||||
result.result.flags.new_window = true;
|
||||
self.do_action(result.result);
|
||||
@@ -472,6 +483,9 @@ openerp.base.Sidebar = openerp.base.Widget.extend({
|
||||
openerp.base.TranslateDialog = openerp.base.Dialog.extend({
|
||||
dialog_title: _t("Translations"),
|
||||
init: function(view) {
|
||||
// TODO fme: should add the language to fields_view_get because between the fields view get
|
||||
// and the moment the user opens the translation dialog, the user language could have been changed
|
||||
this.view_language = view.session.user_context.lang;
|
||||
this['on_button' + _t("Save")] = this.on_button_Save;
|
||||
this['on_button' + _t("Close")] = this.on_button_Close;
|
||||
this._super(view, {
|
||||
@@ -500,6 +514,9 @@ openerp.base.TranslateDialog = openerp.base.Dialog.extend({
|
||||
self.select_tab('view');
|
||||
}
|
||||
self.$fields_form = self.$element.find('.oe_translation_form');
|
||||
self.$fields_form.find('.oe_trad_field').change(function() {
|
||||
$(this).toggleClass('touched', ($(this).val() != $(this).attr('data-value')));
|
||||
});
|
||||
});
|
||||
return this;
|
||||
},
|
||||
@@ -514,19 +531,27 @@ openerp.base.TranslateDialog = openerp.base.Dialog.extend({
|
||||
_.each(self.languages, function(lg) {
|
||||
var deff = $.Deferred();
|
||||
deffered.push(deff);
|
||||
self.rpc('/base/dataset/get', {
|
||||
model: self.view.dataset.model,
|
||||
ids: [self.view.datarecord.id],
|
||||
fields: self.translatable_fields_keys,
|
||||
context: self.view.dataset.get_context({
|
||||
'lang': lg.code
|
||||
})
|
||||
}, function(values) {
|
||||
var callback = function(values) {
|
||||
_.each(self.translatable_fields_keys, function(f) {
|
||||
self.$fields_form.find('.oe_trad_field[name="' + lg.code + '-' + f + '"]').val(values[0][f] || '');
|
||||
self.$fields_form.find('.oe_trad_field[name="' + lg.code + '-' + f + '"]').val(values[0][f] || '').attr('data-value', values[0][f] || '');
|
||||
});
|
||||
deff.resolve();
|
||||
});
|
||||
}
|
||||
if (lg.code === self.view_language) {
|
||||
var values = {};
|
||||
_.each(self.translatable_fields_keys, function(field) {
|
||||
values[field] = self.view.fields[field].get_value();
|
||||
});
|
||||
callback([values]);
|
||||
} else {
|
||||
self.rpc('/base/dataset/get', {
|
||||
model: self.view.dataset.model,
|
||||
ids: [self.view.datarecord.id],
|
||||
fields: self.translatable_fields_keys,
|
||||
context: self.view.dataset.get_context({
|
||||
'lang': lg.code
|
||||
})}, callback);
|
||||
}
|
||||
});
|
||||
$.when.apply(null, deffered).then(callback);
|
||||
},
|
||||
@@ -562,6 +587,24 @@ openerp.base.TranslateDialog = openerp.base.Dialog.extend({
|
||||
});
|
||||
},
|
||||
on_button_Save: function() {
|
||||
var trads = {},
|
||||
self = this;
|
||||
self.$fields_form.find('.oe_trad_field.touched').each(function() {
|
||||
var field = $(this).attr('name').split('-');
|
||||
if (!trads[field[0]]) {
|
||||
trads[field[0]] = {};
|
||||
}
|
||||
trads[field[0]][field[1]] = $(this).val();
|
||||
});
|
||||
_.each(trads, function(data, code) {
|
||||
if (code === self.view_language) {
|
||||
_.each(data, function(value, field) {
|
||||
self.view.fields[field].set_value(value);
|
||||
});
|
||||
} else {
|
||||
self.view.dataset.write(self.view.datarecord.id, data, { 'lang': code });
|
||||
}
|
||||
});
|
||||
this.close();
|
||||
},
|
||||
on_button_Close: function() {
|
||||
@@ -667,7 +710,7 @@ openerp.base.View = openerp.base.Widget.extend({
|
||||
}, {
|
||||
label: "Translate",
|
||||
callback: this.on_sidebar_translate,
|
||||
classname: 'oe_sidebar_translate'
|
||||
classname: 'oe_sidebar_translate oe_hide'
|
||||
}, {
|
||||
label: "View Log",
|
||||
callback: this.on_sidebar_view_log,
|
||||
|
||||
@@ -325,15 +325,19 @@
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="Header">
|
||||
<a t-att-href="'/' + qs" class="company_logo_link">
|
||||
<div class="company_logo" />
|
||||
</a>
|
||||
<h1 class="header_title" t-if="session.session_is_valid()">
|
||||
<span class="database"><t t-esc="session.db"/></span> - <t t-esc="session.login"/> <br/>
|
||||
<small class="username">rpc_session_id: <t t-esc="session.session_id"/></small>
|
||||
<div>
|
||||
<a t-att-href="'/' + widget.qs" class="company_logo_link">
|
||||
<div class="company_logo" />
|
||||
</a>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="Header-content">
|
||||
<h1 class="header_title">
|
||||
<span class="database"><t t-esc="widget.session.db"/></span> - <t t-esc="widget.session.login"/> <br/>
|
||||
<small class="username">rpc_session_id: <t t-esc="widget.session.session_id"/></small>
|
||||
</h1>
|
||||
<div class="header_corner">
|
||||
<ul class="block" t-if="session.session_is_valid()">
|
||||
<ul class="block">
|
||||
<li>
|
||||
<a href="#home" title="Home" class="home"><img src="/base/static/src/img/header-home.png" width="16" height="16" border="0"/></a>
|
||||
</li>
|
||||
@@ -470,11 +474,11 @@
|
||||
</tr>
|
||||
<tr t-foreach="widget.view.translatable_fields" t-as="field">
|
||||
<td class="oe_form_frame_cell" width="1%" nowrap="nowrap">
|
||||
<label class="oe_form_label"><t t-esc="field.string"/>:</label>
|
||||
<label class="oe_label"><t t-esc="field.string"/>:</label>
|
||||
</td>
|
||||
<td t-foreach="widget.languages" t-as="lg" class="oe_form_frame_cell">
|
||||
<input t-if="field.type == 'char'" type="text" t-attf-name="#{lg.code}-#{field.name}" value="" class="oe_trad_field" style="width: 100%"/>
|
||||
<textarea t-if="field.type == 'text'" t-attf-name="#{lg.code}-#{field.name}" class="oe_trad_field" style="width: 100%"></textarea>
|
||||
<input t-if="field.type == 'char'" type="text" t-attf-name="#{lg.code}-#{field.name}" value="" data-value="" class="oe_trad_field" style="width: 100%"/>
|
||||
<textarea t-if="field.type == 'text'" t-attf-name="#{lg.code}-#{field.name}" data-value="" class="oe_trad_field" style="width: 100%"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -617,7 +621,7 @@
|
||||
</t>
|
||||
<t t-name="FormView">
|
||||
<div class="oe_form_header" t-att-id="view.element_id + '_header'">
|
||||
<h2 class="oe_view_title"><t t-esc="view.fields_view.arch.attrs.string"/> <button class="oe_get_xml_view">xml</button></h2>
|
||||
<h2 class="oe_view_title"><t t-esc="view.fields_view.arch.attrs.string"/> <button t-if="view.session.debug" class="oe_get_xml_view">View#<t t-esc="view.fields_view.view_id"/></button></h2>
|
||||
<div class="oe_form_buttons" t-if="view.options.action_buttons !== false">
|
||||
<!--<button type="button" class="oe_form_button_save">
|
||||
<span class="oe_form_on_update">Save</span>
|
||||
@@ -685,11 +689,11 @@
|
||||
<tr t-foreach="widget.table" t-as="row">
|
||||
<t t-foreach="row" t-as="td">
|
||||
<td t-att-colspan="td.colspan gt 1 ? td.colspan : undefined"
|
||||
t-att-width="td.width ? td.width : undefined"
|
||||
t-att-nowrap="td.is_field_label or td.is_field_m2o? 'true' : undefined"
|
||||
t-att-width="td.width"
|
||||
t-att-nowrap="td.nowrap or td.is_field_m2o? 'true' : undefined"
|
||||
t-att-valign="td.table ? 'top' : undefined"
|
||||
t-att-id="td.element_id"
|
||||
t-att-class="'oe_form_frame_cell oe_form_' + (td.is_field_label ? 'label' : (td.field ? 'field_' + td.type : td.type))"
|
||||
t-attf-class="oe_form_frame_cell #{td.classname}"
|
||||
>
|
||||
<t t-raw="td.render()"/>
|
||||
</td>
|
||||
@@ -715,13 +719,13 @@
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="WidgetSeparator">
|
||||
<div t-att-class="'separator ' + (widget.node.attrs.orientation || 'horizontal')">
|
||||
<div t-if="widget.orientation !== 'vertical'" t-att-class="'separator ' + widget.orientation">
|
||||
<t t-esc="widget.string"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="WidgetLabel">
|
||||
<label t-att-for="widget.element_id + '_field'"
|
||||
t-att-class="'oe_form_label' + (widget.help ? '_help' : '')"
|
||||
t-att-class="'oe_label' + (widget.help ? '_help' : '')"
|
||||
t-att-title="widget.help">
|
||||
<t t-esc="widget.string"/>
|
||||
<span t-if="widget.help">?</span>
|
||||
@@ -856,7 +860,8 @@
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="/base/static/src/img/placeholder.png" class="oe-binary-image" border="1"
|
||||
<img src="/base/static/src/img/placeholder.png" class="oe-binary-image"
|
||||
t-att-border="widget.readonly ? 0 : 1"
|
||||
t-att-id="widget.element_id + '_field'"
|
||||
t-att-name="widget.name"
|
||||
t-att-class="'field_' + widget.type"
|
||||
@@ -1014,10 +1019,11 @@
|
||||
><t t-raw="filter.render(defaults)"/></t
|
||||
></span>
|
||||
<t t-name="SearchView.field">
|
||||
<label style="display: block" t-att-title="attrs.help"
|
||||
<label t-att-class="'oe_label' + (attrs.help ? '_help' : '')"
|
||||
t-att-title="attrs.help"
|
||||
t-att-for="element_id">
|
||||
<t t-esc="attrs.string || attrs.name"/>
|
||||
<span t-if="attrs.help">(?)</span>
|
||||
<span t-if="attrs.help">?</span>
|
||||
</label>
|
||||
<div style="white-space: nowrap;">
|
||||
<input type="text" size="15" t-att-name="attrs.name"
|
||||
@@ -1028,10 +1034,11 @@
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="SearchView.field.selection">
|
||||
<label style="display: block" t-att-title="attrs.help"
|
||||
<label t-att-title="attrs.help"
|
||||
t-att-class="'oe_label' + (attrs.help ? '_help' : '')"
|
||||
t-att-for="element_id">
|
||||
<t t-esc="attrs.string || attrs.name"/>
|
||||
<span t-if="attrs.help">(?)</span>
|
||||
<span t-if="attrs.help">?</span>
|
||||
</label>
|
||||
<div style="white-space: nowrap;">
|
||||
<select t-att-name="attrs.name" t-att-id="element_id"
|
||||
@@ -1325,4 +1332,28 @@
|
||||
<td><button class="oe_export_button_export" id="delete_export_list">Delete</button></td>
|
||||
</tr>
|
||||
</t>
|
||||
<t t-name="Change_Pwd">
|
||||
<form name="change_password_form" class="oe_forms" method="POST">
|
||||
<table align="center">
|
||||
<tr>
|
||||
<td><label for="old_pwd">Old Password:</label></td>
|
||||
<td><input type="password" name="old_pwd"
|
||||
minlength="1" autofocus="autofocus"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="new_password">New Password:</label></td>
|
||||
<td><input type="password" name="new_password"
|
||||
minlength="1" autofocus="autofocus"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="confirm_pwd">Confirm Password:</label></td>
|
||||
<td><input type="password" name="confirm_pwd"
|
||||
minlength="1"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" align="right"><input type="submit" value="Change Password"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</t>
|
||||
</templates>
|
||||
|
||||
@@ -11,17 +11,17 @@ $(document).ready(function () {
|
||||
test("format_datetime", function () {
|
||||
var date = openerp.base.str_to_datetime("2009-05-04 12:34:23");
|
||||
var str = openerp.base.format_value(date, {type:"datetime"});
|
||||
equal(str, date.format("%m/%d/%Y %H:%M:%S"));
|
||||
equal(str, date.toString("M/d/yyyy h:mm:ss tt"));
|
||||
});
|
||||
test("format_date", function () {
|
||||
var date = openerp.base.str_to_datetime("2009-05-04 12:34:23");
|
||||
var str = openerp.base.format_value(date, {type:"date"});
|
||||
equal(str, date.format("%m/%d/%Y"));
|
||||
equal(str, date.toString("M/d/yyyy"));
|
||||
});
|
||||
test("format_time", function () {
|
||||
var date = openerp.base.str_to_datetime("2009-05-04 12:34:23");
|
||||
var str = openerp.base.format_value(date, {type:"time"});
|
||||
equal(str, date.format("%H:%M:%S"));
|
||||
equal(str, date.toString("h:mm:ss tt"));
|
||||
});
|
||||
test("format_float", function () {
|
||||
var fl = 12.1234;
|
||||
@@ -30,22 +30,25 @@ $(document).ready(function () {
|
||||
});
|
||||
test("parse_datetime", function () {
|
||||
var val = openerp.base.str_to_datetime("2009-05-04 12:34:23");
|
||||
var res = openerp.base.parse_value(val.format("%m/%d/%Y %H:%M:%S"), {type:"datetime"});
|
||||
equal(val.format("%m/%d/%Y %H:%M:%S"), res.format("%m/%d/%Y %H:%M:%S"));
|
||||
var res = openerp.base.parse_value(val.toString("M/d/yyyy h:mm:ss tt"), {type:"datetime"});
|
||||
equal(val.toString("M/d/yyyy h:mm:ss tt"), res.toString("M/d/yyyy h:mm:ss tt"));
|
||||
});
|
||||
test("parse_date", function () {
|
||||
var val = openerp.base.str_to_date("2009-05-04");
|
||||
var res = openerp.base.parse_value(val.format("%m/%d/%Y"), {type:"date"});
|
||||
equal(val.format("%m/%d/%Y %H:%M:%S"), res.format("%m/%d/%Y %H:%M:%S"));
|
||||
var res = openerp.base.parse_value(val.toString("M/d/yyyy"), {type:"date"});
|
||||
equal(val.toString("M/d/yyyy"), res.toString("M/d/yyyy"));
|
||||
});
|
||||
test("parse_time", function () {
|
||||
var val = openerp.base.str_to_time("12:34:23");
|
||||
var res = openerp.base.parse_value(val.format("%H:%M:%S"), {type:"time"});
|
||||
equal(val.format("%m/%d/%Y %H:%M:%S"), res.format("%m/%d/%Y %H:%M:%S"));
|
||||
var res = openerp.base.parse_value(val.toString("h:mm:ss tt"), {type:"time"});
|
||||
equal(val.toString("h:mm:ss tt"), res.toString("h:mm:ss tt"));
|
||||
});
|
||||
test("parse_float", function () {
|
||||
var str = "134,112.1234";
|
||||
var val = openerp.base.parse_value(str, {type:"float"});
|
||||
equal(val, 134112.1234);
|
||||
var str = "-134,112.1234";
|
||||
var val = openerp.base.parse_value(str, {type:"float"});
|
||||
equal(val, -134112.1234);
|
||||
});
|
||||
});
|
||||
@@ -14,7 +14,11 @@
|
||||
<!-- jquery -->
|
||||
<script src="/base/static/lib/jquery/jquery-1.6.2.js"></script>
|
||||
<script src="/base/static/lib/jquery.ui/js/jquery-ui-1.8.9.custom.min.js"></script>
|
||||
<script src="/base/static/lib/datejs/date-en-US.js"></script>
|
||||
|
||||
<script src="/base/static/lib/datejs/globalization/en-US.js"></script>
|
||||
<script src="/base/static/lib/datejs/core.js"></script>
|
||||
<script src="/base/static/lib/datejs/parser.js"></script>
|
||||
<script src="/base/static/lib/datejs/sugarpak.js"></script>
|
||||
<script src="/base/static/lib/datejs/extras.js"></script>
|
||||
|
||||
<script src="/base/static/lib/qweb/qweb.js"></script>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import base.common as openerpweb
|
||||
|
||||
from base.controllers.main import View
|
||||
import openerpweb
|
||||
|
||||
class CalendarView(View):
|
||||
_cp_path = "/base_calendar/calendarview"
|
||||
|
||||
@@ -251,7 +251,7 @@ openerp.base_calendar.CalendarView = openerp.base.View.extend({
|
||||
do_save_event: function(event_id, event_obj) {
|
||||
var self = this,
|
||||
data = this.get_event_data(event_obj);
|
||||
this.dataset.write(parseInt(event_id, 10), data, function() {
|
||||
this.dataset.write(parseInt(event_id, 10), data, {}, function() {
|
||||
self.refresh_minical();
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import openerpweb
|
||||
import base.common as openerpweb
|
||||
|
||||
WIDGET_CONTENT_PATTERN = """<!DOCTYPE html>
|
||||
<html>
|
||||
@@ -18,7 +18,7 @@ WIDGET_CONTENT_PATTERN = """<!DOCTYPE html>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
class Widgets(openerpweb.openerpweb.Controller):
|
||||
class Widgets(openerpweb.Controller):
|
||||
_cp_path = '/base_dashboard/widgets'
|
||||
|
||||
@openerpweb.httprequest
|
||||
|
||||
@@ -173,7 +173,6 @@
|
||||
.openerp .oe-dashboard-config-overview li.oe-done {
|
||||
cursor: default;
|
||||
color: #999999;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.openerp .oe-dashboard-layout_2-1 .index_0 .oe-dashboard-config-overview ul,
|
||||
|
||||
@@ -327,7 +327,7 @@ openerp.base_dashboard.ConfigOverview = openerp.base.View.extend({
|
||||
e.stopImmediatePropagation();
|
||||
var new_state = this.checked ? 'done' : 'open',
|
||||
todo_id = parseInt($(this).val(), 10);
|
||||
self.dataset.write(todo_id, {state: new_state}, function () {
|
||||
self.dataset.write(todo_id, {state: new_state}, {}, function () {
|
||||
self.start();
|
||||
});
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div t-name="StaticHome" class="oe-static-home">
|
||||
<h1>Welcome to your new OpenERP instance.</h1>
|
||||
<div class="oe-static-home-banner">
|
||||
<li>Bookmark this <a t-att-href="url">page</a></li>
|
||||
<li>Remember to bookmark this page.</li>
|
||||
<li>Remember your login: <i><t t-esc="session.login"/></i></li>
|
||||
<li>Choose the first OpenERP Application you want to install..</li>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import base.common as openerpweb
|
||||
from base.controllers.main import View
|
||||
import openerpweb
|
||||
|
||||
class DiagramView(View):
|
||||
_cp_path = "/base_diagram/diagram"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import openerpweb
|
||||
import base.common as openerpweb
|
||||
from base.controllers.main import View
|
||||
|
||||
class GanttView(View):
|
||||
|
||||
@@ -459,7 +459,7 @@ init: function(parent, element_id, dataset, view_id) {
|
||||
}else{
|
||||
data[this.date_delay] = task.getDuration();
|
||||
}
|
||||
this.dataset.write(event_id, data, function(result) {});
|
||||
this.dataset.write(event_id, data, {}, function(result) {});
|
||||
|
||||
},
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from base.controllers.main import View
|
||||
import openerpweb
|
||||
import base.common as openerpweb
|
||||
|
||||
class GraphView(View):
|
||||
_cp_path = "/base_graph/graphview"
|
||||
@@ -8,4 +8,4 @@ class GraphView(View):
|
||||
def load(self, req, model, view_id):
|
||||
fields_view = self.fields_view_get(req, model, view_id, 'graph')
|
||||
all_fields = req.session.model(model).fields_get()
|
||||
return {'fields_view': fields_view, 'all_fields':all_fields}
|
||||
return {'fields_view': fields_view, 'all_fields':all_fields}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys, time
|
||||
import cherrypy
|
||||
import time
|
||||
|
||||
import simplejson
|
||||
import random
|
||||
import openerpweb
|
||||
import base.common as openerpweb
|
||||
|
||||
#----------------------------------------------------------
|
||||
# OpenERP Web ajaxim Controllers
|
||||
@@ -38,7 +36,7 @@ class PollServerMessageQueue(object):
|
||||
if msg['to'] == recipient:
|
||||
return self.messages
|
||||
|
||||
def gc():
|
||||
def gc(self):
|
||||
# remove message older than 300s from self.l
|
||||
# remove dead users from self.users
|
||||
pass
|
||||
@@ -72,7 +70,6 @@ class PollServer(openerpweb.Controller):
|
||||
|
||||
#r = 'logged in'
|
||||
#u = generate random.randint(0,2**32)
|
||||
#s = cherrypy cookie id
|
||||
#f = mq.userlist()
|
||||
|
||||
# username = 'Guest'+ str(random.randint(0, 2**32))
|
||||
@@ -132,8 +129,6 @@ class PollServer(openerpweb.Controller):
|
||||
|
||||
msg = '[]'
|
||||
|
||||
cherrypy.response.headers['content-type'] = 'application/javascript';
|
||||
|
||||
for i in range(5):
|
||||
received_msg = mq.read('Guest1', i)
|
||||
if received_msg:
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
import main
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import glob, os
|
||||
import pprint
|
||||
|
||||
import simplejson
|
||||
|
||||
import openerpweb
|
||||
import openerpweb.ast
|
||||
import openerpweb.nonliterals
|
||||
|
||||
import cherrypy
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
/* jqm docs css
|
||||
|
||||
Beware: lots of last-minute CSS going on in here
|
||||
cobblers, shoes,
|
||||
*/
|
||||
|
||||
body { background: #dddddd; }
|
||||
|
||||
.ui-mobile #jqm-home { background: #e5e5e5 url(../images/jqm-sitebg.png) top center repeat-x; }
|
||||
.ui-mobile #jqm-homeheader { padding: 40px 10px 0; text-align: center; margin: 0 auto; }
|
||||
.ui-mobile #jqm-homeheader h1 { margin: 0 0 ; }
|
||||
.ui-mobile #jqm-homeheader p { margin: .3em 0 0; line-height: 1.3; font-size: .9em; font-weight: bold; color: #666; }
|
||||
.ui-mobile #jqm-version { text-indent: -99999px; background: url(../images/version.png) top right no-repeat; width: 119px; height: 122px; overflow: hidden; position: absolute; z-index: 50; top: 0; right: 0; }
|
||||
.ui-mobile .jqm-themeswitcher { margin: 10px 25px 10px 10px; }
|
||||
|
||||
h2 { margin-top:1.5em; }
|
||||
p code { font-size:1.2em; font-weight:bold; }
|
||||
|
||||
dt { font-weight: bold; margin: 2em 0 .5em; }
|
||||
dt code, dd code { font-size:1.3em; line-height:150%; }
|
||||
pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; }
|
||||
|
||||
#jqm-homeheader img { width: 235px; }
|
||||
|
||||
.ui-header .jqm-home { top:0.65em; }
|
||||
nav { margin: 0; }
|
||||
|
||||
p.intro {
|
||||
font-size: .96em;
|
||||
line-height: 1.3;
|
||||
border-top: 1px solid #75ae18;
|
||||
border-bottom: 0;
|
||||
background: none;
|
||||
margin: 1.5em 0;
|
||||
padding: 1.5em 15px 0;
|
||||
|
||||
}
|
||||
p.intro strong {
|
||||
color: #558e08;
|
||||
}
|
||||
.footer-docs {
|
||||
padding: 5px 0;
|
||||
}
|
||||
.footer-docs p {
|
||||
float: left;
|
||||
margin-left:15px;
|
||||
font-weight: normal;
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
.type-interior .content-secondary {
|
||||
border-right: 0;
|
||||
border-left: 0;
|
||||
margin: 10px -15px 0;
|
||||
background: #fff;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
.type-home .ui-content {
|
||||
margin-top: 5px;
|
||||
}
|
||||
.type-interior .ui-content {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.content-secondary .ui-collapsible-contain {
|
||||
padding: 10px 15px;
|
||||
|
||||
}
|
||||
.content-secondary .ui-collapsible-heading {
|
||||
margin: 0 0 30px;
|
||||
}
|
||||
.content-secondary .ui-collapsible-heading-collapsed,
|
||||
.content-secondary .ui-collapsible-content {
|
||||
padding:0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* F bar theme - just for the docs overview headers */
|
||||
.ui-bar-f {
|
||||
border: 1px solid #56A00E;
|
||||
background: #74b042;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 -1px 1px #234403;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#74b042,
|
||||
#56A00E);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #74b042),
|
||||
color-stop(1, #56A00E));
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#81a8ce', EndColorStr='#5e87b0')";
|
||||
}
|
||||
.ui-bar-f,
|
||||
.ui-bar-f .ui-link-inherit {
|
||||
color: #fff;
|
||||
}
|
||||
.ui-bar-f .ui-link {
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* docs site layout */
|
||||
|
||||
@media all and (min-width: 650px){
|
||||
|
||||
.jqm-home {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 0;
|
||||
}
|
||||
.type-home .ui-content {
|
||||
margin-top: 5px;
|
||||
}
|
||||
.ui-mobile #jqm-homeheader {
|
||||
max-width: 340px;
|
||||
}
|
||||
.ui-mobile .jqm-themeswitcher {
|
||||
float: right;
|
||||
}
|
||||
p.intro {
|
||||
margin: 2em 0;
|
||||
}
|
||||
.type-home .ui-content,
|
||||
.type-interior .ui-content {
|
||||
padding: 0;
|
||||
background: url(../images/px-ccc.gif) 50% 0 repeat-y;
|
||||
}
|
||||
.type-interior .ui-content {
|
||||
background-position: 45%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.content-secondary {
|
||||
text-align: left;
|
||||
float: left;
|
||||
width: 45%;
|
||||
background: none;
|
||||
border-top: 0;
|
||||
}
|
||||
.content-secondary,
|
||||
.type-interior .content-secondary {
|
||||
margin: 30px 0 20px 2%;
|
||||
padding: 20px 4% 0 0;
|
||||
background: none;
|
||||
}
|
||||
.type-index .content-secondary {
|
||||
padding: 0;
|
||||
}
|
||||
.type-index .content-secondary .ui-listview {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ui-mobile #jqm-homeheader {
|
||||
padding: 0;
|
||||
}
|
||||
.content-primary {
|
||||
width: 45%;
|
||||
float: right;
|
||||
margin-top: 30px;
|
||||
margin-right: 1%;
|
||||
padding-right: 1%;
|
||||
}
|
||||
.content-primary ul:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.content-secondary h2 {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
}
|
||||
.type-interior .content-primary {
|
||||
padding: 1.5em 6% 3em 0;
|
||||
margin: 0;
|
||||
}
|
||||
/* fix up the collapsibles - expanded on desktop */
|
||||
.content-secondary .ui-collapsible-heading {
|
||||
display: none;
|
||||
}
|
||||
.content-secondary .ui-collapsible-contain {
|
||||
margin:0;
|
||||
}
|
||||
.content-secondary .ui-collapsible-content {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.type-interior .content-secondary .ui-li-divider {
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
.type-interior .content-secondary {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
}
|
||||
@media all and (min-width: 750px){
|
||||
.type-home .ui-content,
|
||||
.type-interior .ui-content {
|
||||
background-position: 39%;
|
||||
}
|
||||
.content-secondary {
|
||||
width: 34%;
|
||||
}
|
||||
.content-primary {
|
||||
width: 56%;
|
||||
padding-right: 1%;
|
||||
}
|
||||
.type-interior .ui-content {
|
||||
background-position: 34%;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 1200px){
|
||||
.type-home .ui-content{
|
||||
background-position: 38.5%;
|
||||
}
|
||||
.type-interior .ui-content {
|
||||
background-position: 30%;
|
||||
}
|
||||
.content-secondary {
|
||||
width: 30%;
|
||||
padding-right:6%;
|
||||
margin: 30px 0 20px 5%;
|
||||
}
|
||||
.type-interior .content-secondary {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.content-primary {
|
||||
width: 50%;
|
||||
margin-right: 5%;
|
||||
padding-right: 3%;
|
||||
}
|
||||
.type-interior .content-primary {
|
||||
width: 60%;
|
||||
}
|
||||
}
|
||||
@@ -15,18 +15,18 @@
|
||||
color: #ffffff;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 -1px 1px #000000;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#3c3c3c,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#3c3c3c,
|
||||
#111111);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #3c3c3c),
|
||||
color-stop(1, #111111));
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#3c3c3c', EndColorStr='#111111')";
|
||||
}
|
||||
.ui-bar-a,
|
||||
.ui-bar-a input,
|
||||
.ui-bar-a select,
|
||||
.ui-bar-a textarea,
|
||||
.ui-bar-a,
|
||||
.ui-bar-a input,
|
||||
.ui-bar-a select,
|
||||
.ui-bar-a textarea,
|
||||
.ui-bar-a button {
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
}
|
||||
@@ -43,8 +43,8 @@
|
||||
color: #fff;
|
||||
text-shadow: 0 1px 0 #000;
|
||||
font-weight: normal;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#666666,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#666666,
|
||||
#222222);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #666666),
|
||||
@@ -77,8 +77,8 @@
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 1px #000;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#555555,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#555555,
|
||||
#333333);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #555555),
|
||||
@@ -94,8 +94,8 @@
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 1px #000;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#666666,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#666666,
|
||||
#444444);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #666666),
|
||||
@@ -111,8 +111,8 @@
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 1px #000;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#333333,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#333333,
|
||||
#5a5a5a);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #333333),
|
||||
@@ -139,8 +139,8 @@
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 -1px 1px #254f7a;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#81a8ce,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#81a8ce,
|
||||
#5e87b0);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #81a8ce),
|
||||
@@ -168,8 +168,8 @@
|
||||
color: #333333;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
font-weight: normal;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#e6e6e6,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#e6e6e6,
|
||||
#cccccc);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #e6e6e6),
|
||||
@@ -196,8 +196,8 @@
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 1px #145072;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#4e89c5,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#4e89c5,
|
||||
#2567ab);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #5f9cc5),
|
||||
@@ -213,8 +213,8 @@
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 1px #014D68;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#72b0d4,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#72b0d4,
|
||||
#4b88b6);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #72b0d4),
|
||||
@@ -230,8 +230,8 @@
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 1px #225377;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#396b9e,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#396b9e,
|
||||
#4e89c5);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #396b9e),
|
||||
@@ -258,7 +258,7 @@
|
||||
color: #3E3E3E;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 1px 1px #fff;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#f0f0f0,
|
||||
#e9eaeb);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
@@ -278,8 +278,8 @@
|
||||
color: #333333;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
background: #f0f0f0;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#eeeeee,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#eeeeee,
|
||||
#dddddd);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #eeeeee),
|
||||
@@ -307,8 +307,8 @@
|
||||
font-weight: bold;
|
||||
color: #444;
|
||||
text-shadow: 0 1px 1px #f6f6f6;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#fefefe,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#fefefe,
|
||||
#eeeeee);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #fdfdfd),
|
||||
@@ -325,8 +325,8 @@
|
||||
font-weight: bold;
|
||||
color: #101010;
|
||||
text-shadow: 0 1px 1px #fff;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#ededed,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#ededed,
|
||||
#dadada);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #ededed),
|
||||
@@ -342,8 +342,8 @@
|
||||
font-weight: bold;
|
||||
color: #111111;
|
||||
text-shadow: 0 1px 1px #ffffff;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#eeeeee,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#eeeeee,
|
||||
#fdfdfd);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #eeeeee),
|
||||
@@ -369,8 +369,8 @@
|
||||
background: #bbb;
|
||||
color: #333;
|
||||
text-shadow: 0 1px 0 #eee;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#ddd,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#ddd,
|
||||
#bbb);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #ddd),
|
||||
@@ -428,8 +428,8 @@
|
||||
color: #222;
|
||||
cursor: pointer;
|
||||
text-shadow: 0 1px 1px #fff;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#fdfdfd,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#fdfdfd,
|
||||
#eeeeee);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #fdfdfd),
|
||||
@@ -445,8 +445,8 @@
|
||||
font-weight: bold;
|
||||
color: #111;
|
||||
text-shadow: 0 1px 1px #ffffff;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#eeeeee,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#eeeeee,
|
||||
#ffffff);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #eeeeee),
|
||||
@@ -472,8 +472,8 @@
|
||||
background: #fadb4e;
|
||||
color: #333;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#fceda7,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#fceda7,
|
||||
#fadb4e);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #fceda7),
|
||||
@@ -499,8 +499,8 @@
|
||||
color: #333333;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
background: #faeb9e;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#fff,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#fff,
|
||||
#faeb9e);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #fff),
|
||||
@@ -527,8 +527,8 @@
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#fceda7,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#fceda7,
|
||||
#fadb4e);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #fceda7),
|
||||
@@ -544,8 +544,8 @@
|
||||
font-weight: bold;
|
||||
color: #111;
|
||||
text-shadow: 0 1px 1px #fff;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#fcf0b5,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#fcf0b5,
|
||||
#fbe26f);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #fcf0b5),
|
||||
@@ -562,8 +562,8 @@
|
||||
font-weight: bold;
|
||||
color: #111;
|
||||
text-shadow: 0 1px 1px #ffffff;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#fadb4e,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#fadb4e,
|
||||
#fceda7);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #fadb4e),
|
||||
@@ -581,7 +581,7 @@
|
||||
}
|
||||
|
||||
|
||||
/* links within "buttons"
|
||||
/* links within "buttons"
|
||||
-----------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
a.ui-link-inherit {
|
||||
@@ -600,8 +600,8 @@ a.ui-link-inherit {
|
||||
cursor: pointer;
|
||||
text-shadow: 0 -1px 1px #145072;
|
||||
text-decoration: none;
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#85bae4,
|
||||
background-image: -moz-linear-gradient(top,
|
||||
#85bae4,
|
||||
#5393c5);
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,
|
||||
color-stop(0, #85bae4),
|
||||
@@ -726,11 +726,11 @@ a.ui-link-inherit {
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
|
||||
only screen and (min--moz-device-pixel-ratio: 1.5),
|
||||
only screen and (min-resolution: 240dpi) {
|
||||
|
||||
|
||||
.ui-icon-plus, .ui-icon-minus, .ui-icon-delete, .ui-icon-arrow-r,
|
||||
.ui-icon-arrow-l, .ui-icon-arrow-u, .ui-icon-arrow-d, .ui-icon-check,
|
||||
.ui-icon-gear, .ui-icon-refresh, .ui-icon-forward, .ui-icon-back,
|
||||
.ui-icon-grid, .ui-icon-star, .ui-icon-alert, .ui-icon-info, .ui-icon-home, .ui-icon-search,
|
||||
.ui-icon-grid, .ui-icon-star, .ui-icon-alert, .ui-icon-info, .ui-icon-home, .ui-icon-search,
|
||||
.ui-icon-checkbox-off, .ui-icon-checkbox-on, .ui-icon-radio-off, .ui-icon-radio-on {
|
||||
background-image: url(../img/icons-36-white.png);
|
||||
-moz-background-size: 776px 18px;
|
||||
@@ -909,19 +909,19 @@ a.ui-link-inherit {
|
||||
/* radius clip workaround for cleaning up corner trapping */
|
||||
.ui-corner-tl,
|
||||
.ui-corner-tr,
|
||||
.ui-corner-bl,
|
||||
.ui-corner-bl,
|
||||
.ui-corner-br,
|
||||
.ui-corner-top,
|
||||
.ui-corner-bottom,
|
||||
.ui-corner-bottom,
|
||||
.ui-corner-right,
|
||||
.ui-corner-left,
|
||||
.ui-corner-all,
|
||||
.ui-btn-corner-tl,
|
||||
.ui-btn-corner-tr,
|
||||
.ui-btn-corner-bl,
|
||||
.ui-btn-corner-bl,
|
||||
.ui-btn-corner-br,
|
||||
.ui-btn-corner-top,
|
||||
.ui-btn-corner-bottom,
|
||||
.ui-btn-corner-bottom,
|
||||
.ui-btn-corner-right,
|
||||
.ui-btn-corner-left,
|
||||
.ui-btn-corner-all {
|
||||
@@ -997,7 +997,7 @@ a.ui-link-inherit {
|
||||
* jQuery Mobile Framework
|
||||
* Copyright (c) jQuery Project
|
||||
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
|
||||
* Note: Code is in draft form and is subject to change
|
||||
* Note: Code is in draft form and is subject to change
|
||||
*/
|
||||
|
||||
/* some unsets - more probably needed */
|
||||
@@ -1009,7 +1009,7 @@ a.ui-link-inherit {
|
||||
.ui-mobile-viewport { margin: 0; overflow-x: hidden; -webkit-text-size-adjust: none; -ms-text-size-adjust:none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); }
|
||||
|
||||
/* "page" containers - full-screen views, one should always be in view post-pageload */
|
||||
.ui-mobile [data-role=page], .ui-mobile [data-role=dialog], .ui-page { top: 0; left: 0; width: 100%; min-height: 100%; position: absolute; display: none; border: 0; }
|
||||
.ui-mobile [data-role=page], .ui-mobile [data-role=dialog], .ui-page { top: 0; left: 0; width: 100%; min-height: 100%; position: absolute; display: none; border: 0; }
|
||||
.ui-mobile .ui-page-active { display: block; overflow: visible; }
|
||||
|
||||
/*orientations from js are available */
|
||||
@@ -1497,8 +1497,8 @@ Built by David Kaneda and maintained by Jonathan Stark.
|
||||
|
||||
@media all and (min-width: 450px){
|
||||
.ui-controlgroup-label { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0; }
|
||||
.ui-controlgroup-controls { width: 60%; display: inline-block; }
|
||||
}
|
||||
.ui-controlgroup-controls { width: 60%; display: inline-block; }
|
||||
}
|
||||
|
||||
/*
|
||||
* jQuery Mobile Framework
|
||||
@@ -1535,7 +1535,7 @@ Built by David Kaneda and maintained by Jonathan Stark.
|
||||
.ui-field-contain:first-child { border-top-width: 0; }
|
||||
@media all and (min-width: 450px){
|
||||
.ui-field-contain { border-width: 0; padding: 0; margin: 1em 0; }
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* jQuery Mobile Framework
|
||||
@@ -1549,7 +1549,7 @@ Built by David Kaneda and maintained by Jonathan Stark.
|
||||
@-moz-document url-prefix() {.ui-select .ui-btn select { opacity: 0.0001; }}
|
||||
.ui-select .ui-btn select.ui-select-nativeonly { opacity: 1; text-indent: 0; }
|
||||
|
||||
.ui-select .ui-btn-icon-right .ui-btn-inner { padding-right: 45px; }
|
||||
.ui-select .ui-btn-icon-right .ui-btn-inner { padding-right: 45px; }
|
||||
.ui-select .ui-btn-icon-right .ui-icon { right: 15px; }
|
||||
|
||||
/* labels */
|
||||
@@ -1572,7 +1572,7 @@ label.ui-select { font-size: 16px; line-height: 1.4; font-weight: normal; margi
|
||||
@media all and (min-width: 450px){
|
||||
label.ui-select { display: inline-block; width: 20%; margin: 0 2% 0 0; }
|
||||
.ui-select { width: 60%; display: inline-block; }
|
||||
}
|
||||
}
|
||||
|
||||
/* when no placeholder is defined in a multiple select, the header height doesn't even extend past the close button. this shim's content in there */
|
||||
.ui-selectmenu .ui-header h1:after { content: '.'; visibility: hidden; }
|
||||
@@ -1594,9 +1594,9 @@ textarea.ui-input-text { height: 50px; -webkit-transition: height 200ms linear;
|
||||
/* orientation adjustments - incomplete!*/
|
||||
@media all and (min-width: 450px){
|
||||
label.ui-input-text { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0 }
|
||||
input.ui-input-text,
|
||||
textarea.ui-input-text,
|
||||
.ui-input-search { width: 60%; display: inline-block; }
|
||||
input.ui-input-text,
|
||||
textarea.ui-input-text,
|
||||
.ui-input-search { width: 60%; display: inline-block; }
|
||||
.ui-input-search { width: 50%; }
|
||||
.ui-input-search input.ui-input-text { width: 98%; /*echos rule from above*/ }
|
||||
}
|
||||
@@ -1631,7 +1631,7 @@ ol.ui-listview .ui-li-jsnumbering:before { content: "" !important; } /* to avoid
|
||||
.ui-li-aside { float: right; width: 50%; text-align: right; margin: .3em 0; }
|
||||
@media all and (min-width: 480px){
|
||||
.ui-li-aside { width: 45%; }
|
||||
}
|
||||
}
|
||||
.ui-li-divider { cursor: default; }
|
||||
.ui-li-has-alt .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-alt { padding-right: 95px; }
|
||||
.ui-li-count { position: absolute; font-size: 11px; font-weight: bold; padding: .2em .5em; top: 50%; margin-top: -.9em; right: 38px; }
|
||||
@@ -1666,7 +1666,7 @@ a.ui-slider-handle .ui-btn-inner { padding-left: 0; padding-right: 0; }
|
||||
@media all and (min-width: 480px){
|
||||
label.ui-slider { display: inline-block; width: 20%; margin: 0 2% 0 0; }
|
||||
div.ui-slider { width: 45%; }
|
||||
}
|
||||
}
|
||||
|
||||
div.ui-slider-switch { height: 32px; overflow: hidden; margin-left: 0; }
|
||||
div.ui-slider-inneroffset { margin-left: 50%; position: absolute; top: 1px; height: 100%; width: 50%; }
|
||||
@@ -1680,4 +1680,4 @@ div.ui-slider-switch div.ui-slider-labelbg-b { width: 60%; height: 100%; right:
|
||||
div.ui-slider-switch a.ui-slider-handle { z-index: 20; width: 101%; height: 32px; margin-top: -18px; margin-left: -101%; }
|
||||
span.ui-slider-label { width: 100%; position: absolute;height: 32px; font-size: 16px; text-align: center; line-height: 2; background: none; border-color: transparent; }
|
||||
span.ui-slider-label-a { left: -100%; margin-right: -1px }
|
||||
span.ui-slider-label-b { right: -100%; margin-left: -1px }
|
||||
span.ui-slider-label-b { right: -100%; margin-left: -1px }
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
//set up the theme switcher on the homepage
|
||||
$('div').live('pagecreate',function(event){
|
||||
if( !$(this).is('.ui-dialog')){
|
||||
var appendEl = $(this).find('.ui-footer:last');
|
||||
|
||||
if( !appendEl.length ){
|
||||
appendEl = $(this).find('.ui-content');
|
||||
}
|
||||
|
||||
if( appendEl.is("[data-position]") ){
|
||||
return;
|
||||
}
|
||||
|
||||
$('<a href="#themeswitcher" data-'+ $.mobile.ns +'rel="dialog" data-'+ $.mobile.ns +'transition="pop">Switch theme</a>')
|
||||
.buttonMarkup({
|
||||
'icon':'gear',
|
||||
'inline': true,
|
||||
'shadow': false,
|
||||
'theme': 'd'
|
||||
})
|
||||
.appendTo( appendEl )
|
||||
.wrap('<div class="jqm-themeswitcher">')
|
||||
.bind( "vclick", function(){
|
||||
$.themeswitcher();
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//collapse page navs after use
|
||||
$(function(){
|
||||
$('body').delegate('.content-secondary .ui-collapsible-content', 'vclick', function(){
|
||||
$(this).trigger("collapse")
|
||||
});
|
||||
});
|
||||
|
||||
function setDefaultTransition(){
|
||||
var winwidth = $( window ).width(),
|
||||
trans ="slide";
|
||||
|
||||
if( winwidth >= 1000 ){
|
||||
trans = "none";
|
||||
}
|
||||
else if( winwidth >= 650 ){
|
||||
trans = "fade";
|
||||
}
|
||||
|
||||
$.mobile.defaultPageTransition = trans;
|
||||
}
|
||||
|
||||
|
||||
//set default documentation
|
||||
$( document ).bind( "mobileinit", setDefaultTransition );
|
||||
$(function(){
|
||||
$( window ).bind( "throttledresize", setDefaultTransition );
|
||||
});
|
||||
$(document).bind('mobileinit',function(){
|
||||
$.mobile.selectmenu.prototype.options.nativeMenu = false;
|
||||
});
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,340 @@
|
||||
/*!
|
||||
* jQuery Mobile v1.0b1
|
||||
* http://jquerymobile.com/
|
||||
*
|
||||
* Copyright 2010, jQuery Project
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*/
|
||||
(function(a,d){if(a.cleanData){var c=a.cleanData;a.cleanData=function(e){for(var b=0,d;(d=e[b])!=null;b++)a(d).triggerHandler("remove");c(e)}}else{var b=a.fn.remove;a.fn.remove=function(e,c){return this.each(function(){c||(!e||a.filter(e,[this]).length)&&a("*",this).add([this]).each(function(){a(this).triggerHandler("remove")});return b.call(a(this),e,c)})}}a.widget=function(e,b,c){var d=e.split(".")[0],h,e=e.split(".")[1];h=d+"-"+e;if(!c)c=b,b=a.Widget;a.expr[":"][h]=function(b){return!!a.data(b,
|
||||
e)};a[d]=a[d]||{};a[d][e]=function(a,e){arguments.length&&this._createWidget(a,e)};b=new b;b.options=a.extend(!0,{},b.options);a[d][e].prototype=a.extend(!0,b,{namespace:d,widgetName:e,widgetEventPrefix:a[d][e].prototype.widgetEventPrefix||e,widgetBaseClass:h},c);a.widget.bridge(e,a[d][e])};a.widget.bridge=function(e,b){a.fn[e]=function(c){var i=typeof c==="string",h=Array.prototype.slice.call(arguments,1),l=this,c=!i&&h.length?a.extend.apply(null,[!0,c].concat(h)):c;if(i&&c.charAt(0)==="_")return l;
|
||||
i?this.each(function(){var b=a.data(this,e);if(!b)throw"cannot call methods on "+e+" prior to initialization; attempted to call method '"+c+"'";if(!a.isFunction(b[c]))throw"no such method '"+c+"' for "+e+" widget instance";var f=b[c].apply(b,h);if(f!==b&&f!==d)return l=f,!1}):this.each(function(){var d=a.data(this,e);d?d.option(c||{})._init():a.data(this,e,new b(c,this))});return l}};a.Widget=function(a,b){arguments.length&&this._createWidget(a,b)};a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",
|
||||
options:{disabled:!1},_createWidget:function(b,c){a.data(c,this.widgetName,this);this.element=a(c);this.options=a.extend(!0,{},this.options,this._getCreateOptions(),b);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){var b={};a.metadata&&(b=a.metadata.get(element)[this.widgetName]);return b},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);
|
||||
this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(b,c){var g=b;if(arguments.length===0)return a.extend({},this.options);if(typeof b==="string"){if(c===d)return this.options[b];g={};g[b]=c}this._setOptions(g);return this},_setOptions:function(b){var c=this;a.each(b,function(a,b){c._setOption(a,b)});return this},_setOption:function(a,b){this.options[a]=b;a==="disabled"&&
|
||||
this.widget()[b?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",b);return this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_trigger:function(b,c,d){var i=this.options[b],c=a.Event(c);c.type=(b===this.widgetEventPrefix?b:this.widgetEventPrefix+b).toLowerCase();d=d||{};if(c.originalEvent)for(var b=a.event.props.length,h;b;)h=a.event.props[--b],c[h]=c.originalEvent[h];this.element.trigger(c,
|
||||
d);return!(a.isFunction(i)&&i.call(this.element[0],c,d)===!1||c.isDefaultPrevented())}}})(jQuery);(function(a,d){a.widget("mobile.widget",{_getCreateOptions:function(){var c=this.element,b={};a.each(this.options,function(a){var f=c.jqmData(a.replace(/[A-Z]/g,function(a){return"-"+a.toLowerCase()}));f!==d&&(b[a]=f)});return b}})})(jQuery);
|
||||
(function(a){function d(){var d=c.width(),g=[],i=[],h;b.removeClass("min-width-"+e.join("px min-width-")+"px max-width-"+e.join("px max-width-")+"px");a.each(e,function(a,b){d>=b&&g.push("min-width-"+b+"px");d<=b&&i.push("max-width-"+b+"px")});g.length&&(h=g.join(" "));i.length&&(h+=" "+i.join(" "));b.addClass(h)}var c=a(window),b=a("html"),e=[320,480,768,1024];a.mobile.media=function(){var c={},e=a("<div id='jquery-mediatest'>"),d=a("<body>").append(e);return function(a){if(!(a in c)){var l=document.createElement("style"),
|
||||
m="@media "+a+" { #jquery-mediatest { position:absolute; } }";l.type="text/css";l.styleSheet?l.styleSheet.cssText=m:l.appendChild(document.createTextNode(m));b.prepend(d).prepend(l);c[a]=e.css("position")==="absolute";d.add(l).remove()}return c[a]}}();a.mobile.addResolutionBreakpoints=function(b){a.type(b)==="array"?e=e.concat(b):e.push(b);e.sort(function(a,b){return a-b});d()};a(document).bind("mobileinit.htmlclass",function(){c.bind("orientationchange.htmlclass throttledResize.htmlclass",function(a){a.orientation&&
|
||||
b.removeClass("portrait landscape").addClass(a.orientation);d()})});a(function(){c.trigger("orientationchange.htmlclass")})})(jQuery);
|
||||
(function(a,d){function c(a){var b=a.charAt(0).toUpperCase()+a.substr(1),a=(a+" "+f.join(b+" ")+b).split(" "),c;for(c in a)if(e[c]!==d)return!0}var b=a("<body>").prependTo("html"),e=b[0].style,f=["webkit","moz","o"],g="palmGetResource"in window,i=window.blackberry;a.mobile.browser={};a.mobile.browser.ie=function(){for(var a=3,b=document.createElement("div"),c=b.all||[];b.innerHTML="<\!--[if gt IE "+ ++a+"]><br><![endif]--\>",c[0];);return a>4?a:!a}();a.extend(a.support,{orientation:"orientation"in
|
||||
window,touch:"ontouchend"in document,cssTransitions:"WebKitTransitionEvent"in window,pushState:!!history.pushState,mediaquery:a.mobile.media("only all"),cssPseudoElement:!!c("content"),boxShadow:!!c("boxShadow")&&!i,scrollTop:("pageXOffset"in window||"scrollTop"in document.documentElement||"scrollTop"in b[0])&&!g,dynamicBaseTag:function(){var c=location.protocol+"//"+location.host+location.pathname+"ui-dir/",e=a("head base"),d=null,f="";e.length?f=e.attr("href"):e=d=a("<base>",{href:c}).appendTo("head");
|
||||
var g=a("<a href='testurl'></a>").prependTo(b)[0].href;e[0].href=f?f:location.pathname;d&&d.remove();return g.indexOf(c)===0}(),eventCapture:"addEventListener"in document});b.remove();a.support.boxShadow||a("html").addClass("ui-mobile-nosupport-boxshadow")})(jQuery);
|
||||
(function(a,d,c,b){function e(a){for(;a&&typeof a.originalEvent!=="undefined";)a=a.originalEvent;return a}function f(b){for(var c={};b;){var e=a.data(b,n),d;for(d in e)if(e[d])c[d]=c.hasVirtualBinding=!0;b=b.parentNode}return c}function g(){v&&(clearTimeout(v),v=0);v=setTimeout(function(){A=v=0;B.length=0;w=!1;r=!0},a.vmouse.resetTimerDuration)}function i(c,d,r){var f=!1,g;if(!(g=r&&r[c])){if(r=!r)a:{for(r=d.target;r;){if((g=a.data(r,n))&&(!c||g[c]))break a;r=r.parentNode}r=null}g=r}if(g){f=d;r=f.type;
|
||||
f=a.Event(f);f.type=c;var h=f.originalEvent,j=a.event.props;if(h)for(c=j.length;c;)g=j[--c],f[g]=h[g];if(r.search(/^touch/)!==-1&&(c=e(h),r=c.touches,c=c.changedTouches,r=r&&r.length?r[0]:c&&c.length?c[0]:b)){c=0;for(h=y.length;c<h;c++)g=y[c],f[g]=r[g]}a(d.target).trigger(f);f=f.isDefaultPrevented()}return f}function h(b){var c=a.data(b.target,z);!w&&(!A||A!==c)&&i("v"+b.type,b)}function l(b){var c=e(b).touches;if(c&&c.length===1){var d=b.target,c=f(d);if(c.hasVirtualBinding)A=F++,a.data(d,z,A),v&&
|
||||
(clearTimeout(v),v=0),s=r=!1,d=e(b).touches[0],x=d.pageX,u=d.pageY,i("vmouseover",b,c),i("vmousedown",b,c)}}function m(a){r||(s||i("vmousecancel",a,f(a.target)),s=!0,g())}function o(b){if(!r){var c=e(b).touches[0],d=s,h=a.vmouse.moveDistanceThreshold;s=s||Math.abs(c.pageX-x)>h||Math.abs(c.pageY-u)>h;c=f(b.target);s&&!d&&i("vmousecancel",b,c);i("vmousemove",b,c);g()}}function j(a){if(!r){r=!0;var b=f(a.target);i("vmouseup",a,b);if(!s&&i("vclick",a,b)){var c=e(a).changedTouches[0];B.push({touchID:A,
|
||||
x:c.clientX,y:c.clientY});w=!0}i("vmouseout",a,b);s=!1;g()}}function p(b){var b=a.data(b,n),c;if(b)for(c in b)if(b[c])return!0;return!1}function k(){}function q(b){var c=b.substr(1);return{setup:function(){p(this)||a.data(this,n,{});a.data(this,n)[b]=!0;t[b]=(t[b]||0)+1;t[b]===1&&C.bind(c,h);a(this).bind(c,k);if(E)t.touchstart=(t.touchstart||0)+1,t.touchstart===1&&C.bind("touchstart",l).bind("touchend",j).bind("touchmove",o).bind("scroll",m)},teardown:function(){--t[b];t[b]||C.unbind(c,h);E&&(--t.touchstart,
|
||||
t.touchstart||C.unbind("touchstart",l).unbind("touchmove",o).unbind("touchend",j).unbind("scroll",m));var d=a(this),e=a.data(this,n);e&&(e[b]=!1);d.unbind(c,k);p(this)||d.removeData(n)}}}var n="virtualMouseBindings",z="virtualTouchID",d="vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split(" "),y="clientX clientY pageX pageY screenX screenY".split(" "),t={},v=0,x=0,u=0,s=!1,B=[],w=!1,r=!1,E=a.support.eventCapture,C=a(c),F=1,A=0;a.vmouse={moveDistanceThreshold:10,clickDistanceThreshold:10,
|
||||
resetTimerDuration:1500};for(var D=0;D<d.length;D++)a.event.special[d[D]]=q(d[D]);E&&c.addEventListener("click",function(b){var c=B.length,d=b.target;if(c)for(var e=b.clientX,r=b.clientY,f=a.vmouse.clickDistanceThreshold,g=d;g;){for(var h=0;h<c;h++){var j=B[h];if(g===d&&Math.abs(j.x-e)<f&&Math.abs(j.y-r)<f||a.data(g,z)===j.touchID){b.preventDefault();b.stopPropagation();return}}g=g.parentNode}},!0)})(jQuery,window,document);
|
||||
(function(a,d){function c(b,c,d){var e=d.type;d.type=c;a.event.handle.call(b,d);d.type=e}a.each("touchstart touchmove touchend orientationchange throttledresize tap taphold swipe swipeleft swiperight scrollstart scrollstop".split(" "),function(b,c){a.fn[c]=function(a){return a?this.bind(c,a):this.trigger(c)};a.attrFn[c]=!0});var b=a.support.touch,e=b?"touchstart":"mousedown",f=b?"touchend":"mouseup",g=b?"touchmove":"mousemove";a.event.special.scrollstart={enabled:!0,setup:function(){function b(a,
|
||||
f){e=f;c(d,e?"scrollstart":"scrollstop",a)}var d=this,e,f;a(d).bind("touchmove scroll",function(c){a.event.special.scrollstart.enabled&&(e||b(c,!0),clearTimeout(f),f=setTimeout(function(){b(c,!1)},50))})}};a.event.special.tap={setup:function(){var b=this,d=a(b);d.bind("vmousedown",function(a){function e(){g=!1;clearTimeout(k);d.unbind("vclick",f).unbind("vmousecancel",e)}function f(a){e();p==a.target&&c(b,"tap",a)}if(a.which&&a.which!==1)return!1;var g=!0,p=a.target,k;d.bind("vmousecancel",e).bind("vclick",
|
||||
f);k=setTimeout(function(){g&&c(b,"taphold",a)},750)})}};a.event.special.swipe={setup:function(){var b=a(this);b.bind(e,function(c){function e(a){if(o){var b=a.originalEvent.touches?a.originalEvent.touches[0]:a;j={time:(new Date).getTime(),coords:[b.pageX,b.pageY]};Math.abs(o.coords[0]-j.coords[0])>10&&a.preventDefault()}}var m=c.originalEvent.touches?c.originalEvent.touches[0]:c,o={time:(new Date).getTime(),coords:[m.pageX,m.pageY],origin:a(c.target)},j;b.bind(g,e).one(f,function(){b.unbind(g,e);
|
||||
o&&j&&j.time-o.time<1E3&&Math.abs(o.coords[0]-j.coords[0])>30&&Math.abs(o.coords[1]-j.coords[1])<75&&o.origin.trigger("swipe").trigger(o.coords[0]>j.coords[0]?"swipeleft":"swiperight");o=j=d})})}};(function(a){function b(){var a=d();a!==e&&(e=a,c.trigger("orientationchange"))}var c=a(window),d,e;a.event.special.orientationchange={setup:function(){if(a.support.orientation)return!1;e=d();c.bind("throttledresize",b)},teardown:function(){if(a.support.orientation)return!1;c.unbind("throttledresize",b)},
|
||||
add:function(a){var b=a.handler;a.handler=function(a){a.orientation=d();return b.apply(this,arguments)}}};a.event.special.orientationchange.orientation=d=function(){var a=document.documentElement;return a&&a.clientWidth/a.clientHeight<1.1?"portrait":"landscape"}})(jQuery);(function(){a.event.special.throttledresize={setup:function(){a(this).bind("resize",b)},teardown:function(){a(this).unbind("resize",b)}};var b=function(){e=(new Date).getTime();f=e-c;f>=250?(c=e,a(this).trigger("throttledresize")):
|
||||
(d&&clearTimeout(d),d=setTimeout(b,250-f))},c=0,d,e,f})();a.each({scrollstop:"scrollstart",taphold:"tap",swipeleft:"swipe",swiperight:"swipe"},function(b,c){a.event.special[b]={setup:function(){a(this).bind(c,a.noop)}}})})(jQuery);
|
||||
(function(a,d,c){function b(a){a=a||location.href;return"#"+a.replace(/^[^#]*#?(.*)$/,"$1")}var e="hashchange",f=document,g,i=a.event.special,h=f.documentMode,l="on"+e in d&&(h===c||h>7);a.fn[e]=function(a){return a?this.bind(e,a):this.trigger(e)};a.fn[e].delay=50;i[e]=a.extend(i[e],{setup:function(){if(l)return!1;a(g.start)},teardown:function(){if(l)return!1;a(g.stop)}});g=function(){function g(){var c=b(),f=n(i);if(c!==i)q(i=c,f),a(d).trigger(e);else if(f!==i)location.href=location.href.replace(/#.*/,
|
||||
"")+f;j=setTimeout(g,a.fn[e].delay)}var h={},j,i=b(),k=function(a){return a},q=k,n=k;h.start=function(){j||g()};h.stop=function(){j&&clearTimeout(j);j=c};a.browser.msie&&!l&&function(){var c,d;h.start=function(){if(!c)d=(d=a.fn[e].src)&&d+b(),c=a('<iframe tabindex="-1" title="empty"/>').hide().one("load",function(){d||q(b());g()}).attr("src",d||"javascript:0").insertAfter("body")[0].contentWindow,f.onpropertychange=function(){try{if(event.propertyName==="title")c.document.title=f.title}catch(a){}}};
|
||||
h.stop=k;n=function(){return b(c.location.href)};q=function(b,d){var g=c.document,h=a.fn[e].domain;if(b!==d)g.title=f.title,g.open(),h&&g.write('<script>document.domain="'+h+'"<\/script>'),g.close(),c.location.hash=b}}();return h}()})(jQuery,this);
|
||||
(function(a){a.widget("mobile.page",a.mobile.widget,{options:{backBtnText:"Back",addBackBtn:!1,backBtnTheme:null,degradeInputs:{color:!1,date:!1,datetime:!1,"datetime-local":!1,email:!1,month:!1,number:!1,range:"number",search:!0,tel:!1,time:!1,url:!1,week:!1},keepNative:null},_create:function(){var d=this.element,c=this.options;this.keepNative=":jqmData(role='none'), :jqmData(role='nojs')"+(c.keepNative?", "+c.keepNative:"");this._trigger("beforeCreate")!==!1&&(d.find(":jqmData(role='page'), :jqmData(role='content')").andSelf().each(function(){a(this).addClass("ui-"+
|
||||
a(this).jqmData("role"))}),d.find(":jqmData(role='nojs')").addClass("ui-nojs"),d.find(":jqmData(role)").andSelf().each(function(){var b=a(this),e=b.jqmData("role"),f=b.jqmData("theme");if(e==="header"||e==="footer"){b.addClass("ui-bar-"+(f||b.parent(":jqmData(role='page')").jqmData("theme")||"a"));b.attr("role",e==="header"?"banner":"contentinfo");var f=b.children("a"),g=f.hasClass("ui-btn-left"),i=f.hasClass("ui-btn-right");if(!g)g=f.eq(0).not(".ui-btn-right").addClass("ui-btn-left").length;i||f.eq(1).addClass("ui-btn-right");
|
||||
c.addBackBtn&&e==="header"&&a(".ui-page").length>1&&d.jqmData("url")!==a.mobile.path.stripHash(location.hash)&&!g&&b.jqmData("backbtn")!==!1&&(f=a("<a href='#' class='ui-btn-left' data-"+a.mobile.ns+"rel='back' data-"+a.mobile.ns+"icon='arrow-l'>"+c.backBtnText+"</a>").prependTo(b),c.backBtnTheme&&f.attr("data-"+a.mobile.ns+"theme",c.backBtnTheme));b.children("h1, h2, h3, h4, h5, h6").addClass("ui-title").attr({tabindex:"0",role:"heading","aria-level":"1"})}else e==="content"?(f&&b.addClass("ui-body-"+
|
||||
f),b.attr("role","main")):e==="page"&&b.addClass("ui-body-"+(f||"c"));switch(e){case "header":case "footer":case "page":case "content":b.addClass("ui-"+e);break;case "collapsible":case "fieldcontain":case "navbar":case "listview":case "dialog":b[e]()}}),this._enhanceControls(),d.find(":jqmData(role='button'), .ui-bar > a, .ui-header > a, .ui-footer > a").not(".ui-btn").not(this.keepNative).buttonMarkup(),d.find(":jqmData(role='controlgroup')").controlgroup(),d.find("a:not(.ui-btn):not(.ui-link-inherit)").not(this.keepNative).addClass("ui-link"),
|
||||
d.fixHeaderFooter())},_typeAttributeRegex:/\s+type=["']?\w+['"]?/,_enhanceControls:function(){var d=this.options,c=this;this.element.find("input").not(this.keepNative).each(function(){var b=this.getAttribute("type"),e=d.degradeInputs[b]||"text";d.degradeInputs[b]&&a(this).replaceWith(a("<div>").html(a(this).clone()).html().replace(c._typeAttributeRegex,' type="'+e+'" data-'+a.mobile.ns+'type="'+b+'" '))});var b=this.element.find("input, textarea, select, button"),e=b.not(this.keepNative),b=b.filter("input[type=text]");
|
||||
b.length&&typeof b[0].autocorrect!=="undefined"&&b.each(function(){this.setAttribute("autocorrect","off");this.setAttribute("autocomplete","off")});e.filter("[type='radio'], [type='checkbox']").checkboxradio();e.filter("button, [type='button'], [type='submit'], [type='reset'], [type='image']").button();e.filter("input, textarea").not("[type='radio'], [type='checkbox'], [type='button'], [type='submit'], [type='reset'], [type='image'], [type='hidden']").textinput();e.filter("input, select").filter(":jqmData(role='slider'), :jqmData(type='range')").slider();
|
||||
e.filter("select:not(:jqmData(role='slider'))").selectmenu()}})})(jQuery);
|
||||
(function(a,d){a.extend(a.mobile,{ns:"",subPageUrlKey:"ui-page",nonHistorySelectors:"dialog",activePageClass:"ui-page-active",activeBtnClass:"ui-btn-active",ajaxEnabled:!0,useFastClick:!0,hashListeningEnabled:!0,defaultPageTransition:"slide",minScrollBack:screen.height/2,defaultDialogTransition:"pop",loadingMessage:"loading",pageLoadErrorMessage:"Error Loading Page",gradeA:function(){return a.support.mediaquery||a.mobile.browser.ie&&a.mobile.browser.ie>=7},keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,
|
||||
COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91},silentScroll:function(b){if(a.type(b)!=="number")b=a.mobile.defaultHomeScroll;a.event.special.scrollstart.enabled=!1;setTimeout(function(){d.scrollTo(0,b);a(document).trigger("silentscroll",
|
||||
{x:0,y:b})},20);setTimeout(function(){a.event.special.scrollstart.enabled=!0},150)},normalizeRegex:/-([a-z])/g,nsNormalize:function(b){if(b)return a.camelCase(a.mobile.ns+b)}});a.fn.jqmData=function(b,c){return this.data(b?a.mobile.nsNormalize(b):b,c)};a.jqmData=function(b,c,d){return a.data(b,a.mobile.nsNormalize(c),d)};a.fn.jqmRemoveData=function(b){return this.removeData(a.mobile.nsNormalize(b))};a.jqmRemoveData=function(b,c){return a.removeData(b,a.mobile.nsNormalize(c))};a.jqmHasData=function(b,
|
||||
c){return a.hasData(b,a.mobile.nsNormalize(c))};var c=a.find;a.find=function(b,d,f,g){b=b.replace(/:jqmData\(([^)]*)\)/g,"[data-"+(a.mobile.ns||"")+"$1]");return c.call(this,b,d,f,g)};a.extend(a.find,c);a.find.matches=function(b,c){return a.find(b,null,null,c)};a.find.matchesSelector=function(b,c){return a.find(c,null,null,[b]).length>0}})(jQuery,this);
|
||||
(function(a,d){function c(a){var b=a.jqmData("lastClicked");b&&b.length?b.focus():(b=a.find(".ui-title:eq(0)"),b.length?b.focus():a.find(z).eq(0).focus())}function b(b){q&&(!q.closest(".ui-page-active").length||b)&&q.removeClass(a.mobile.activeBtnClass);q=null}function e(){t=!1;y.length>0&&a.mobile.changePage.apply(null,y.pop())}function f(b,d,e,f){var h=a.support.scrollTop?o.scrollTop():!0,j=b.data("lastScroll")||a.mobile.defaultHomeScroll,i=g();h&&window.scrollTo(0,a.mobile.defaultHomeScroll);j<
|
||||
a.mobile.minScrollBack&&(j=0);d&&(d.height(i+h).jqmData("lastScroll",h).jqmData("lastClicked",q),d.data("page")._trigger("beforehide",null,{nextPage:b}));b.height(i+j).data("page")._trigger("beforeshow",null,{prevPage:d||a("")});a.mobile.hidePageLoadingMsg();e=(a.mobile.transitionHandlers[e||"none"]||a.mobile.defaultTransitionHandler)(e,f,b,d);e.done(function(){b.height("");j?(a.mobile.silentScroll(j),a(document).one("silentscroll",function(){c(b)})):c(b);d&&d.height("").data("page")._trigger("hide",
|
||||
null,{nextPage:b});b.data("page")._trigger("show",null,{prevPage:d||a("")})});return e}function g(){var b=jQuery.event.special.orientationchange.orientation()==="portrait",c=b?screen.availHeight:screen.availWidth,b=Math.max(b?480:320,a(window).height());return Math.min(c,b)}function i(){a("."+a.mobile.activePageClass).css("min-height",g())}function h(b,c){c&&b.attr("data-"+a.mobile.ns+"role",c);b.page()}function l(a){for(;a;){if(a.nodeName.toLowerCase()=="a")break;a=a.parentNode}return a}function m(b){var b=
|
||||
a(b).closest(".ui-page").jqmData("url"),c=s.hrefNoHash;if(!b||!k.isPath(b))b=c;return k.makeUrlAbsolute(b,c)}var o=a(window),j=a("html"),p=a("head"),k={urlParseRE:/^(((([^:\/#\?]+:)?(?:\/\/((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?]+)(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,parseUrl:function(a){if(typeof a==="object")return a;var a=k.urlParseRE.exec(a),b;a&&(b={href:a[0]||"",hrefNoHash:a[1]||"",hrefNoSearch:a[2]||"",domain:a[3]||"",protocol:a[4]||"",authority:a[5]||
|
||||
"",username:a[7]||"",password:a[8]||"",host:a[9]||"",hostname:a[10]||"",port:a[11]||"",pathname:a[12]||"",directory:a[13]||"",filename:a[14]||"",search:a[15]||"",hash:a[16]||""});return b||{}},makePathAbsolute:function(a,b){if(a&&a.charAt(0)==="/")return a;for(var a=a||"",c=(b=b?b.replace(/^\/|\/?[^\/]*$/g,""):"")?b.split("/"):[],d=a.split("/"),e=0;e<d.length;e++){var f=d[e];switch(f){case ".":break;case "..":c.length&&c.pop();break;default:c.push(f)}}return"/"+c.join("/")},isSameDomain:function(a,
|
||||
b){return k.parseUrl(a).domain===k.parseUrl(b).domain},isRelativeUrl:function(a){return k.parseUrl(a).protocol===""},isAbsoluteUrl:function(a){return k.parseUrl(a).protocol!==""},makeUrlAbsolute:function(a,b){if(!k.isRelativeUrl(a))return a;var c=k.parseUrl(a),d=k.parseUrl(b),e=c.protocol||d.protocol,f=c.authority||d.authority,g=c.pathname!=="",h=k.makePathAbsolute(c.pathname||d.filename,d.pathname);return e+"//"+f+h+(c.search||!g&&d.search||"")+c.hash},addSearchParams:function(b,c){var d=k.parseUrl(b),
|
||||
e=typeof c==="object"?a.param(c):c,f=d.search||"?";return d.hrefNoSearch+f+(f.charAt(f.length-1)!=="?"?"&":"")+e+(d.hash||"")},convertUrlToDataUrl:function(a){var b=k.parseUrl(a);if(k.isEmbeddedPage(b))return b.hash.replace(/^#/,"");else if(k.isSameDomain(b,s))return b.hrefNoHash.replace(s.domain,"");return a},get:function(a){if(a===d)a=location.hash;return k.stripHash(a).replace(/[^\/]*\.[^\/*]+$/,"")},getFilePath:function(b){var c="&"+a.mobile.subPageUrlKey;return b&&b.split(c)[0].split(v)[0]},
|
||||
set:function(a){location.hash=a},isPath:function(a){return/\//.test(a)},clean:function(a){return a.replace(s.domain,"")},stripHash:function(a){return a.replace(/^#/,"")},cleanHash:function(a){return k.stripHash(a.replace(/\?.*$/,"").replace(v,""))},isExternal:function(a){a=k.parseUrl(a);return a.protocol&&a.domain!==u.domain?!0:!1},hasProtocol:function(a){return/^(:?\w+:)/.test(a)},isEmbeddedPage:function(a){a=k.parseUrl(a);if(a.protocol!=="")return a.hash&&(a.hrefNoHash===u.hrefNoHash||B&&a.hrefNoHash===
|
||||
s.hrefNoHash);return/^#/.test(a.href)}},q=null,n={stack:[],activeIndex:0,getActive:function(){return n.stack[n.activeIndex]},getPrev:function(){return n.stack[n.activeIndex-1]},getNext:function(){return n.stack[n.activeIndex+1]},addNew:function(a,b,c,d){n.getNext()&&n.clearForward();n.stack.push({url:a,transition:b,title:c,page:d});n.activeIndex=n.stack.length-1},clearForward:function(){n.stack=n.stack.slice(0,n.activeIndex+1)},directHashChange:function(b){var c,e,f;a.each(n.stack,function(a,d){b.currentUrl===
|
||||
d.url&&(c=a<n.activeIndex,e=!c,f=a)});this.activeIndex=f!==d?f:this.activeIndex;c?b.isBack():e&&b.isForward()},ignoreNextHashChange:!1},z="[tabindex],a,button:visible,select:visible,input",y=[],t=!1,v="&ui-state=dialog",x=p.children("base"),u=k.parseUrl(location.href),s=x.length?k.parseUrl(k.makeUrlAbsolute(x.attr("href"),u.href)):u,B=u.hrefNoHash!==s.hrefNoHash,w=a.support.dynamicBaseTag?{element:x.length?x:a("<base>",{href:s.hrefNoHash}).prependTo(p),set:function(a){w.element.attr("href",k.makeUrlAbsolute(a,
|
||||
s))},reset:function(){w.element.attr("href",s.hrefNoHash)}}:d;a.fn.animationComplete=function(b){return a.support.cssTransitions?a(this).one("webkitAnimationEnd",b):(setTimeout(b,0),a(this))};a.mobile.updateHash=k.set;a.mobile.path=k;a.mobile.base=w;a.mobile.urlstack=n.stack;a.mobile.urlHistory=n;a.mobile.noneTransitionHandler=function(b,c,d,e){e&&e.removeClass(a.mobile.activePageClass);d.addClass(a.mobile.activePageClass);return a.Deferred().resolve(b,c,d,e).promise()};a.mobile.defaultTransitionHandler=
|
||||
a.mobile.noneTransitionHandler;a.mobile.transitionHandlers={none:a.mobile.defaultTransitionHandler};a.mobile.allowCrossDomainPages=!1;a.mobile.getDocumentUrl=function(b){return b?a.extend({},u):u.href};a.mobile.getDocumentBase=function(b){return b?a.extend({},s):s.href};a.mobile.loadPage=function(b,c){var e=a.Deferred(),f=a.extend({},a.mobile.loadPage.defaults,c),g=null,j=null,i=k.makeUrlAbsolute(b,s.hrefNoHash);if(f.data&&f.type==="get")i=k.addSearchParams(i,f.data),f.data=d;var n=k.getFilePath(i),
|
||||
q=k.convertUrlToDataUrl(i);f.pageContainer=f.pageContainer||a.mobile.pageContainer;g=f.pageContainer.children(":jqmData(url='"+q+"')");w&&w.reset();if(g.length){if(!f.reloadPage)return h(g,f.role),e.resolve(i,c,g),e.promise();j=g}f.showLoadMsg&&a.mobile.showPageLoadingMsg();a.ajax({url:n,type:f.type,data:f.data,dataType:"html",success:function(d){var l=a("<div></div>"),p=d.match(/<title[^>]*>([^<]*)/)&&RegExp.$1,o=RegExp("\\bdata-"+a.mobile.ns+"url=[\"']?([^\"'>]*)[\"']?");RegExp(".*(<[^>]+\\bdata-"+
|
||||
a.mobile.ns+"role=[\"']?page[\"']?[^>]*>).*").test(d)&&RegExp.$1&&o.test(RegExp.$1)&&RegExp.$1&&(b=n=k.getFilePath(RegExp.$1));w&&w.set(n);l.get(0).innerHTML=d;g=l.find(":jqmData(role='page'), :jqmData(role='dialog')").first();p&&!g.jqmData("title")&&g.jqmData("title",p);if(!a.support.dynamicBaseTag){var m=k.get(n);g.find("[src], link[href], a[rel='external'], :jqmData(ajax='false'), a[target]").each(function(){var b=a(this).is("[href]")?"href":a(this).is("[src]")?"src":"action",c=a(this).attr(b),
|
||||
c=c.replace(location.protocol+"//"+location.host+location.pathname,"");/^(\w+:|#|\/)/.test(c)||a(this).attr(b,m+c)})}g.attr("data-"+a.mobile.ns+"url",k.convertUrlToDataUrl(n)).appendTo(f.pageContainer);h(g,f.role);i.indexOf("&"+a.mobile.subPageUrlKey)>-1&&(g=f.pageContainer.children(":jqmData(url='"+q+"')"));f.showLoadMsg&&a.mobile.hidePageLoadingMsg();e.resolve(i,c,g,j)},error:function(){w&&w.set(k.get());f.showLoadMsg&&(a.mobile.hidePageLoadingMsg(),a("<div class='ui-loader ui-overlay-shadow ui-body-e ui-corner-all'><h1>"+
|
||||
a.mobile.pageLoadErrorMessage+"</h1></div>").css({display:"block",opacity:0.96,top:o.scrollTop()+100}).appendTo(f.pageContainer).delay(800).fadeOut(400,function(){a(this).remove()}));e.reject(i,c)}});return e.promise()};a.mobile.loadPage.defaults={type:"get",data:d,reloadPage:!1,role:d,showLoadMsg:!0,pageContainer:d};a.mobile.changePage=function(c,g){if(typeof g!=="object"){var i=null;if(typeof c==="object"&&c.url&&c.type)i={type:c.type,data:c.data,forcePageLoad:!0},c=c.url;var q=arguments.length;
|
||||
if(q>1){var l=["transition","reverse","changeHash","fromHashChange"],p;for(p=1;p<q;p++){var o=arguments[p];typeof o!=="undefined"&&(i=i||{},i[l[p-1]]=o)}}if(i)return a.mobile.changePage(c,i)}if(t)y.unshift(arguments);else{t=!0;var m=a.extend({},a.mobile.changePage.defaults,g);m.pageContainer=m.pageContainer||a.mobile.pageContainer;if(typeof c=="string")a.mobile.loadPage(c,m).done(function(b,c,d,e){t=!1;c.duplicateCachedPage=e;a.mobile.changePage(d,c)}).fail(function(){t=!1;b(!0);e();m.pageContainer.trigger("changepagefailed")});
|
||||
else{var s=m.pageContainer,i=a.mobile.activePage,q=c.jqmData("url");k.getFilePath(q);l=n.getActive();p=n.activeIndex===0;var x=0,o=document.title,u=m.role==="dialog"||c.jqmData("role")==="dialog";s.trigger("beforechangepage");if(i&&i[0]===c[0])t=!1,s.trigger("changepage");else{h(c,m.role);m.fromHashChange&&n.directHashChange({currentUrl:q,isBack:function(){x=-1},isForward:function(){x=1}});a(document.activeElement||"").add("input:focus, textarea:focus, select:focus").blur();u&&l&&(q=l.url+v);if(m.changeHash!==
|
||||
!1&&q)n.ignoreNextHashChange=!0,k.set(q);(u=c.jqmData("title")||c.children(":jqmData(role='header')").find(".ui-title").text())&&o==document.title&&(o=u);x||n.addNew(q,m.transition,o,c);document.title=n.getActive().title;a.mobile.activePage=c;m.transition=m.transition||(x&&!p?l.transition:d)||(m.role==="dialog"?a.mobile.defaultDialogTransition:a.mobile.defaultPageTransition);m.reverse=m.reverse||x<0;f(c,i,m.transition,m.reverse).done(function(){b();m.duplicateCachedPage&&m.duplicateCachedPage.remove();
|
||||
j.removeClass("ui-mobile-rendering");e();s.trigger("changepage")})}}}};a.mobile.changePage.defaults={transition:d,reverse:!1,changeHash:!0,fromHashChange:!1,role:d,duplicateCachedPage:d,pageContainer:d};a("form").live("submit",function(b){var c=a(this);if(a.mobile.ajaxEnabled&&!c.is(":jqmData(ajax='false')")){var d=c.attr("method"),e=k.makeUrlAbsolute(c.attr("action"),m(c)),f=c.attr("target");!k.isExternal(e)&&!f&&(a.mobile.changePage(e,{type:d.length&&d.toLowerCase()||"get",data:c.serialize(),transition:c.jqmData("transition"),
|
||||
direction:c.jqmData("direction"),reloadPage:!0}),b.preventDefault())}});a(document).bind("vclick",function(b){if((b=l(b.target))&&k.parseUrl(b.getAttribute("href")||"#").hash!=="#")a(b).closest(".ui-btn").not(".ui-disabled").addClass(a.mobile.activeBtnClass),a("."+a.mobile.activePageClass+" .ui-btn").not(b).blur()});a(document).bind(a.mobile.useFastClick?"vclick click":"click",function(c){var e=l(c.target);if(e){var f=a(e),g=function(){window.setTimeout(function(){b(!0)},200)};if(f.is(":jqmData(rel='back')"))return window.history.back(),
|
||||
!1;if(a.mobile.ajaxEnabled){var h=m(f),e=k.makeUrlAbsolute(f.attr("href")||"#",h);if(e.search("#")!=-1)if(e=e.replace(/[^#]*#/,""))e=k.isPath(e)?k.makeUrlAbsolute(e,h):k.makeUrlAbsolute("#"+e,u.hrefNoHash);else{c.preventDefault();return}var h=f.is("[rel='external']")||f.is(":jqmData(ajax='false')")||f.is("[target]"),i=a.mobile.allowCrossDomainPages&&u.protocol==="file:"&&e.search(/^https?:/)!=-1,h=h||k.isExternal(e)&&!i;q=f.closest(".ui-btn");h?g():(g=f.jqmData("transition"),h=(h=f.jqmData("direction"))&&
|
||||
h==="reverse"||f.jqmData("back"),f=f.attr("data-"+a.mobile.ns+"rel")||d,a.mobile.changePage(e,{transition:g,reverse:h,role:f}),c.preventDefault())}else g()}});o.bind("hashchange",function(){var b=k.stripHash(location.hash),c=a.mobile.urlHistory.stack.length===0?"none":d;if(!a.mobile.hashListeningEnabled||n.ignoreNextHashChange)n.ignoreNextHashChange=!1;else{if(n.stack.length>1&&b.indexOf(v)>-1)if(a.mobile.activePage.is(".ui-dialog")){var e=function(){b=a.mobile.urlHistory.getActive().page};n.directHashChange({currentUrl:b,
|
||||
isBack:e,isForward:e})}else{n.directHashChange({currentUrl:b,isBack:function(){window.history.back()},isForward:function(){window.history.forward()}});return}b?(b=typeof b==="string"&&!k.isPath(b)?"#"+b:b,a.mobile.changePage(b,{transition:c,changeHash:!1,fromHashChange:!0})):a.mobile.changePage(a.mobile.firstPage,{transition:c,changeHash:!1,fromHashChange:!0})}});a(document).bind("pageshow",i);a(window).bind("throttledresize",i)})(jQuery);
|
||||
(function(a){function d(c,b,d,f){var g=new a.Deferred,i=b?" reverse":"",h="ui-mobile-viewport-transitioning viewport-"+c;d.animationComplete(function(){d.add(f).removeClass("out in reverse "+c);f&&f.removeClass(a.mobile.activePageClass);d.parent().removeClass(h);g.resolve(c,b,d,f)});d.parent().addClass(h);f&&f.addClass(c+" out"+i);d.addClass(a.mobile.activePageClass+" "+c+" in"+i);return g.promise()}a.mobile.css3TransitionHandler=d;if(a.mobile.defaultTransitionHandler===a.mobile.noneTransitionHandler)a.mobile.defaultTransitionHandler=
|
||||
d})(jQuery,this);
|
||||
(function(a,d){a.fn.fixHeaderFooter=function(){if(!a.support.scrollTop)return this;return this.each(function(){var c=a(this);c.jqmData("fullscreen")&&c.addClass("ui-page-fullscreen");c.find(".ui-header:jqmData(position='fixed')").addClass("ui-header-fixed ui-fixed-inline fade");c.find(".ui-footer:jqmData(position='fixed')").addClass("ui-footer-fixed ui-fixed-inline fade")})};a.fixedToolbars=function(){function c(){!g&&f=="overlay"&&(i||a.fixedToolbars.hide(!0),a.fixedToolbars.startShowTimer())}function b(a){var b=
|
||||
0;if(a)for(var c=a.offsetParent,d=document.body,b=a.offsetTop;a&&a!=d;){b+=a.scrollTop||0;if(a==c)b+=c.offsetTop,c=a.offsetParent;a=a.parentNode}return b}function e(c){var d=a(window).scrollTop(),e=b(c[0]),f=c.css("top")=="auto"?0:parseFloat(c.css("top")),g=window.innerHeight,h=c.outerHeight(),i=c.parents(".ui-page:not(.ui-page-fullscreen)").length;return c.is(".ui-header-fixed")?(f=d-e+f,f<e&&(f=0),c.css("top",i?f:d)):c.css("top",i?d+g-h-(e-f):d+g-h)}if(a.support.scrollTop){var f="inline",g=!1,i,
|
||||
h,l=null,m=!1,o=!0;a(function(){a(document).bind("vmousedown",function(){o&&(l=f)}).bind("vclick",function(b){o&&!a(b.target).closest("a,input,textarea,select,button,label,.ui-header-fixed,.ui-footer-fixed").length&&!m&&(a.fixedToolbars.toggle(l),l=null)}).bind("silentscroll",c);(a(document).scrollTop()==0?a(window):a(document)).bind("scrollstart",function(){m=!0;l==null&&(l=f);var b=l=="overlay";if(g=b||!!i)a.fixedToolbars.clearShowTimer(),b&&a.fixedToolbars.hide(!0)}).bind("scrollstop",function(b){a(b.target).closest("a,input,textarea,select,button,label,.ui-header-fixed,.ui-footer-fixed").length||
|
||||
(m=!1,g&&(g=!1,a.fixedToolbars.startShowTimer()),l=null)});a(window).bind("resize",c)});a(".ui-page").live("pagebeforeshow",function(b,c){var d=a(b.target).find(":jqmData(role='footer')"),f=d.data("id"),g=c.prevPage,g=g&&g.find(":jqmData(role='footer')"),g=g.length&&g.jqmData("id")===f;f&&g&&(h=d,e(h.removeClass("fade in out").appendTo(a.mobile.pageContainer)))});a(".ui-page").live("pageshow",function(){var b=a(this);h&&h.length&&setTimeout(function(){e(h.appendTo(b).addClass("fade"));h=null},500);
|
||||
a.fixedToolbars.show(!0,this)});a(".ui-collapsible-contain").live("collapse expand",c);return{show:function(c,d){a.fixedToolbars.clearShowTimer();f="overlay";return(d?a(d):a.mobile.activePage?a.mobile.activePage:a(".ui-page-active")).children(".ui-header-fixed:first, .ui-footer-fixed:not(.ui-footer-duplicate):last").each(function(){var d=a(this),f=a(window).scrollTop(),g=b(d[0]),h=window.innerHeight,i=d.outerHeight(),f=d.is(".ui-header-fixed")&&f<=g+i||d.is(".ui-footer-fixed")&&g<=f+h;d.addClass("ui-fixed-overlay").removeClass("ui-fixed-inline");
|
||||
!f&&!c&&d.animationComplete(function(){d.removeClass("in")}).addClass("in");e(d)})},hide:function(b){f="inline";return(a.mobile.activePage?a.mobile.activePage:a(".ui-page-active")).children(".ui-header-fixed:first, .ui-footer-fixed:not(.ui-footer-duplicate):last").each(function(){var c=a(this),d=c.css("top"),d=d=="auto"?0:parseFloat(d);c.addClass("ui-fixed-inline").removeClass("ui-fixed-overlay");if(d<0||c.is(".ui-header-fixed")&&d!=0)b?c.css("top",0):c.css("top")!=="auto"&&parseFloat(c.css("top"))!==
|
||||
0&&c.animationComplete(function(){c.removeClass("out reverse");c.css("top",0)}).addClass("out reverse")})},startShowTimer:function(){a.fixedToolbars.clearShowTimer();var b=a.makeArray(arguments);i=setTimeout(function(){i=d;a.fixedToolbars.show.apply(null,b)},100)},clearShowTimer:function(){i&&clearTimeout(i);i=d},toggle:function(b){b&&(f=b);return f=="overlay"?a.fixedToolbars.hide():a.fixedToolbars.show()},setTouchToggleEnabled:function(a){o=a}}}}()})(jQuery);
|
||||
(function(a,d){a.widget("mobile.checkboxradio",a.mobile.widget,{options:{theme:null},_create:function(){var c=this,b=this.element,e=b.closest("form,fieldset,:jqmData(role='page')").find("label").filter('[for="'+b[0].id+'"]'),f=b.attr("type"),g="ui-icon-"+f+"-off";if(!(f!="checkbox"&&f!="radio")){a.extend(this,{label:e,inputtype:f,checkedicon:"ui-icon-"+f+"-on",uncheckedicon:g});if(!this.options.theme)this.options.theme=this.element.jqmData("theme");e.buttonMarkup({theme:this.options.theme,icon:this.element.parents(":jqmData(type='horizontal')").length?
|
||||
d:g,shadow:!1});b.add(e).wrapAll("<div class='ui-"+f+"'></div>");e.bind({vmouseover:function(){if(a(this).parent().is(".ui-disabled"))return!1},vclick:function(a){if(b.is(":disabled"))a.preventDefault();else return c._cacheVals(),b.prop("checked",f==="radio"&&!0||!b.prop("checked")),c._getInputSet().not(b).prop("checked",!1),c._updateAll(),!1}});b.bind({vmousedown:function(){this._cacheVals()},vclick:function(){a(this).is(":checked")?(a(this).prop("checked",!0),c._getInputSet().not(a(this)).prop("checked",
|
||||
!1)):a(this).prop("checked",!1);c._updateAll()},focus:function(){e.addClass("ui-focus")},blur:function(){e.removeClass("ui-focus")}});this.refresh()}},_cacheVals:function(){this._getInputSet().each(function(){a(this).jqmData("cacheVal",a(this).is(":checked"))})},_getInputSet:function(){return this.element.closest("form,fieldset,:jqmData(role='page')").find("input[name='"+this.element.attr("name")+"'][type='"+this.inputtype+"']")},_updateAll:function(){var c=this;this._getInputSet().each(function(){(a(this).is(":checked")||
|
||||
c.inputtype==="checkbox")&&a(this).trigger("change")}).checkboxradio("refresh")},refresh:function(){var c=this.element,b=this.label,d=b.find(".ui-icon");a(c[0]).prop("checked")?(b.addClass(a.mobile.activeBtnClass),d.addClass(this.checkedicon).removeClass(this.uncheckedicon)):(b.removeClass(a.mobile.activeBtnClass),d.removeClass(this.checkedicon).addClass(this.uncheckedicon));c.is(":disabled")?this.disable():this.enable()},disable:function(){this.element.prop("disabled",!0).parent().addClass("ui-disabled")},
|
||||
enable:function(){this.element.prop("disabled",!1).parent().removeClass("ui-disabled")}})})(jQuery);
|
||||
(function(a){a.widget("mobile.textinput",a.mobile.widget,{options:{theme:null},_create:function(){var h;var d=this.element,c=this.options,b=c.theme;b||(b=this.element.closest("[class*='ui-bar-'],[class*='ui-body-']"),h=(b=b.length&&/ui-(bar|body)-([a-z])/.exec(b.attr("class")))&&b[2]||"c",b=h);b=" ui-body-"+b;a('label[for="'+d.attr("id")+'"]').addClass("ui-input-text");d.addClass("ui-input-text ui-body-"+c.theme);var e=d;if(d.is("[type='search'],:jqmData(type='search')")){var e=d.wrap('<div class="ui-input-search ui-shadow-inset ui-btn-corner-all ui-btn-shadow ui-icon-searchfield'+
|
||||
b+'"></div>').parent(),f=a('<a href="#" class="ui-input-clear" title="clear text">clear text</a>').tap(function(a){d.val("").focus();d.trigger("change");f.addClass("ui-input-clear-hidden");a.preventDefault()}).appendTo(e).buttonMarkup({icon:"delete",iconpos:"notext",corners:!0,shadow:!0}),c=function(){d.val()==""?f.addClass("ui-input-clear-hidden"):f.removeClass("ui-input-clear-hidden")};c();d.keyup(c);d.focus(c)}else d.addClass("ui-corner-all ui-shadow-inset"+b);d.focus(function(){e.addClass("ui-focus")}).blur(function(){e.removeClass("ui-focus")});
|
||||
if(d.is("textarea")){var g=function(){var a=d[0].scrollHeight;d[0].clientHeight<a&&d.css({height:a+15})},i;d.keyup(function(){clearTimeout(i);i=setTimeout(g,100)})}},disable:function(){(this.element.attr("disabled",!0).is("[type='search'],:jqmData(type='search')")?this.element.parent():this.element).addClass("ui-disabled")},enable:function(){(this.element.attr("disabled",!1).is("[type='search'],:jqmData(type='search')")?this.element.parent():this.element).removeClass("ui-disabled")}})})(jQuery);
|
||||
|
||||
|
||||
(function(a){a.widget("mobile.selectmenu",a.mobile.widget,{
|
||||
options:{
|
||||
theme:null,
|
||||
disabled:!1,
|
||||
icon:"arrow-d",
|
||||
iconpos:"right",
|
||||
inline:null,
|
||||
corners:!0,shadow:!0,
|
||||
iconshadow:!0,
|
||||
menuPageTheme:"b",
|
||||
overlayTheme:"a",
|
||||
hidePlaceholderMenuItems:!0,
|
||||
closeText:"Close",
|
||||
nativeMenu:!0
|
||||
},
|
||||
_create:function(){
|
||||
var d=this,
|
||||
c=this.options,
|
||||
b=this.element.wrap("<div class='ui-select'>"),
|
||||
e=b.attr("id"),
|
||||
f=a('label[for="'+e+'"]').addClass("ui-select"),
|
||||
g=b[0].selectedIndex==-1?0:b[0].selectedIndex,
|
||||
i=(d.options.nativeMenu?a("<div/>"):a("<a>",{
|
||||
href:"#",
|
||||
role:"button",
|
||||
id:m,
|
||||
"aria-haspopup":"true",
|
||||
"aria-owns":o
|
||||
})).text(a(b[0].options.item(g)).text()).insertBefore(b).buttonMarkup({
|
||||
theme:c.theme,
|
||||
icon:c.icon,
|
||||
iconpos:c.iconpos,
|
||||
inline:c.inline,
|
||||
corners:c.corners,
|
||||
shadow:c.shadow,
|
||||
iconshadow:c.iconshadow
|
||||
}),
|
||||
h=d.isMultiple=b[0].multiple;
|
||||
c.nativeMenu&&window.opera&&window.opera.version&&b.addClass("ui-select-nativeonly");
|
||||
if(!c.nativeMenu){
|
||||
var l=b.find("option"),
|
||||
m=e+"-button",
|
||||
o=e+"-menu",
|
||||
j=b.closest(".ui-page"),
|
||||
g=/ui-btn-up-([a-z])/.exec(i.attr("class"))[1],
|
||||
p=a("<div data-"+a.mobile.ns+"role='dialog' data-"+a.mobile.ns+"theme='"+c.menuPageTheme+"'><div data-"+a.mobile.ns+"role='header'><div class='ui-title'>"+f.text()+"</div></div><div data-"+a.mobile.ns+"role='content'></div></div>").appendTo(a.mobile.pageContainer).page(),k=p.find(".ui-content");p.find(".ui-header a");var q=a("<div>",{"class":"ui-selectmenu-screen ui-screen-hidden"}).appendTo(j),n=a("<div>",{"class":"ui-selectmenu ui-selectmenu-hidden ui-overlay-shadow ui-corner-all pop ui-body-"+c.overlayTheme}).insertAfter(q),z=a("<ul>",{"class":"ui-selectmenu-list",id:o,role:"listbox","aria-labelledby":m}).attr("data-"+a.mobile.ns+"theme",g).appendTo(n),y=a("<div>",{"class":"ui-header ui-bar-"+g}).prependTo(n),t=a("<h1>",{"class":"ui-title"}).appendTo(y),v=a("<a>",{text:c.closeText,href:"#","class":"ui-btn-left"}).attr("data-"+a.mobile.ns+"iconpos","notext").attr("data-"+a.mobile.ns+"icon","delete").appendTo(y).buttonMarkup()}if(h)d.buttonCount=a("<span>").addClass("ui-li-count ui-btn-up-c ui-btn-corner-all").hide().appendTo(i);c.disabled&&this.disable();b.change(function(){d.refresh()});a.extend(d,{select:b,optionElems:l,selectID:e,label:f,buttonId:m,menuId:o,thisPage:j,button:i,menuPage:p,menuPageContent:k,screen:q,listbox:n,list:z,menuType:void 0,header:y,headerClose:v,headerTitle:t,placeholder:""});
|
||||
c.nativeMenu?b.appendTo(i).bind("vmousedown",function(){
|
||||
i.addClass(a.mobile.activeBtnClass)
|
||||
}).bind("focus vmouseover",function(){
|
||||
i.trigger("vmouseover")
|
||||
}).bind("vmousemove",function(){
|
||||
i.removeClass(a.mobile.activeBtnClass)
|
||||
}).bind("change blur vmouseout",function(){
|
||||
i.trigger("vmouseout").removeClass(a.mobile.activeBtnClass)
|
||||
}):(d.refresh(),b.attr("tabindex","-1").focus(function(){
|
||||
a(this).blur();i.focus()
|
||||
}),
|
||||
i.bind("vclick keydown",function(b){
|
||||
if(b.type=="vclick"||b.keyCode&&(b.keyCode===a.mobile.keyCode.ENTER||b.keyCode===a.mobile.keyCode.SPACE))
|
||||
d.open(),b.preventDefault()
|
||||
}),
|
||||
z.attr("role","listbox").delegate(".ui-li>a","focusin",function(){
|
||||
a(this).attr("tabindex","0")
|
||||
}).delegate(".ui-li>a","focusout",function(){
|
||||
a(this).attr("tabindex","-1")
|
||||
}).delegate("li:not(.ui-disabled, .ui-li-divider)","vclick",function(c){
|
||||
var e=b[0].selectedIndex,
|
||||
f=z.find("li:not(.ui-li-divider)").index(this),
|
||||
g=d.optionElems.eq(f)[0];
|
||||
g.selected=h?!g.selected:!0;
|
||||
h&&a(this).find(".ui-icon").toggleClass("ui-icon-checkbox-on",g.selected).toggleClass("ui-icon-checkbox-off",!g.selected);
|
||||
(h||e!==f)&&b.trigger("change");
|
||||
h||d.close();
|
||||
c.preventDefault()
|
||||
}).keydown(function(b){
|
||||
var c=a(b.target),
|
||||
d=c.closest("li");
|
||||
switch(b.keyCode){
|
||||
case 38:
|
||||
return b=d.prev(),b.length&&(c.blur().attr("tabindex","-1"),b.find("a").first().focus()),!1;
|
||||
case 40:
|
||||
return b=d.next(),b.length&&(c.blur().attr("tabindex","-1"),b.find("a").first().focus()),!1;
|
||||
case 13:case 32:
|
||||
return c.trigger("vclick"),!1
|
||||
}
|
||||
}),
|
||||
q.bind("vclick",function(){
|
||||
d.close()
|
||||
}),
|
||||
d.headerClose.click(function(){
|
||||
if(d.menuType=="overlay")
|
||||
return d.close(),!1
|
||||
})
|
||||
)},
|
||||
_buildList:function(){
|
||||
var d=this,
|
||||
c=this.options,
|
||||
b=this.placeholder,
|
||||
e=[],
|
||||
f=[],
|
||||
g=d.isMultiple?"checkbox-off":"false";
|
||||
d.list.empty().filter(".ui-listview").listview("destroy");
|
||||
d.select.find("option").each(function(){
|
||||
var i=a(this),
|
||||
h=i.parent(),
|
||||
l=i.text(),
|
||||
m="<a href='#'>"+l+"</a>",
|
||||
o=[],
|
||||
j=[];
|
||||
h.is("optgroup")&&(h=h.attr("label"),a.inArray(h,e)===-1&&(f.push("<li data-"+a.mobile.ns+"role='list-divider'>"+h+"</li>"),e.push(h)));
|
||||
if(!this.getAttribute("value")||l.length==0||i.jqmData("placeholder"))
|
||||
c.hidePlaceholderMenuItems&&o.push("ui-selectmenu-placeholder"),b=d.placeholder=l;
|
||||
this.disabled&&(o.push("ui-disabled"),j.push("aria-disabled='true'"));
|
||||
f.push("<li data-"+a.mobile.ns+"icon='"+g+"' class='"+o.join(" ")+"' "+j.join(" ")+">"+m+"</li>")
|
||||
});
|
||||
d.list.html(f.join(" "));
|
||||
d.list.find("li").attr({role:"option",tabindex:"-1"}).first().attr("tabindex","0");
|
||||
this.isMultiple||this.headerClose.hide();
|
||||
!this.isMultiple&&!b.length?this.header.hide():this.headerTitle.text(this.placeholder);
|
||||
d.list.listview()
|
||||
},
|
||||
refresh:function(d){
|
||||
var c=this,
|
||||
b=this.element,
|
||||
e=this.isMultiple,
|
||||
f=this.optionElems=b.find("option"),
|
||||
g=f.filter(":selected"),
|
||||
i=g.map(function(){
|
||||
return f.index(this)
|
||||
}).get();
|
||||
!c.options.nativeMenu&&(d||b[0].options.length!=c.list.find("li").length)&&c._buildList();
|
||||
c.button.find(".ui-btn-text").text(function(){
|
||||
if(!e)return g.text();
|
||||
return g.length?g.map(function(){
|
||||
return a(this).text()
|
||||
}).get().join(", "):c.placeholder
|
||||
});
|
||||
e&&c.buttonCount[g.length>1?"show":"hide"]().text(g.length);
|
||||
c.options.nativeMenu||c.list.find("li:not(.ui-li-divider)").removeClass(a.mobile.activeBtnClass).attr("aria-selected",!1).each(function(b){
|
||||
a.inArray(b,i)>-1&&(b=a(this).addClass(a.mobile.activeBtnClass),
|
||||
b.find("a").attr("aria-selected",!0),
|
||||
e&&b.find(".ui-icon").removeClass("ui-icon-checkbox-off").addClass("ui-icon-checkbox-on")
|
||||
)
|
||||
})
|
||||
},
|
||||
open:function(){
|
||||
function d(){
|
||||
c.list.find(".ui-btn-active").focus()
|
||||
}
|
||||
if(!this.options.disabled&&!this.options.nativeMenu){
|
||||
var c=this,
|
||||
b=c.list.parent().outerHeight(),
|
||||
e=c.list.parent().outerWidth(),
|
||||
f=a(window).scrollTop(),
|
||||
g=c.button.offset().top,
|
||||
i=window.innerHeight,
|
||||
h=window.innerWidth;
|
||||
c.button.addClass(a.mobile.activeBtnClass);
|
||||
setTimeout(function(){
|
||||
c.button.removeClass(a.mobile.activeBtnClass)
|
||||
},300);
|
||||
if(b>i-80||!a.support.scrollTop){
|
||||
if(f==0&&g>i)
|
||||
c.thisPage.one("pagehide",function(){
|
||||
a(this).jqmData("lastScroll",g)
|
||||
});
|
||||
c.menuPage.one("pageshow",function(){
|
||||
a(window).one("silentscroll",function(){d()})
|
||||
});
|
||||
c.menuType="page";
|
||||
c.menuPageContent.append(c.list);
|
||||
a.mobile.changePage(c.menuPage,{transition:"pop"})
|
||||
}else{
|
||||
c.menuType="overlay";
|
||||
c.screen.height(a(document).height()).removeClass("ui-screen-hidden");
|
||||
var l=g-f,m=f+i-g,o=b/2,j=parseFloat(c.list.parent().css("max-width")),b=l>b/2&&m>b/2?g+c.button.outerHeight()/2-o:l>m?f+i-b-30:f+30;e<j?j=(h-e)/2:(j=c.button.offset().left+c.button.outerWidth()/2-e/2,j<30?j=30:j+e>h&&(j=h-e-30));
|
||||
c.listbox.append(c.list).removeClass("ui-selectmenu-hidden").css({top:b,left:j}).addClass("in");d()
|
||||
}
|
||||
setTimeout(function(){
|
||||
c.isOpen=!0
|
||||
},400)
|
||||
}
|
||||
},
|
||||
close:function(){
|
||||
function a(){
|
||||
setTimeout(function(){
|
||||
c.button.focus()
|
||||
},40);
|
||||
c.listbox.removeAttr("style").append(c.list)
|
||||
}
|
||||
if(!this.options.disabled&&this.isOpen&&!this.options.nativeMenu){
|
||||
var c=this;
|
||||
c.menuType=="page"?(c.menuPage.one("pagehide",a),window.history.back()):(c.screen.addClass("ui-screen-hidden"),c.listbox.addClass("ui-selectmenu-hidden").removeAttr("style").removeClass("in"),a());this.isOpen=!1
|
||||
}
|
||||
},
|
||||
disable:function(){
|
||||
this.element.attr("disabled",!0);
|
||||
this.button.addClass("ui-disabled").attr("aria-disabled",!0);return this._setOption("disabled",!0)
|
||||
},
|
||||
enable:function(){
|
||||
this.element.attr("disabled",!1);
|
||||
this.button.removeClass("ui-disabled").attr("aria-disabled",!1);
|
||||
return this._setOption("disabled",!1)
|
||||
}
|
||||
})})(jQuery);
|
||||
(function(a){function d(b){for(;b;){var c=a(b);if(c.hasClass("ui-btn")&&!c.hasClass("ui-disabled"))break;b=b.parentNode}return b}a.fn.buttonMarkup=function(b){return this.each(function(){var d=a(this),f=a.extend({},a.fn.buttonMarkup.defaults,d.jqmData(),b),g,i="ui-btn-inner",h;c&&c();if(!f.theme)g=d.closest("[class*='ui-bar-'],[class*='ui-body-']"),f.theme=g.length?/ui-(bar|body)-([a-z])/.exec(g.attr("class"))[2]:"c";g="ui-btn ui-btn-up-"+f.theme;f.inline&&(g+=" ui-btn-inline");if(f.icon)f.icon="ui-icon-"+
|
||||
f.icon,f.iconpos=f.iconpos||"left",h="ui-icon "+f.icon,f.shadow&&(h+=" ui-icon-shadow");f.iconpos&&(g+=" ui-btn-icon-"+f.iconpos,f.iconpos=="notext"&&!d.attr("title")&&d.attr("title",d.text()));f.corners&&(g+=" ui-btn-corner-all",i+=" ui-btn-corner-all");f.shadow&&(g+=" ui-shadow");d.attr("data-"+a.mobile.ns+"theme",f.theme).addClass(g);f=("<D class='"+i+"'><D class='ui-btn-text'></D>"+(f.icon?"<span class='"+h+"'></span>":"")+"</D>").replace(/D/g,f.wrapperEls);d.wrapInner(f)})};a.fn.buttonMarkup.defaults=
|
||||
{corners:!0,shadow:!0,iconshadow:!0,wrapperEls:"span"};var c=function(){a(document).bind({vmousedown:function(b){if(b=d(b.target)){var b=a(b),c=b.attr("data-"+a.mobile.ns+"theme");b.removeClass("ui-btn-up-"+c).addClass("ui-btn-down-"+c)}},"vmousecancel vmouseup":function(b){if(b=d(b.target)){var b=a(b),c=b.attr("data-"+a.mobile.ns+"theme");b.removeClass("ui-btn-down-"+c).addClass("ui-btn-up-"+c)}},"vmouseover focus":function(b){if(b=d(b.target)){var b=a(b),c=b.attr("data-"+a.mobile.ns+"theme");b.removeClass("ui-btn-up-"+
|
||||
c).addClass("ui-btn-hover-"+c)}},"vmouseout blur":function(b){if(b=d(b.target)){var b=a(b),c=b.attr("data-"+a.mobile.ns+"theme");b.removeClass("ui-btn-hover-"+c).addClass("ui-btn-up-"+c)}}});c=null}})(jQuery);
|
||||
(function(a){a.widget("mobile.button",a.mobile.widget,{options:{theme:null,icon:null,iconpos:null,inline:null,corners:!0,shadow:!0,iconshadow:!0},_create:function(){var d=this.element,c=this.options;this.button=a("<div></div>").text(d.text()||d.val()).buttonMarkup({theme:c.theme,icon:c.icon,iconpos:c.iconpos,inline:c.inline,corners:c.corners,shadow:c.shadow,iconshadow:c.iconshadow}).insertBefore(d).append(d.addClass("ui-btn-hidden"));c=d.attr("type");c!=="button"&&c!=="reset"&&d.bind("vclick",function(){var b=
|
||||
a("<input>",{type:"hidden",name:d.attr("name"),value:d.attr("value")}).insertBefore(d);a(document).submit(function(){b.remove()})});this.refresh()},enable:function(){this.element.attr("disabled",!1);this.button.removeClass("ui-disabled").attr("aria-disabled",!1);return this._setOption("disabled",!1)},disable:function(){this.element.attr("disabled",!0);this.button.addClass("ui-disabled").attr("aria-disabled",!0);return this._setOption("disabled",!0)},refresh:function(){this.element.attr("disabled")?
|
||||
this.disable():this.enable()}})})(jQuery);
|
||||
|
||||
|
||||
(function(a){a.widget("mobile.slider",a.mobile.widget,{options:{theme:null,trackTheme:null,disabled:!1},_create:function(){var d=this,c=this.element,b=c.parents("[class*=ui-bar-],[class*=ui-body-]").eq(0),b=b.length?b.attr("class").match(/ui-(bar|body)-([a-z])/)[2]:"c",e=this.options.theme?this.options.theme:b,f=this.options.trackTheme?this.options.trackTheme:b,g=c[0].nodeName.toLowerCase(),b=g=="select"?"ui-slider-switch":"",i=c.attr("id"),h=i+"-label",i=a('[for="'+i+'"]').attr("id",h),l=function(){return g==
|
||||
"input"?parseFloat(c.val()):c[0].selectedIndex},m=g=="input"?parseFloat(c.attr("min")):0,o=g=="input"?parseFloat(c.attr("max")):c.find("option").length-1,j=window.parseFloat(c.attr("step")||1),p=a('<div class="ui-slider '+b+" ui-btn-down-"+f+' ui-btn-corner-all" role="application"></div>'),k=a('<a href="#" class="ui-slider-handle"></a>').appendTo(p).buttonMarkup({corners:!0,theme:e,shadow:!0}).attr({role:"slider","aria-valuemin":m,"aria-valuemax":o,"aria-valuenow":l(),"aria-valuetext":l(),title:l(),
|
||||
"aria-labelledby":h});a.extend(this,{slider:p,handle:k,dragging:!1,beforeStart:null});g=="select"&&(p.wrapInner('<div class="ui-slider-inneroffset"></div>'),c.find("option"),c.find("option").each(function(b){var c=b==0?"b":"a",d=b==0?"right":"left",b=b==0?" ui-btn-down-"+f:" ui-btn-active";a('<div class="ui-slider-labelbg ui-slider-labelbg-'+c+b+" ui-btn-corner-"+d+'"></div>').prependTo(p);a('<span class="ui-slider-label ui-slider-label-'+c+b+" ui-btn-corner-"+d+'" role="img">'+a(this).text()+"</span>").prependTo(k)}));
|
||||
i.addClass("ui-slider");c.addClass(g=="input"?"ui-slider-input":"ui-slider-switch").change(function(){d.refresh(l(),!0)}).keyup(function(){d.refresh(l(),!0,!0)}).blur(function(){d.refresh(l(),!0)});a(document).bind("vmousemove",function(a){if(d.dragging)return d.refresh(a),!1});p.bind("vmousedown",function(a){d.dragging=!0;if(g==="select")d.beforeStart=c[0].selectedIndex;d.refresh(a);return!1});p.add(document).bind("vmouseup",function(){if(d.dragging){d.dragging=!1;if(g==="select"){d.beforeStart===
|
||||
c[0].selectedIndex&&d.refresh(d.beforeStart===0?1:0);var a=l(),a=Math.round(a/(o-m)*100);k.addClass("ui-slider-handle-snapping").css("left",a+"%").animationComplete(function(){k.removeClass("ui-slider-handle-snapping")})}return!1}});p.insertAfter(c);this.handle.bind("vmousedown",function(){a(this).focus()}).bind("vclick",!1);this.handle.bind("keydown",function(b){var c=l();if(!d.options.disabled){switch(b.keyCode){case a.mobile.keyCode.HOME:case a.mobile.keyCode.END:case a.mobile.keyCode.PAGE_UP:case a.mobile.keyCode.PAGE_DOWN:case a.mobile.keyCode.UP:case a.mobile.keyCode.RIGHT:case a.mobile.keyCode.DOWN:case a.mobile.keyCode.LEFT:if(b.preventDefault(),
|
||||
!d._keySliding)d._keySliding=!0,a(this).addClass("ui-state-active")}switch(b.keyCode){case a.mobile.keyCode.HOME:d.refresh(m);break;case a.mobile.keyCode.END:d.refresh(o);break;case a.mobile.keyCode.PAGE_UP:case a.mobile.keyCode.UP:case a.mobile.keyCode.RIGHT:d.refresh(c+j);break;case a.mobile.keyCode.PAGE_DOWN:case a.mobile.keyCode.DOWN:case a.mobile.keyCode.LEFT:d.refresh(c-j)}}}).keyup(function(){if(d._keySliding)d._keySliding=!1,a(this).removeClass("ui-state-active")});this.refresh()},refresh:function(a,
|
||||
c,b){if(!this.options.disabled){var e=this.element,f=e[0].nodeName.toLowerCase(),g=f==="input"?parseFloat(e.attr("min")):0,i=f==="input"?parseFloat(e.attr("max")):e.find("option").length-1;if(typeof a==="object"){if(!this.dragging||a.pageX<this.slider.offset().left-8||a.pageX>this.slider.offset().left+this.slider.width()+8)return;a=Math.round((a.pageX-this.slider.offset().left)/this.slider.width()*100)}else a==null&&(a=f==="input"?parseFloat(e.val()):e[0].selectedIndex),a=(parseFloat(a)-g)/(i-g)*
|
||||
100;if(!isNaN(a)){a<0&&(a=0);a>100&&(a=100);var h=Math.round(a/100*(i-g))+g;h<g&&(h=g);h>i&&(h=i);this.handle.css("left",a+"%");this.handle.attr({"aria-valuenow":f==="input"?h:e.find("option").eq(h).attr("value"),"aria-valuetext":f==="input"?h:e.find("option").eq(h).text(),title:h});f==="select"&&(h===0?this.slider.addClass("ui-slider-switch-a").removeClass("ui-slider-switch-b"):this.slider.addClass("ui-slider-switch-b").removeClass("ui-slider-switch-a"));if(!b)f==="input"?e.val(h):e[0].selectedIndex=
|
||||
h,c||e.trigger("change")}}},enable:function(){this.element.attr("disabled",!1);this.slider.removeClass("ui-disabled").attr("aria-disabled",!1);return this._setOption("disabled",!1)},disable:function(){this.element.attr("disabled",!0);this.slider.addClass("ui-disabled").attr("aria-disabled",!0);return this._setOption("disabled",!0)}})})(jQuery);
|
||||
(function(a){a.widget("mobile.collapsible",a.mobile.widget,{options:{expandCueText:" click to expand contents",collapseCueText:" click to collapse contents",collapsed:!1,heading:">:header,>legend",theme:null,iconTheme:"d"},_create:function(){var d=this.element,c=this.options,b=d.addClass("ui-collapsible-contain"),e=d.find(c.heading).eq(0),f=b.wrapInner('<div class="ui-collapsible-content"></div>').find(".ui-collapsible-content"),d=d.closest(":jqmData(role='collapsible-set')").addClass("ui-collapsible-set");
|
||||
e.is("legend")&&(e=a('<div role="heading">'+e.html()+"</div>").insertBefore(e),e.next().remove());e.insertBefore(f).addClass("ui-collapsible-heading").append('<span class="ui-collapsible-heading-status"></span>').wrapInner('<a href="#" class="ui-collapsible-heading-toggle"></a>').find("a:eq(0)").buttonMarkup({shadow:!d.length,corners:!1,iconPos:"left",icon:"plus",theme:c.theme}).find(".ui-icon").removeAttr("class").buttonMarkup({shadow:!0,corners:!0,iconPos:"notext",icon:"plus",theme:c.iconTheme});
|
||||
d.length?b.jqmData("collapsible-last")&&e.find("a:eq(0), .ui-btn-inner").addClass("ui-corner-bottom"):e.find("a:eq(0)").addClass("ui-corner-all").find(".ui-btn-inner").addClass("ui-corner-all");b.bind("collapse",function(d){!d.isDefaultPrevented()&&a(d.target).closest(".ui-collapsible-contain").is(b)&&(d.preventDefault(),e.addClass("ui-collapsible-heading-collapsed").find(".ui-collapsible-heading-status").text(c.expandCueText).end().find(".ui-icon").removeClass("ui-icon-minus").addClass("ui-icon-plus"),
|
||||
f.addClass("ui-collapsible-content-collapsed").attr("aria-hidden",!0),b.jqmData("collapsible-last")&&e.find("a:eq(0), .ui-btn-inner").addClass("ui-corner-bottom"))}).bind("expand",function(a){a.isDefaultPrevented()||(a.preventDefault(),e.removeClass("ui-collapsible-heading-collapsed").find(".ui-collapsible-heading-status").text(c.collapseCueText),e.find(".ui-icon").removeClass("ui-icon-plus").addClass("ui-icon-minus"),f.removeClass("ui-collapsible-content-collapsed").attr("aria-hidden",!1),b.jqmData("collapsible-last")&&
|
||||
e.find("a:eq(0), .ui-btn-inner").removeClass("ui-corner-bottom"))}).trigger(c.collapsed?"collapse":"expand");d.length&&!d.jqmData("collapsiblebound")&&(d.jqmData("collapsiblebound",!0).bind("expand",function(b){a(b.target).closest(".ui-collapsible-contain").siblings(".ui-collapsible-contain").trigger("collapse")}),d=d.find(":jqmData(role='collapsible'):first"),d.first().find("a:eq(0)").addClass("ui-corner-top").find(".ui-btn-inner").addClass("ui-corner-top"),d.last().jqmData("collapsible-last",!0));
|
||||
e.bind("vclick",function(a){e.is(".ui-collapsible-heading-collapsed")?b.trigger("expand"):b.trigger("collapse");a.preventDefault()})}})})(jQuery);
|
||||
(function(a){a.fn.controlgroup=function(d){return this.each(function(){function c(a){a.removeClass("ui-btn-corner-all ui-shadow").eq(0).addClass(f[0]).end().filter(":last").addClass(f[1]).addClass("ui-controlgroup-last")}var b=a.extend({direction:a(this).jqmData("type")||"vertical",shadow:!1},d),e=a(this).find(">legend"),f=b.direction=="horizontal"?["ui-corner-left","ui-corner-right"]:["ui-corner-top","ui-corner-bottom"];a(this).find("input:eq(0)").attr("type");e.length&&(a(this).wrapInner('<div class="ui-controlgroup-controls"></div>'),
|
||||
a('<div role="heading" class="ui-controlgroup-label">'+e.html()+"</div>").insertBefore(a(this).children(0)),e.remove());a(this).addClass("ui-corner-all ui-controlgroup ui-controlgroup-"+b.direction);c(a(this).find(".ui-btn"));c(a(this).find(".ui-btn-inner"));b.shadow&&a(this).addClass("ui-shadow")})}})(jQuery);(function(a){a.fn.fieldcontain=function(){return this.addClass("ui-field-contain ui-body ui-br")}})(jQuery);
|
||||
(function(a){var d={};a.widget("mobile.listview",a.mobile.widget,{options:{theme:"c",countTheme:"c",headerTheme:"b",dividerTheme:"b",splitIcon:"arrow-r",splitTheme:"b",inset:!1},_create:function(){var a=this;a.element.addClass(function(b,d){return d+" ui-listview "+(a.options.inset?" ui-listview-inset ui-corner-all ui-shadow ":"")});a.refresh()},_itemApply:function(c,b){b.find(".ui-li-count").addClass("ui-btn-up-"+(c.jqmData("counttheme")||this.options.countTheme)+" ui-btn-corner-all").end().find("h1, h2, h3, h4, h5, h6").addClass("ui-li-heading").end().find("p, dl").addClass("ui-li-desc").end().find(">img:eq(0), .ui-link-inherit>img:eq(0)").addClass("ui-li-thumb").each(function(){b.addClass(a(this).is(".ui-li-icon")?
|
||||
"ui-li-has-icon":"ui-li-has-thumb")}).end().find(".ui-li-aside").each(function(){var b=a(this);b.prependTo(b.parent())})},_removeCorners:function(a){a.add(a.find(".ui-btn-inner, .ui-li-link-alt, .ui-li-thumb")).removeClass("ui-corner-top ui-corner-bottom ui-corner-br ui-corner-bl ui-corner-tr ui-corner-tl")},refresh:function(c){this._createSubPages();var b=this.options,d=this.element,f=d.jqmData("dividertheme")||b.dividerTheme,g=d.jqmData("splittheme"),i=d.jqmData("spliticon"),h=d.children("li"),
|
||||
l=a.support.cssPseudoElement||!a.nodeName(d[0],"ol")?0:1;l&&d.find(".ui-li-dec").remove();for(var m=0,o=h.length;m<o;m++){var j=h.eq(m),p="ui-li";if(c||!j.hasClass("ui-li")){var k=j.jqmData("theme")||b.theme,q=j.children("a");if(q.length){var n=j.jqmData("icon");j.buttonMarkup({wrapperEls:"div",shadow:!1,corners:!1,iconpos:"right",icon:q.length>1||n===!1?!1:n||"arrow-r",theme:k});q.first().addClass("ui-link-inherit");q.length>1&&(p+=" ui-li-has-alt",q=q.last(),n=g||q.jqmData("theme")||b.splitTheme,
|
||||
q.appendTo(j).attr("title",q.text()).addClass("ui-li-link-alt").empty().buttonMarkup({shadow:!1,corners:!1,theme:k,icon:!1,iconpos:!1}).find(".ui-btn-inner").append(a("<span />").buttonMarkup({shadow:!0,corners:!0,theme:n,iconpos:"notext",icon:i||q.jqmData("icon")||b.splitIcon})))}else j.jqmData("role")==="list-divider"?(p+=" ui-li-divider ui-btn ui-bar-"+f,j.attr("role","heading"),l&&(l=1)):p+=" ui-li-static ui-body-"+k}b.inset&&(m===0&&(p+=" ui-corner-top",j.add(j.find(".ui-btn-inner")).find(".ui-li-link-alt").addClass("ui-corner-tr").end().find(".ui-li-thumb").addClass("ui-corner-tl"),
|
||||
j.next().next().length&&this._removeCorners(j.next())),m===h.length-1&&(p+=" ui-corner-bottom",j.add(j.find(".ui-btn-inner")).find(".ui-li-link-alt").addClass("ui-corner-br").end().find(".ui-li-thumb").addClass("ui-corner-bl"),j.prev().prev().length&&this._removeCorners(j.prev())));l&&p.indexOf("ui-li-divider")<0&&(j.is(".ui-li-static:first")?j:j.find(".ui-link-inherit")).addClass("ui-li-jsnumbering").prepend("<span class='ui-li-dec'>"+l++ +". </span>");j.add(j.children(".ui-btn-inner")).addClass(p);
|
||||
c||this._itemApply(d,j)}},_idStringEscape:function(a){return a.replace(/[^a-zA-Z0-9]/g,"-")},_createSubPages:function(){var c=this.element,b=c.closest(".ui-page"),e=b.jqmData("url"),f=e||b[0][a.expando],g=c.attr("id"),i=this.options,h="data-"+a.mobile.ns,l=b.find(":jqmData(role='footer')").jqmData("id");typeof d[f]==="undefined"&&(d[f]=-1);g=g||++d[f];a(c.find("li>ul, li>ol").toArray().reverse()).each(function(b){var d=a(this),f=d.attr("id")||g+"-"+b,b=d.parent(),p=a(d.prevAll().toArray().reverse()),
|
||||
p=p.length?p:a("<span>"+a.trim(b.contents()[0].nodeValue)+"</span>"),k=p.first().text(),f=(e||"")+"&"+a.mobile.subPageUrlKey+"="+f;theme=d.jqmData("theme")||i.theme;countTheme=d.jqmData("counttheme")||c.jqmData("counttheme")||i.countTheme;newPage=d.detach().wrap("<div "+h+"role='page' "+h+"url='"+f+"' "+h+"theme='"+theme+"' "+h+"count-theme='"+countTheme+"'><div "+h+"role='content'></div></div>").parent().before("<div "+h+"role='header' "+h+"theme='"+i.headerTheme+"'><div class='ui-title'>"+k+"</div></div>").after(l?
|
||||
a("<div "+h+"role='footer' "+h+"id='"+l+"'>"):"").parent().appendTo(a.mobile.pageContainer);newPage.page();d=b.find("a:first");d.length||(d=a("<a />").html(p||k).prependTo(b.empty()));d.attr("href","#"+f)}).listview()}})})(jQuery);
|
||||
(function(a){a.mobile.listview.prototype.options.filter=!1;a.mobile.listview.prototype.options.filterPlaceholder="Filter items...";a.mobile.listview.prototype.options.filterTheme="c";a(":jqmData(role='listview')").live("listviewcreate",function(){var d=a(this),c=d.data("listview");if(c.options.filter){var b=a("<form>",{"class":"ui-listview-filter ui-bar-"+c.options.filterTheme,role:"search"});a("<input>",{placeholder:c.options.filterPlaceholder}).attr("data-"+a.mobile.ns+"type","search").jqmData("lastval",
|
||||
"").bind("keyup change",function(){var b=this.value.toLowerCase(),c=null,c=a(this).jqmData("lastval")+"";a(this).jqmData("lastval",b);change=b.replace(RegExp("^"+c),"");c=b.length<c.length||change.length!=b.length-c.length?d.children():d.children(":not(.ui-screen-hidden)");if(b){for(var g,i=!1,h="",l=c.length-1;l>=0;l--)g=a(c[l]),h=g.jqmData("filtertext")||g.text(),g.is("li:jqmData(role=list-divider)")?(g.toggleClass("ui-filter-hidequeue",!i),i=!1):h.toLowerCase().indexOf(b)===-1?g.toggleClass("ui-filter-hidequeue",
|
||||
!0):i=!0;c.filter(":not(.ui-filter-hidequeue)").toggleClass("ui-screen-hidden",!1);c.filter(".ui-filter-hidequeue").toggleClass("ui-screen-hidden",!0).toggleClass("ui-filter-hidequeue",!1)}else c.toggleClass("ui-screen-hidden",!1)}).appendTo(b).textinput();a(this).jqmData("inset")&&b.addClass("ui-listview-filter-inset");b.insertBefore(d)}})})(jQuery);
|
||||
(function(a){a.widget("mobile.dialog",a.mobile.widget,{options:{closeBtnText:"Close"},_create:function(){var d=this.element;d.attr("role","dialog").addClass("ui-page ui-dialog ui-body-a").find(":jqmData(role=header)").addClass("ui-corner-top ui-overlay-shadow").prepend("<a href='#' data-"+a.mobile.ns+"icon='delete' data-"+a.mobile.ns+"rel='back' data-"+a.mobile.ns+"iconpos='notext'>"+this.options.closeBtnText+"</a>").end().find('.ui-content:not([class*="ui-body-"])').addClass("ui-body-c").end().find(".ui-content,:jqmData(role='footer')").last().addClass("ui-corner-bottom ui-overlay-shadow");
|
||||
d.bind("vclick submit",function(c){c=a(c.target).closest(c.type==="vclick"?"a":"form");if(c.length&&!c.jqmData("transition")){var b=a.mobile.urlHistory.getActive()||{};c.attr("data-"+a.mobile.ns+"transition",b.transition||a.mobile.defaultDialogTransition).attr("data-"+a.mobile.ns+"direction","reverse")}}).bind("pagehide",function(){a(this).find("."+a.mobile.activeBtnClass).removeClass(a.mobile.activeBtnClass)})},close:function(){window.history.back()}})})(jQuery);
|
||||
(function(a,d){a.widget("mobile.navbar",a.mobile.widget,{options:{iconpos:"top",grid:null},_create:function(){var c=this.element,b=c.find("a"),e=b.filter(":jqmData(icon)").length?this.options.iconpos:d;c.addClass("ui-navbar").attr("role","navigation").find("ul").grid({grid:this.options.grid});e||c.addClass("ui-navbar-noicons");b.buttonMarkup({corners:!1,shadow:!1,iconpos:e});c.delegate("a","vclick",function(){b.not(".ui-state-persist").removeClass(a.mobile.activeBtnClass);a(this).addClass(a.mobile.activeBtnClass)})}})})(jQuery);
|
||||
(function(a){a.fn.grid=function(d){return this.each(function(){var c=a.extend({grid:null},d),b=a(this).children(),e={solo:1,a:2,b:3,c:4,d:5},c=c.grid;if(!c)if(b.length<=5)for(var f in e)e[f]==b.length&&(c=f);else c="a";e=e[c];a(this).addClass("ui-grid-"+c);b.filter(":nth-child("+e+"n+1)").addClass("ui-block-a");e>1&&b.filter(":nth-child("+e+"n+2)").addClass("ui-block-b");e>2&&b.filter(":nth-child(3n+3)").addClass("ui-block-c");e>3&&b.filter(":nth-child(4n+4)").addClass("ui-block-d");e>4&&b.filter(":nth-child(5n+5)").addClass("ui-block-e")})}})(jQuery);
|
||||
(function(a,d,c){var b=a("html");a("head");var e=a(d);a(d.document).trigger("mobileinit");if(a.mobile.gradeA()){if(d.blackberry&&!d.WebKitPoint||d.operamini&&Object.prototype.toString.call(d.operamini)==="[object OperaMini]")a.mobile.ajaxEnabled=!1;b.addClass("ui-mobile ui-mobile-rendering");var f=a.mobile.loadingMessage?a("<div class='ui-loader ui-body-a ui-corner-all'><span class='ui-icon ui-icon-loading spin'></span><h1>"+a.mobile.loadingMessage+"</h1></div>"):c;a.extend(a.mobile,{showPageLoadingMsg:function(){if(a.mobile.loadingMessage){var c=
|
||||
a("."+a.mobile.activeBtnClass).first();f.appendTo(a.mobile.pageContainer).css({top:a.support.scrollTop&&a(d).scrollTop()+a(d).height()/2||c.length&&c.offset().top||100})}b.addClass("ui-loading")},hidePageLoadingMsg:function(){b.removeClass("ui-loading")},pageLoading:function(b){b?a.mobile.hidePageLoadingMsg():a.mobile.showPageLoadingMsg()},initializePage:function(){var b=a(":jqmData(role='page')");b.add(":jqmData(role='dialog')").each(function(){var b=a(this);b.jqmData("url")||b.attr("data-"+a.mobile.ns+
|
||||
"url",b.attr("id"))});a.mobile.firstPage=b.first();a.mobile.pageContainer=b.first().parent().addClass("ui-mobile-viewport");a.mobile.showPageLoadingMsg();!a.mobile.hashListeningEnabled||!a.mobile.path.stripHash(location.hash)?a.mobile.changePage(a.mobile.firstPage,{transition:"none",reverse:!0,changeHash:!1,fromHashChange:!0}):e.trigger("hashchange",[!0])}});a(function(){d.scrollTo(0,1);a.mobile.defaultHomeScroll=!a.support.scrollTop||a(d).scrollTop()===1?0:1;a(a.mobile.initializePage);e.load(a.mobile.silentScroll)})}})(jQuery,
|
||||
this);
|
||||
@@ -0,0 +1,37 @@
|
||||
//quick & dirty theme switcher, written to potentially work as a bookmarklet
|
||||
(function($){
|
||||
$.themeswitcher = function(){
|
||||
if( $('[data-'+ $.mobile.ns +'-url=themeswitcher]').length ){ return; }
|
||||
var themesDir = 'http://jquerymobile.com/test/themes/',
|
||||
themes = ['default','valencia'],
|
||||
currentPage = $.mobile.activePage,
|
||||
menuPage = $( '<div data-'+ $.mobile.ns +'url="themeswitcher" data-'+ $.mobile.ns +'role=\'dialog\' data-'+ $.mobile.ns +'theme=\'a\'>' +
|
||||
'<div data-'+ $.mobile.ns +'role=\'header\' data-'+ $.mobile.ns +'theme=\'b\'>' +
|
||||
'<div class=\'ui-title\'>Switch Theme:</div>'+
|
||||
'</div>'+
|
||||
'<div data-'+ $.mobile.ns +'role=\'content\' data-'+ $.mobile.ns +'theme=\'c\'><ul data-'+ $.mobile.ns +'role=\'listview\' data-'+ $.mobile.ns +'inset=\'true\'></ul></div>'+
|
||||
'</div>' )
|
||||
.appendTo( $.mobile.pageContainer ),
|
||||
menu = menuPage.find('ul');
|
||||
|
||||
//menu items
|
||||
$.each(themes, function( i ){
|
||||
$('<li><a href="#" data-'+ $.mobile.ns +'rel="back">' + themes[ i ].charAt(0).toUpperCase() + themes[ i ].substr(1) + '</a></li>')
|
||||
.bind("vclick", function(){
|
||||
addTheme( themes[i] );
|
||||
menuPage.dialog( "close" );
|
||||
return false;
|
||||
})
|
||||
.appendTo(menu);
|
||||
});
|
||||
|
||||
//remover, adder
|
||||
function addTheme(theme){
|
||||
$('head').append( '<link rel=\'stylesheet\' href=\''+ themesDir + theme +'/\' />' );
|
||||
}
|
||||
|
||||
//create page, listview
|
||||
menuPage.page();
|
||||
|
||||
};
|
||||
})(jQuery);
|
||||
@@ -2,3 +2,23 @@
|
||||
.ui-collapsible-content-expanded {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.login_error_message {
|
||||
display: none;
|
||||
background-color: #9A0404;
|
||||
border-radius: 12px;
|
||||
-moz-border-radius: 12px;
|
||||
-webkit-border-radius: 12px;
|
||||
color: white;
|
||||
font-family: Ubuntu, Helvetica, sans-serif;
|
||||
font-size: 16px;
|
||||
padding: 5px;
|
||||
margin-top: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
.login_invalid .login_error_message {
|
||||
display: block;
|
||||
}
|
||||
.login_valid .login_error_message {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,130 @@
|
||||
/*---------------------------------------------------------
|
||||
* OpenERP Web Mobile chrome
|
||||
*---------------------------------------------------------*/
|
||||
|
||||
openerp.web_mobile.chrome_mobile = function(openerp) {
|
||||
|
||||
openerp.web_mobile.mobilewebclient = function(element_id) {
|
||||
// TODO Helper to start mobile webclient rename it openerp.base.webclient
|
||||
var client = new openerp.web_mobile.MobileWebClient(element_id);
|
||||
client.start();
|
||||
return client;
|
||||
};
|
||||
|
||||
openerp.web_mobile.MobileWebClient = openerp.base.Widget.extend({
|
||||
init: function(element_id) {
|
||||
var self = this;
|
||||
this._super(null, element_id);
|
||||
QWeb.add_template("xml/web_mobile.xml");
|
||||
var params = {};
|
||||
this.$element.html(QWeb.render("WebClient", {}));
|
||||
this.session = new openerp.base.Session("oe_errors");
|
||||
this.crashmanager = new openerp.base.CrashManager(this);
|
||||
this.login = new openerp.web_mobile.Login(this, "oe_app");
|
||||
// this.session.on_session_invalid.add(this.login.do_ask_login);
|
||||
},
|
||||
start: function() {
|
||||
this.session.start();
|
||||
this.login.start();
|
||||
}
|
||||
});
|
||||
|
||||
openerp.web_mobile.Login = openerp.base.Widget.extend({
|
||||
init: function(session, element_id) {
|
||||
this._super(session, element_id);
|
||||
},
|
||||
start: function() {
|
||||
var self = this;
|
||||
jQuery("#oe_header").children().remove();
|
||||
this.rpc("/base/database/get_list", {}, function(result) {
|
||||
var selection = new openerp.web_mobile.Selection();
|
||||
self.db_list = result.db_list;
|
||||
self.$element.html(QWeb.render("Login", self));
|
||||
self.$element.find("#login_btn").click(self.on_login);
|
||||
$.mobile.initializePage();
|
||||
});
|
||||
this.$element
|
||||
.removeClass("login_invalid");
|
||||
},
|
||||
on_login: function(ev) {
|
||||
ev.preventDefault();
|
||||
var self = this;
|
||||
var $e = this.$element;
|
||||
var db = $e.find("div select[name=database]").val();
|
||||
var login = $e.find("div input[name=login]").val();
|
||||
var password = $e.find("div input[name=password]").val();
|
||||
//$e.hide();
|
||||
// Should hide then call callback
|
||||
this.session.session_login(db, login, password, function() {
|
||||
if(self.session.session_is_valid()) {
|
||||
self.on_login_valid();
|
||||
} else {
|
||||
self.on_login_invalid();
|
||||
}
|
||||
});
|
||||
},
|
||||
on_login_invalid: function() {
|
||||
this.$element
|
||||
.removeClass("login_valid")
|
||||
.addClass("login_invalid")
|
||||
.show();
|
||||
},
|
||||
on_login_valid: function() {
|
||||
this.$element
|
||||
.removeClass("login_invalid")
|
||||
.addClass("login_valid");
|
||||
//.hide();
|
||||
this.homepage = new openerp.web_mobile.HomePage(this, "oe_app");
|
||||
this.homepage.start();
|
||||
},
|
||||
do_ask_login: function(continuation) {
|
||||
this.on_login_invalid();
|
||||
this.on_login_valid.add({
|
||||
position: "last",
|
||||
unique: true,
|
||||
callback: continuation
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
openerp.web_mobile.HomePage = openerp.base.Widget.extend({
|
||||
init: function(session, element_id) {
|
||||
this._super(session, element_id);
|
||||
},
|
||||
start: function() {
|
||||
this.$element.html(QWeb.render("HomePage", {}));
|
||||
this.header = new openerp.web_mobile.Header(this, "oe_header");
|
||||
this.shortcuts = new openerp.web_mobile.Shortcuts(this, "oe_shortcuts");
|
||||
this.menu = new openerp.web_mobile.Menu(this, "oe_menu", "oe_secondary_menu");
|
||||
this.options = new openerp.web_mobile.Options(this, "oe_options");
|
||||
this.header.start();
|
||||
this.shortcuts.start();
|
||||
this.menu.start();
|
||||
this.options.start();
|
||||
jQuery("#oe_header").find("h1").html('Home');
|
||||
this.$element.find("a").click(this.on_clicked);
|
||||
}
|
||||
});
|
||||
|
||||
openerp.web_mobile.Header = openerp.base.Widget.extend({
|
||||
init: function(session, element_id) {
|
||||
this._super(session, element_id);
|
||||
},
|
||||
start: function() {
|
||||
var self = this;
|
||||
self.$element.html(QWeb.render("Header", this));
|
||||
self.$element.find("a").click(this.on_clicked);
|
||||
},
|
||||
on_clicked: function(ev) {
|
||||
$opt = $(ev.currentTarget);
|
||||
current_id = $opt.attr('id');
|
||||
if (current_id == 'home') {
|
||||
this.homepage = new openerp.web_mobile.HomePage(this, "oe_app");
|
||||
this.homepage.start();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
openerp.web_mobile.Shortcuts = openerp.base.Widget.extend({
|
||||
init: function(session, element_id) {
|
||||
this._super(session, element_id);
|
||||
@@ -15,64 +141,10 @@ openerp.web_mobile.Shortcuts = openerp.base.Widget.extend({
|
||||
id = $shortcut.data('menu');
|
||||
res_id = $shortcut.data('res');
|
||||
jQuery("#oe_header").find("h1").html($shortcut.data('name'));
|
||||
this.listview = new openerp.web_mobile.ListView(this.session, "oe_app", res_id);
|
||||
this.listview = new openerp.web_mobile.ListView(this, "oe_app", res_id);
|
||||
this.listview.start();
|
||||
}
|
||||
});
|
||||
openerp.web_mobile.Header = openerp.base.Widget.extend({
|
||||
init: function(session, element_id) {
|
||||
this._super(session, element_id);
|
||||
},
|
||||
start: function() {
|
||||
this.$element.html(QWeb.render("Header", this));
|
||||
this.$element.find("a").click(this.on_clicked);
|
||||
},
|
||||
on_clicked: function(ev) {
|
||||
$opt = $(ev.currentTarget);
|
||||
current_id = $opt.attr('id');
|
||||
if (current_id == 'home') {
|
||||
this.homepage = new openerp.web_mobile.Login(this.session, "oe_app");
|
||||
this.homepage.on_login_valid();
|
||||
}
|
||||
}
|
||||
});
|
||||
openerp.web_mobile.Secondary = openerp.base.Widget.extend({
|
||||
init: function(session, element_id, secondary_menu_id) {
|
||||
this._super(session, element_id);
|
||||
this.data = secondary_menu_id;
|
||||
},
|
||||
start: function(ev, id) {
|
||||
var v = { menu : this.data };
|
||||
this.$element.html(QWeb.render("Menu.secondary", v));
|
||||
this.$element.add(this.$secondary_menu).find("a").click(this.on_menu_click);
|
||||
},
|
||||
on_menu_click: function(ev, id) {
|
||||
$menu = $(ev.currentTarget);
|
||||
id = $menu.data('menu');
|
||||
for (var i = 0; i < this.data.children.length; i++) {
|
||||
if (this.data.children[i].id == id) {
|
||||
this.children = this.data.children[i];
|
||||
}
|
||||
}
|
||||
jQuery("#oe_header").find("h1").html($menu.data('name'));
|
||||
|
||||
var child_len = this.children.children.length;
|
||||
if (child_len > 0) {
|
||||
this.$element
|
||||
.removeClass("secondary_menu")
|
||||
.addClass("content_menu");
|
||||
//.hide();
|
||||
this.secondary = new openerp.web_mobile.Secondary(this.session, "oe_app", this.children);
|
||||
this.secondary.start();
|
||||
}
|
||||
else {
|
||||
if (id) {
|
||||
this.listview = new openerp.web_mobile.ListView(this.session, "oe_app", id);
|
||||
this.listview.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
openerp.web_mobile.Menu = openerp.base.Widget.extend({
|
||||
init: function(session, element_id, secondary_menu_id) {
|
||||
@@ -102,10 +174,48 @@ openerp.web_mobile.Menu = openerp.base.Widget.extend({
|
||||
.removeClass("login_valid")
|
||||
.addClass("secondary_menu");
|
||||
//.hide();
|
||||
this.secondary = new openerp.web_mobile.Secondary(this.session, "oe_app", this.children);
|
||||
this.secondary = new openerp.web_mobile.Secondary(this, "oe_app", this.children);
|
||||
this.secondary.start();
|
||||
}
|
||||
});
|
||||
|
||||
openerp.web_mobile.Secondary = openerp.base.Widget.extend({
|
||||
init: function(session, element_id, secondary_menu_id) {
|
||||
this._super(session, element_id);
|
||||
this.data = secondary_menu_id;
|
||||
},
|
||||
start: function(ev, id) {
|
||||
var v = { menu : this.data };
|
||||
this.$element.html(QWeb.render("Menu.secondary", v));
|
||||
this.$element.add(this.$secondary_menu).find("a").click(this.on_menu_click);
|
||||
},
|
||||
on_menu_click: function(ev, id) {
|
||||
$menu = $(ev.currentTarget);
|
||||
id = $menu.data('menu');
|
||||
for (var i = 0; i < this.data.children.length; i++) {
|
||||
if (this.data.children[i].id == id) {
|
||||
this.children = this.data.children[i];
|
||||
}
|
||||
}
|
||||
jQuery("#oe_header").find("h1").html($menu.data('name'));
|
||||
var child_len = this.children.children.length;
|
||||
if (child_len > 0) {
|
||||
this.$element
|
||||
.removeClass("secondary_menu")
|
||||
.addClass("content_menu");
|
||||
//.hide();
|
||||
this.secondary = new openerp.web_mobile.Secondary(this, "oe_app", this.children);
|
||||
this.secondary.start();
|
||||
}
|
||||
else {
|
||||
if (id) {
|
||||
this.listview = new openerp.web_mobile.ListView(this, "oe_app", id);
|
||||
this.listview.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
openerp.web_mobile.Options = openerp.base.Widget.extend({
|
||||
init: function(session, element_id) {
|
||||
this._super(session, element_id);
|
||||
@@ -117,101 +227,23 @@ openerp.web_mobile.Options = openerp.base.Widget.extend({
|
||||
},
|
||||
on_logout: function(ev) {
|
||||
this.session.logout();
|
||||
this.login = new openerp.web_mobile.Login(this.session, "oe_app");
|
||||
this.login.start();
|
||||
// this.login = new openerp.web_mobile.Login(this, "oe_app");
|
||||
// this.login.start();
|
||||
}
|
||||
});
|
||||
openerp.web_mobile.Login = openerp.base.Widget.extend({
|
||||
init: function(session, element_id) {
|
||||
this._super(session, element_id);
|
||||
},
|
||||
start: function() {
|
||||
var self = this;
|
||||
|
||||
jQuery("#oe_header").children().remove();
|
||||
this.rpc("/base/database/get_list", {}, function(result) {
|
||||
self.db_list = result.db_list;
|
||||
self.$element.html(QWeb.render("Login", self));
|
||||
self.$element.find('#database').click(self.on_db_select);
|
||||
self.$element.find("#login").click(self.on_login);
|
||||
$.mobile.initializePage();
|
||||
})
|
||||
openerp.web_mobile.Selection = openerp.base.Widget.extend({
|
||||
init: function (){
|
||||
this._super();
|
||||
},
|
||||
on_db_select: function(ev) {
|
||||
var db = this.$element.find("#database option:selected").val();
|
||||
jQuery("#db_text").html(db);
|
||||
start: function(){
|
||||
this._super();
|
||||
var self = this;
|
||||
},
|
||||
on_login: function(ev) {
|
||||
on_select_option: function(ev){
|
||||
ev.preventDefault();
|
||||
var self = this;
|
||||
var $e = this.$element;
|
||||
var db = $e.find("div select[name=database]").val();
|
||||
var login = $e.find("div input[name=login]").val();
|
||||
var password = $e.find("div input[name=password]").val();
|
||||
//$e.hide();
|
||||
// Should hide then call callback
|
||||
this.session.session_login(db, login, password, function() {
|
||||
if(self.session.session_is_valid()) {
|
||||
self.on_login_valid();
|
||||
} else {
|
||||
self.on_login_invalid();
|
||||
}
|
||||
});
|
||||
},
|
||||
on_login_invalid: function() {
|
||||
this.$element
|
||||
.removeClass("login_valid")
|
||||
.addClass("login_invalid")
|
||||
.show();
|
||||
},
|
||||
on_login_valid: function() {
|
||||
this.$element
|
||||
.removeClass("login_invalid")
|
||||
.addClass("login_valid");
|
||||
//.hide();
|
||||
this.$element.html(QWeb.render("HomePage", {}));
|
||||
this.header = new openerp.web_mobile.Header(this.session, "oe_header");
|
||||
this.shortcuts = new openerp.web_mobile.Shortcuts(this.session, "oe_shortcuts");
|
||||
this.menu = new openerp.web_mobile.Menu(this.session, "oe_menu", "oe_secondary_menu");
|
||||
this.options = new openerp.web_mobile.Options(this.session, "oe_options");
|
||||
this.header.start();
|
||||
this.shortcuts.start();
|
||||
this.menu.start();
|
||||
this.options.start();
|
||||
jQuery("#oe_header").find("h1").html('Home');
|
||||
|
||||
},
|
||||
do_ask_login: function(continuation) {
|
||||
this.on_login_invalid();
|
||||
this.on_login_valid.add({
|
||||
position: "last",
|
||||
unique: true,
|
||||
callback: continuation
|
||||
});
|
||||
var $this = ev.currentTarget;
|
||||
$($this).prev().find(".ui-btn-text").html($($this).find("option:selected").text());
|
||||
}
|
||||
});
|
||||
openerp.web_mobile.MobileWebClient = openerp.base.Widget.extend({
|
||||
init: function(element_id) {
|
||||
var self = this;
|
||||
this._super(null, element_id);
|
||||
QWeb.add_template("xml/web_mobile.xml");
|
||||
var params = {};
|
||||
|
||||
this.$element.html(QWeb.render("WebClient", {}));
|
||||
this.session = new openerp.base.Session("oe_errors");
|
||||
this.crashmanager = new openerp.base.CrashManager(this.session);
|
||||
this.login = new openerp.web_mobile.Login(this.session, "oe_app");
|
||||
this.session.on_session_invalid.add(this.login.do_ask_login);
|
||||
},
|
||||
start: function() {
|
||||
this.session.start();
|
||||
this.login.start();
|
||||
}
|
||||
});
|
||||
openerp.web_mobile.mobilewebclient = function(element_id) {
|
||||
// TODO Helper to start mobile webclient rename it openerp.base.webclient
|
||||
var client = new openerp.web_mobile.MobileWebClient(element_id);
|
||||
client.start();
|
||||
return client;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,85 +1,104 @@
|
||||
/*---------------------------------------------------------
|
||||
* OpenERP Web Mobile Form View
|
||||
*---------------------------------------------------------*/
|
||||
|
||||
openerp.web_mobile.form_mobile = function (openerp) {
|
||||
|
||||
openerp.web_mobile.FormView = openerp.base.Widget.extend({
|
||||
init: function(session, element_id, list_id, action) {
|
||||
this._super(session, element_id);
|
||||
this.list_id = list_id;
|
||||
this.action = action;
|
||||
this.content_expanded_class = "ui-collapsible-content ui-collapsible-content-expanded";
|
||||
this.content_collapsed_class = "ui-collapsible-content ui-collapsible-content-collapsed";
|
||||
this.expanded_class = "ui-collapsible-content-expanded";
|
||||
this.collapsed_class = "ui-collapsible-content-collapsed";
|
||||
this.plus_class = "ui-icon-plus";
|
||||
this.minus_class = "ui-icon-minus";
|
||||
},
|
||||
start: function() {
|
||||
var self = this;
|
||||
id = this.list_id;
|
||||
model = this.action.res_model;
|
||||
view_id = this.action.views[1][0];
|
||||
|
||||
this.dataset = new openerp.base.DataSetSearch(this.session, this.action.res_model, null, null);
|
||||
this.dataset = new openerp.base.DataSetSearch(this, this.action.res_model, null, null);
|
||||
this.dataset.read_slice([],{}, function (result) {
|
||||
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
if (result[i].id == id) {
|
||||
var data = result[i];
|
||||
}
|
||||
}
|
||||
self.rpc("/base/formview/load", {"model": model, "view_id": view_id }, function (result) {
|
||||
var fields = result.fields_view.fields;
|
||||
var view_fields = result.fields_view.arch.children;
|
||||
var get_fields = self.get_fields(view_fields);
|
||||
|
||||
var selection = new openerp.web_mobile.Selection();
|
||||
for (var j = 0; j < view_fields.length; j++) {
|
||||
if (view_fields[j].tag == 'notebook') {
|
||||
var notebooks = view_fields[j];
|
||||
}
|
||||
}
|
||||
$("#oe_header").find("h1").html(result.fields_view.arch.attrs.string);
|
||||
self.$element.html(QWeb.render("FormView", {'get_fields': get_fields, 'notebooks': notebooks || false, 'fields' : result.fields_view.fields, 'values' : data }));
|
||||
|
||||
self.$element.html(QWeb.render("FormView", {'get_fields': get_fields, 'notebooks': notebooks || false, 'fields' : fields, 'values' : data }));
|
||||
self.$element.find('select').change(function(ev){
|
||||
selection.on_select_option(ev);
|
||||
});
|
||||
self.$element.find('a').click(function(){
|
||||
|
||||
for (var k = 0; k < notebooks.children.length; k++) {
|
||||
|
||||
var text = $(this).find('.ui-btn-text').text();
|
||||
var next = $(this).next();
|
||||
var span = $(this).find('span .ui-icon');
|
||||
var content_expanded_class = "ui-collapsible-content ui-collapsible-content-expanded";
|
||||
var content_collapsed_class = "ui-collapsible-content ui-collapsible-content-collapsed";
|
||||
var expanded_class = "ui-collapsible-content-expanded";
|
||||
var collapsed_class = "ui-collapsible-content-collapsed";
|
||||
var plus_class = "ui-icon-plus";
|
||||
var minus_class = "ui-icon-minus";
|
||||
|
||||
if (notebooks.children[k].attrs.string == $.trim(text)) {
|
||||
get_fields = self.get_fields(notebooks.children[k].children);
|
||||
|
||||
$(this).parents().find('form').find('div').each( function() {
|
||||
var prev = $(this).prev();
|
||||
var trim_class = $.trim($(this).attr('class'));
|
||||
if (trim_class == content_expanded_class || trim_class == content_collapsed_class) {
|
||||
if (trim_class == self.content_expanded_class || trim_class == self.content_collapsed_class) {
|
||||
prev.removeClass('ui-btn-active');
|
||||
|
||||
if ($.trim(prev.find('.ui-btn-text').text()) != notebooks.children[k].attrs.string) {
|
||||
prev.find('span .ui-icon').removeClass(minus_class);
|
||||
prev.find('span .ui-icon').addClass(plus_class);
|
||||
$(this).removeClass(expanded_class);
|
||||
$(this).addClass(collapsed_class);
|
||||
self.expanded($(this),prev.find('span .ui-icon'));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (next.hasClass(content_collapsed_class)) {
|
||||
span.removeClass(plus_class);
|
||||
span.addClass(minus_class);
|
||||
next.removeClass(collapsed_class);
|
||||
next.addClass(expanded_class);
|
||||
if (next.hasClass(self.content_collapsed_class)) {
|
||||
self.collapsed(next,span);
|
||||
}
|
||||
else if (next.hasClass(content_expanded_class)) {
|
||||
span.removeClass(minus_class);
|
||||
span.addClass(plus_class);
|
||||
next.removeClass(expanded_class);
|
||||
next.addClass(collapsed_class);
|
||||
else if (next.hasClass(self.content_expanded_class)) {
|
||||
self.expanded(next,span);
|
||||
}
|
||||
if (!next.find('.detail').html().length) {
|
||||
next.find('.detail').append(QWeb.render("FormView", {'get_fields': get_fields,'fields' : result.fields_view.fields, 'values' : data }));
|
||||
for (var i = 0; i < get_fields.length; i++) {
|
||||
if (fields[get_fields[i].attrs.name].type == 'one2many'){
|
||||
var get_fields_test = self.get_fields(fields[get_fields[i].attrs.name].views.form.arch.children);
|
||||
var fields_test = fields[get_fields[i].attrs.name]['views'].form.fields;
|
||||
var notebook=fields[get_fields[i].attrs.name].views.form.arch;
|
||||
}
|
||||
}
|
||||
if(notebook){
|
||||
next.find('.detail').append(QWeb.render("FormView", {'get_fields': get_fields,'fields' : result.fields_view.fields, 'values' : data,'til': notebook.attrs.string }));
|
||||
}else{
|
||||
next.find('.detail').append(QWeb.render("FormView", {'get_fields': get_fields,'fields' : result.fields_view.fields, 'values' : data }));
|
||||
}
|
||||
}
|
||||
next.find('.detail').find('a').click(function(){
|
||||
if(next.find('.detail').find('a').next().find('.detail').html().length){
|
||||
if (next.find('.detail').find('a').next().hasClass(self.content_collapsed_class)) {
|
||||
self.collapsed(next.find('.detail').find('a').next(),next.find('.detail').find('a').find('span .ui-icon'));
|
||||
}
|
||||
else if (next.find('.detail').find('a').next().hasClass(self.content_expanded_class)) {
|
||||
self.expanded(next.find('.detail').find('a').next(),next.find('.detail').find('a').find('span .ui-icon'));
|
||||
}
|
||||
}
|
||||
if(!next.find('.detail').find('a').next().find('.detail').html().length){
|
||||
next.find('.detail').find('a').next().find('.detail').append(QWeb.render("FormView", {'get_fields': get_fields_test,'fields' : fields_test, 'values' : data }));
|
||||
self.collapsed(next.find('.detail').find('a').next(),next.find('.detail').find('a').find('span .ui-icon'));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
self.$element.find('select').change(function(ev){
|
||||
selection.on_select_option(ev);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -93,12 +112,20 @@ openerp.web_mobile.FormView = openerp.base.Widget.extend({
|
||||
if (view_fields[i].tag == 'group') {
|
||||
this.get_fields(view_fields[i].children, this.fields);
|
||||
}
|
||||
if (view_fields[i].tag == 'separator') {
|
||||
this.get_fields(view_fields[i].children, this.fields);
|
||||
}
|
||||
}
|
||||
return this.fields;
|
||||
},
|
||||
collapsed: function(next,span) {
|
||||
span.removeClass(this.plus_class);
|
||||
span.addClass(this.minus_class);
|
||||
next.removeClass(this.collapsed_class);
|
||||
next.addClass(this.expanded_class);
|
||||
},
|
||||
expanded: function(next,span) {
|
||||
span.removeClass(this.minus_class);
|
||||
span.addClass(this.plus_class);
|
||||
next.removeClass(this.expanded_class);
|
||||
next.addClass(this.collapsed_class);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,9 @@
|
||||
/*---------------------------------------------------------
|
||||
* OpenERP Web Mobile List View
|
||||
*---------------------------------------------------------*/
|
||||
|
||||
openerp.web_mobile.list_mobile = function (openerp) {
|
||||
|
||||
openerp.web_mobile.ListView = openerp.base.Widget.extend({
|
||||
init: function(session, element_id, list_id) {
|
||||
this._super(session, element_id);
|
||||
@@ -35,10 +40,11 @@ openerp.web_mobile.ListView = openerp.base.Widget.extend({
|
||||
var search_val = '';
|
||||
}
|
||||
var self = this;
|
||||
var dataset = new openerp.base.DataSetStatic(this.session, this.action.res_model, this.action.context);
|
||||
|
||||
var dataset = new openerp.base.DataSetStatic(this, this.action.res_model, this.action.context);
|
||||
dataset.domain=[['name','ilike',search_val]];
|
||||
dataset.name_search(search_val, dataset.domain, 'ilike',false ,function(result){
|
||||
self.$element.html(QWeb.render("ListView", {'records' : result.result}));
|
||||
self.$element.html(QWeb.render("ListView", {'records' : result}));
|
||||
self.$element.find("#searchid").focus();
|
||||
if(request.term){
|
||||
self.$element.find("#searchid").val(request.term);
|
||||
@@ -60,7 +66,7 @@ openerp.web_mobile.ListView = openerp.base.Widget.extend({
|
||||
$record = $(ev.currentTarget);
|
||||
var self = this;
|
||||
id = $record.data('id');
|
||||
this.formview = new openerp.web_mobile.FormView(this.session, "oe_app", id, this.action);
|
||||
this.formview = new openerp.web_mobile.FormView(this, "oe_app", id, this.action);
|
||||
this.formview.start();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/*---------------------------------------------------------
|
||||
* OpenERP Web Mobile
|
||||
*---------------------------------------------------------*/
|
||||
|
||||
openerp.web_mobile = function(instance) {
|
||||
openerp.web_mobile.chrome_mobile(instance);
|
||||
openerp.web_mobile.list_mobile(instance);
|
||||
|
||||
@@ -3,20 +3,20 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>OpenERP Web Mobile</title>
|
||||
<link rel="stylesheet" href="/web_mobile/static/lib/jquery_mobile/css/jquery.mobile-1.0a4.1.css" />
|
||||
|
||||
<script type="text/javascript" src="/base/static/lib/LABjs/LAB.js"></script>
|
||||
<link rel="stylesheet" href="/web_mobile/static/lib/jquery_mobile/css/jquery.mobile-1.0a4.1.css"/>
|
||||
<link rel="stylesheet" href="/web_mobile/static/src/css/web_mobile.css"/>
|
||||
|
||||
<script type="text/javascript" src="/base/static/lib/jquery/jquery-1.6.2.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/jquery.ui/js/jquery-ui-1.8.9.custom.min.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/web_mobile/static/lib/jquery_mobile/js/jquery.mobile-1.0a4.1.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/jquery.ba-bbq/jquery.ba-bbq.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/underscore/underscore.js"></script>
|
||||
<script type="text/javascript" src="/base/static/lib/underscore/underscore.string.js"></script>
|
||||
<script type="text/javascript" src="/web_mobile/static/lib/jquery_mobile/js/jquery.mobile-1.0a4.1.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/base/static/lib/qweb/qweb2.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/base/static/src/js/base.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/boot.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/core.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/chrome.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/data.js"></script>
|
||||
<script type="text/javascript" src="/base/static/src/js/formats.js"></script>
|
||||
@@ -26,19 +26,16 @@
|
||||
<script type="text/javascript" src="/web_mobile/static/src/js/list_mobile.js"></script>
|
||||
<script type="text/javascript" src="/web_mobile/static/src/js/form_mobile.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="/web_mobile/static/src/css/web_mobile.css"/>
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
QWeb = window.QWeb || new QWeb2.Engine();
|
||||
var oe = openerp.init();
|
||||
openerp.web_mobile(oe);
|
||||
oe.web_mobile.mobilewebclient("moe");
|
||||
});
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="moe" class="openerp" data-role="page"></div>
|
||||
<div id="moe" class="openerp"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
@@ -4,54 +4,35 @@
|
||||
<templates id="template" xml:space="preserve">
|
||||
|
||||
<t t-name="WebClient">
|
||||
<div class="ui-page ui-body-c ui-page-active" data-role="page">
|
||||
<div data-role="page">
|
||||
<div id="oe_header"></div>
|
||||
<div id="oe_app"></div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="Header">
|
||||
<div role="banner" class="ui-bar-b ui-header" data-role="header" data-theme="b">
|
||||
<h1 aria-level="1" role="heading" tabindex="0" class="ui-title">OpenERP</h1>
|
||||
<a id="home" class="ui-btn-right jqm-home ui-btn ui-btn-icon-notext ui-btn-corner-all ui-shadow ui-btn-up-b" data-direction="reverse" data-iconpos="notext" data-icon="home" href="#" title="Home" data-theme="b">
|
||||
<span class="ui-btn-inner ui-btn-corner-all">
|
||||
<span class="ui-btn-text">Home</span>
|
||||
<span class="ui-icon ui-icon-home ui-icon-shadow"></span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="Login">
|
||||
<div role="banner" class="ui-bar-b ui-header" data-role="header" data-theme="b">
|
||||
<h1 aria-level="1" role="heading" tabindex="0" class="ui-title">OpenERP</h1>
|
||||
<div data-role="header" data-theme="b">
|
||||
<h1>OpenERP</h1>
|
||||
</div>
|
||||
<div role="main" class="ui-content" data-role="content">
|
||||
<div data-role="content">
|
||||
<fieldset>
|
||||
<div class="ui-field-contain ui-body ui-br" data-role="fieldcontain">
|
||||
<label for="database" class="select ui-select">Database:</label>
|
||||
<div class="ui-select">
|
||||
<div data-theme="c" class="ui-btn ui-btn-icon-right ui-btn-corner-all ui-shadow ui-btn-up-c">
|
||||
<span class="ui-btn-inner ui-btn-corner-all">
|
||||
<span id="db_text" class="ui-btn-text">Choose Database...</span>
|
||||
<span class="ui-icon ui-icon-arrow-d ui-icon-shadow"></span>
|
||||
</span>
|
||||
<select id="database" name="database">
|
||||
<div data-role="fieldcontain">
|
||||
<label for="database" class="select">Database:</label>
|
||||
<select id="database" name="database" data-native-menu="false">
|
||||
<t t-if="db_list">
|
||||
<t t-foreach="db_list" t-as="opt">
|
||||
<option t-att-value="opt"><t t-esc="opt"/></option>
|
||||
</t>
|
||||
</select>
|
||||
</div>
|
||||
</t>
|
||||
</select>
|
||||
<label for="login">Login:</label>
|
||||
<input type="text" id="login" name="login" value=""/><br/>
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" id="password" name="password" value=""/><br/>
|
||||
<a id="login_btn" data-theme="c" href="#" data-role="button">Login</a>
|
||||
<div class="login_error_message ui-btn-inner ui-btn-corner-all">
|
||||
<span class="ui-btn-text">Bad username or password</span>
|
||||
</div>
|
||||
<label class="ui-input-text" for="name">Login:</label>
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" name="login" value=""/><br/>
|
||||
<label class="ui-input-text" for="name">Password:</label>
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="password" name="password" value=""/><br/>
|
||||
<a id="login" class="ui-btn ui-btn-corner-all ui-shadow ui-btn-up-c" data-theme="c" href="#" data-role="button">
|
||||
<span class="ui-btn-inner ui-btn-corner-all">
|
||||
<span class="ui-btn-text">Login</span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
@@ -65,173 +46,18 @@
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ListView">
|
||||
<div role="main" class="ui-content" data-role="content">
|
||||
<form class="ui-listview-filter ui-bar-c" role="search">
|
||||
<div id="search-data" class="ui-input-search ui-shadow-inset ui-btn-corner-all ui-btn-shadow ui-icon-searchfield ui-body-c">
|
||||
<input id="searchid" placeholder="Filter items..." data-type="search" class="ui-input-text ui-body-null" autosearch="true" setTimeDefault="700"/>
|
||||
</div>
|
||||
</form>
|
||||
<ul role="listbox" data-role="listview" class="ui-listview">
|
||||
<li data-theme="c" class="ui-btn ui-btn-icon-right ui-li ui-btn-up-c" t-foreach="records" t-as="record">
|
||||
<div class="ui-btn-inner ui-li">
|
||||
<div class="ui-btn-text">
|
||||
<a id="list-id" t-att-data-id="record[0]" href="#" class="ui-link-inherit">
|
||||
<span><t t-esc="record[1]"/></span>
|
||||
</a>
|
||||
</div>
|
||||
<span class="ui-icon ui-icon-arrow-r"></span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<t t-name="Header">
|
||||
<div role="banner" class="ui-bar-b ui-header" data-role="header" data-theme="b">
|
||||
<h1 aria-level="1" role="heading" tabindex="0" class="ui-title">OpenERP</h1>
|
||||
<a id="home" class="ui-btn-right jqm-home ui-btn ui-btn-icon-notext ui-btn-corner-all ui-shadow ui-btn-up-b" data-direction="reverse" data-iconpos="notext" data-icon="home" href="#" title="Home" data-theme="b">
|
||||
<span class="ui-btn-inner ui-btn-corner-all">
|
||||
<span class="ui-btn-text">Home</span>
|
||||
<span class="ui-icon ui-icon-home ui-icon-shadow"></span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="FormView">
|
||||
<div role="main" class="ui-content" data-role="content">
|
||||
<form>
|
||||
<t t-foreach="get_fields" t-as="field">
|
||||
<div data-role="fieldcontain">
|
||||
|
||||
<label class="ui-input-text">
|
||||
<span>
|
||||
<t t-if="!(field.attrs.string)" t-esc="fields[field.attrs.name].string"></t>
|
||||
<t t-if="field.attrs.string" t-esc="field.attrs.string"></t>
|
||||
</span>:
|
||||
</label>
|
||||
<t t-if="fields[field.attrs.name].type == 'char'">
|
||||
<t t-if="values[field.attrs.name]">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" t-att-value="values[field.attrs.name]"/><br/>
|
||||
</t>
|
||||
<t t-if="!(values[field.attrs.name])">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" value=""/><br/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="fields[field.attrs.name].type == 'boolean'">
|
||||
<t t-if="values[field.attrs.name]">
|
||||
<input type="checkbox" checked="yes"/><br/>
|
||||
</t>
|
||||
<t t-if="!(values[field.attrs.name])">
|
||||
<input type="checkbox"/><br/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="fields[field.attrs.name].type == 'text'">
|
||||
<input type="text" style="width: 100%"/><br/>
|
||||
</t>
|
||||
<t t-if="fields[field.attrs.name].type == 'selection'">
|
||||
<div class="ui-select">
|
||||
<div data-theme="c" class="ui-btn ui-btn-icon-right ui-btn-corner-all ui-shadow ui-btn-up-c">
|
||||
<span class="ui-btn-inner ui-btn-corner-all">
|
||||
<span class="ui-btn-text">
|
||||
<t t-if="values[field.attrs.name]">
|
||||
<t t-foreach="fields[field.attrs.name].selection" t-as="opt">
|
||||
<t t-if="opt[0] == (values[field.attrs.name])">
|
||||
<t t-esc="opt[1]"/>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</span>
|
||||
<span class="ui-icon ui-icon-arrow-d ui-icon-shadow"></span>
|
||||
</span>
|
||||
<select>
|
||||
<t t-foreach="fields[field.attrs.name].selection" t-as="opt">
|
||||
<option t-att-value="opt[0]"><t t-esc="opt[1]"/></option>
|
||||
</t>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="fields[field.attrs.name].type == 'many2one'">
|
||||
<div class="ui-select">
|
||||
<div data-theme="c" class="ui-btn ui-btn-icon-right ui-btn-corner-all ui-shadow ui-btn-up-c">
|
||||
<span class="ui-btn-inner ui-btn-corner-all">
|
||||
<span class="ui-btn-text">
|
||||
<t t-esc="values[field.attrs.name][1]"/>
|
||||
</span>
|
||||
<span class="ui-icon ui-icon-arrow-d ui-icon-shadow"></span>
|
||||
</span>
|
||||
<select>
|
||||
<t t-if="fields[field.attrs.name].selection">
|
||||
<t t-foreach="fields[field.attrs.name].selection" t-as="opt">
|
||||
<option t-att-value="opt[0]"><t t-esc="opt[1]"/></option>
|
||||
</t>
|
||||
</t>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="fields[field.attrs.name].type == 'one2many'">
|
||||
<t t-if="values[field.attrs.name]">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" t-att-value="values[field.attrs.name]"/><br/>
|
||||
</t>
|
||||
<t t-if="!(values[field.attrs.name])">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" value=""/><br/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="fields[field.attrs.name].type == 'many2many'">
|
||||
<t t-if="values[field.attrs.name]">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" t-att-value="values[field.attrs.name]"/><br/>
|
||||
</t>
|
||||
<t t-if="!(values[field.attrs.name])">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" value=""/><br/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="fields[field.attrs.name].type == 'float'">
|
||||
<t t-if="values[field.attrs.name]">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" t-att-value="values[field.attrs.name]"/><br/>
|
||||
</t>
|
||||
<t t-if="!(values[field.attrs.name])">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" value=""/><br/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="fields[field.attrs.name].type == 'date'">
|
||||
<t t-if="values[field.attrs.name]">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" t-att-value="values[field.attrs.name]"/><br/>
|
||||
</t>
|
||||
<t t-if="!(values[field.attrs.name])">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" value=""/><br/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="fields[field.attrs.name].type == 'datetime'">
|
||||
<t t-if="values[field.attrs.name]">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" t-att-value="values[field.attrs.name]"/><br/>
|
||||
</t>
|
||||
<t t-if="!(values[field.attrs.name])">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" value=""/><br/>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="notebooks">
|
||||
<t t-foreach="notebooks.children" t-as="page">
|
||||
<div class="info ui-collapsible-contain" data-collapsed="true" data-role="collapsible">
|
||||
<h1 class="ui-collapsible-heading">
|
||||
<a class="ui-collapsible-heading-toggle ui-btn ui-btn-icon-left ui-shadow ui-corner-all ui-btn-up-c" href="#" data-theme="c" t-id="page.attrs.string">
|
||||
<span class="ui-btn-inner ui-corner-all">
|
||||
<span class="ui-btn-text">
|
||||
<t t-esc="page.attrs.string"></t>
|
||||
<!-- <span class="ui-collapsible-heading-status"></span> -->
|
||||
</span>
|
||||
<span data-theme="d" class="ui-btn ui-btn-icon-left ui-btn-corner-all ui-shadow ui-btn-up-d">
|
||||
<span class="ui-btn-inner ui-btn-corner-all ui-corner-all">
|
||||
<span class="ui-btn-text"></span>
|
||||
<span class="ui-icon ui-icon-shadow ui-icon-plus"></span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
<div class="ui-collapsible-content ui-collapsible-content-collapsed" aria-hidden="true">
|
||||
<div class="detail"></div>
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</form>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
|
||||
<t t-name="Shortcuts">
|
||||
<ul data-dividertheme="b" data-theme="c" data-inset="true" data-role="listview" class="ui-listview ui-listview-inset ui-corner-all ui-shadow">
|
||||
<li data-role="list-divider" role="heading" class="ui-li ui-li-divider ui-btn ui-bar-b ui-corner-top ui-btn-up-undefined">
|
||||
@@ -313,4 +139,188 @@
|
||||
</ul>
|
||||
</t>
|
||||
|
||||
<t t-name="ListView">
|
||||
<div role="main" class="ui-content" data-role="content">
|
||||
<form class="ui-listview-filter ui-bar-c" role="search">
|
||||
<div id="search-data" class="ui-input-search ui-shadow-inset ui-btn-corner-all ui-btn-shadow ui-icon-searchfield ui-body-c">
|
||||
<input id="searchid" placeholder="Filter items..." data-type="search" class="ui-input-text ui-body-null" autosearch="true" setTimeDefault="700"/>
|
||||
</div>
|
||||
</form>
|
||||
<ul role="listbox" data-role="listview" class="ui-listview">
|
||||
<li data-theme="c" class="ui-btn ui-btn-icon-right ui-li ui-btn-up-c" t-foreach="records" t-as="record">
|
||||
<div class="ui-btn-inner ui-li">
|
||||
<div class="ui-btn-text">
|
||||
<a id="list-id" t-att-data-id="record[0]" href="#" class="ui-link-inherit">
|
||||
<span><t t-esc="record[1]"/></span>
|
||||
</a>
|
||||
</div>
|
||||
<span class="ui-icon ui-icon-arrow-r"></span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="FormView">
|
||||
<div role="main" class="ui-content" data-role="content">
|
||||
<form>
|
||||
<t t-foreach="get_fields" t-as="field">
|
||||
<div data-role="fieldcontain">
|
||||
<t t-if="fields[field.attrs.name].type!='one2many' and fields[field.attrs.name].type!='many2many'" >
|
||||
<label class="ui-input-text">
|
||||
<span>
|
||||
<t t-if="!(field.attrs.string)" t-esc="fields[field.attrs.name].string"></t>
|
||||
<t t-if="field.attrs.string" t-esc="field.attrs.string"></t>
|
||||
</span>:
|
||||
</label>
|
||||
</t>
|
||||
<t t-if="fields[field.attrs.name].type == 'char'">
|
||||
<t t-if="values[field.attrs.name]">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" t-att-value="values[field.attrs.name]"/><br/>
|
||||
</t>
|
||||
<t t-if="!(values[field.attrs.name])">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" value=""/><br/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="fields[field.attrs.name].type == 'boolean'">
|
||||
<t t-if="values[field.attrs.name]">
|
||||
<input type="checkbox" checked="yes"/><br/>
|
||||
</t>
|
||||
<t t-if="!(values[field.attrs.name])">
|
||||
<input type="checkbox"/><br/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="fields[field.attrs.name].type == 'text'">
|
||||
<textarea style="width:100%;" rows="8" name="textarea" id="textarea"></textarea><br/>
|
||||
</t>
|
||||
<t t-if="fields[field.attrs.name].type == 'float'">
|
||||
<t t-if="values[field.attrs.name]">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" t-att-value="values[field.attrs.name]"/><br/>
|
||||
</t>
|
||||
<t t-if="!(values[field.attrs.name])">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" value=""/><br/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="fields[field.attrs.name].type == 'date'">
|
||||
<t t-if="values[field.attrs.name]">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" t-att-value="values[field.attrs.name]"/><br/>
|
||||
</t>
|
||||
<t t-if="!(values[field.attrs.name])">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" value=""/><br/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="fields[field.attrs.name].type == 'datetime'">
|
||||
<t t-if="values[field.attrs.name]">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" t-att-value="values[field.attrs.name]"/><br/>
|
||||
</t>
|
||||
<t t-if="!(values[field.attrs.name])">
|
||||
<input class="ui-input-text ui-body-null ui-corner-all ui-shadow-inset ui-body-c" type="text" value=""/><br/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="fields[field.attrs.name].type == 'selection'">
|
||||
<div class="ui-select">
|
||||
<div data-theme="c" class="ui-btn ui-btn-icon-right ui-btn-corner-all ui-shadow ui-btn-up-c">
|
||||
<span class="ui-btn-inner ui-btn-corner-all">
|
||||
<span class="ui-btn-text">
|
||||
<t t-if="values[field.attrs.name]">
|
||||
<t t-foreach="fields[field.attrs.name].selection" t-as="opt">
|
||||
<t t-if="opt[0] == (values[field.attrs.name])">
|
||||
<t t-esc="opt[1]"/>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</span>
|
||||
<span class="ui-icon ui-icon-arrow-d ui-icon-shadow"></span>
|
||||
</span>
|
||||
|
||||
<select t-att-id="'selection_'+fields[field.attrs.name].string">
|
||||
<t t-foreach="fields[field.attrs.name].selection" t-as="opt">
|
||||
<option t-att-value="opt[0]"><t t-esc="opt[1]"/></option>
|
||||
</t>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="fields[field.attrs.name].type == 'many2one'">
|
||||
|
||||
<div class="ui-select">
|
||||
<div data-theme="c" class="ui-btn ui-btn-icon-right ui-btn-corner-all ui-shadow ui-btn-up-c">
|
||||
<span class="ui-btn-inner ui-btn-corner-all">
|
||||
<span class="ui-btn-text">
|
||||
<t t-if="values[field.attrs.name]">
|
||||
<t t-esc="values[field.attrs.name][1]"/>
|
||||
</t>
|
||||
</span>
|
||||
<span class="ui-icon ui-icon-arrow-d ui-icon-shadow"></span>
|
||||
</span>
|
||||
|
||||
<select t-att-id="'selection_'+fields[field.attrs.name].string">
|
||||
<t t-if="fields[field.attrs.name].selection">
|
||||
<t t-foreach="fields[field.attrs.name].selection" t-as="opt">
|
||||
<t t-if="values[field.attrs.name]==opt[0]">
|
||||
<option t-att-value="opt[0]" selected="true" ><t t-esc="opt[1]"/></option>
|
||||
</t>
|
||||
<t t-if="values[field.attrs.name]!=opt[0]">
|
||||
<option t-att-value="opt[0]" ><t t-esc="opt[1]"/></option>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="fields[field.attrs.name].type == 'one2many'">
|
||||
<div class="info ui-collapsible-contain" data-collapsed="true" data-role="collapsible">
|
||||
<h1 class="ui-collapsible-heading">
|
||||
<a class="ui-collapsible-heading-toggle ui-btn ui-btn-icon-left ui-shadow ui-corner-all ui-btn-up-c" href="#" data-theme="c" t-id="page.attrs.string">
|
||||
<span class="ui-btn-inner ui-corner-all">
|
||||
<span class="ui-btn-text">
|
||||
<t t-esc="til"></t>
|
||||
<!-- <span class="ui-collapsible-heading-status"></span> -->
|
||||
</span>
|
||||
<span data-theme="d" class="ui-btn ui-btn-icon-left ui-btn-corner-all ui-shadow ui-btn-up-d">
|
||||
<span class="ui-btn-inner ui-btn-corner-all ui-corner-all">
|
||||
<span class="ui-btn-text"></span>
|
||||
<span class="ui-icon ui-icon-shadow ui-icon-plus"></span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
<div class="ui-collapsible-content ui-collapsible-content-collapsed" aria-hidden="true">
|
||||
<div class="detail"></div>
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="notebooks">
|
||||
<t t-foreach="notebooks.children" t-as="page">
|
||||
<div class="info ui-collapsible-contain" data-collapsed="true" data-role="collapsible">
|
||||
<h1 class="ui-collapsible-heading">
|
||||
<a class="ui-collapsible-heading-toggle ui-btn ui-btn-icon-left ui-shadow ui-corner-all ui-btn-up-c" href="#" data-theme="c" t-id="page.attrs.string">
|
||||
<span class="ui-btn-inner ui-corner-all">
|
||||
<span class="ui-btn-text">
|
||||
<t t-esc="page.attrs.string"></t>
|
||||
<!-- <span class="ui-collapsible-heading-status"></span> -->
|
||||
</span>
|
||||
<span data-theme="d" class="ui-btn ui-btn-icon-left ui-btn-corner-all ui-shadow ui-btn-up-d">
|
||||
<span class="ui-btn-inner ui-btn-corner-all ui-corner-all">
|
||||
<span class="ui-btn-text"></span>
|
||||
<span class="ui-icon ui-icon-shadow ui-icon-plus"></span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
<div class="ui-collapsible-content ui-collapsible-content-collapsed" aria-hidden="true">
|
||||
<div class="detail"></div>
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</form>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
||||
@@ -338,10 +338,10 @@ replace ``addons`` by the directory in which your own addon lives.
|
||||
Python
|
||||
++++++
|
||||
|
||||
.. autoclass:: openerpweb.openerpweb.OpenERPSession
|
||||
.. autoclass:: base.common.backendrpc.OpenERPSession
|
||||
:members:
|
||||
|
||||
.. autoclass:: openerpweb.openerpweb.OpenERPModel
|
||||
.. autoclass:: base.common.backendrpc.OpenERPModel
|
||||
:members:
|
||||
|
||||
* Addons lifecycle (loading, execution, events, ...)
|
||||
|
||||
@@ -376,7 +376,7 @@ entirely.
|
||||
|
||||
.. note::
|
||||
|
||||
the list-wise deletion button (next to the record addition button)
|
||||
the list-wise deletion button (next to the record addition button)
|
||||
simply proxies to :js:func:`~openerp.base.ListView.do_delete` after
|
||||
obtaining all selected record ids, but it is possible to override it
|
||||
alone by replacing
|
||||
@@ -391,11 +391,12 @@ Python
|
||||
These classes should be moved to other sections of the doc as needed,
|
||||
probably.
|
||||
|
||||
.. automodule:: openerpweb.openerpweb
|
||||
:members: JsonRequest
|
||||
.. automodule:: base.common.dispatch
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
See also: :class:`~openerpweb.openerpweb.OpenERPSession`,
|
||||
:class:`~openerpweb.openerpweb.OpenERPModel`
|
||||
See also: :class:`~base.common.backendrpc.OpenERPSession`,
|
||||
:class:`~base.common.backendrpc.OpenERPModel`
|
||||
|
||||
.. automodule:: base.controllers.main
|
||||
:members:
|
||||
|
||||
+38
-2
@@ -1,7 +1,43 @@
|
||||
#!/usr/bin/env python
|
||||
import optparse
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
import openerpweb
|
||||
import werkzeug.serving
|
||||
|
||||
path_root = os.path.dirname(os.path.abspath(__file__))
|
||||
path_addons = os.path.join(path_root, 'addons')
|
||||
if path_addons not in sys.path:
|
||||
sys.path.insert(0, path_addons)
|
||||
|
||||
optparser = optparse.OptionParser()
|
||||
optparser.add_option("-p", "--port", dest="socket_port", default=8002,
|
||||
help="listening port", type="int", metavar="NUMBER")
|
||||
optparser.add_option("-s", "--session-path", dest="session_storage",
|
||||
default=os.path.join(tempfile.gettempdir(), "oe-sessions"),
|
||||
help="directory used for session storage", metavar="DIR")
|
||||
optparser.add_option("--server-host", dest="server_host",
|
||||
default='127.0.0.1', help="OpenERP server hostname", metavar="HOST")
|
||||
optparser.add_option("--server-port", dest="server_port", default=8069,
|
||||
help="OpenERP server port", type="int", metavar="NUMBER")
|
||||
optparser.add_option("--db-filter", dest="dbfilter", default='.*',
|
||||
help="Filter listed database", metavar="REGEXP")
|
||||
optparser.add_option('--addons-path', dest='addons_path', default=path_addons,
|
||||
help="Path do addons directory", metavar="PATH")
|
||||
optparser.add_option('--no-serve-static', dest='serve_static',
|
||||
default=True, action='store_false',
|
||||
help="Do not serve static files via this server")
|
||||
|
||||
import base.common.dispatch
|
||||
|
||||
if __name__ == "__main__":
|
||||
openerpweb.main(sys.argv)
|
||||
(options, args) = optparser.parse_args(sys.argv[1:])
|
||||
|
||||
os.environ["TZ"] = "UTC"
|
||||
app = base.common.dispatch.Root(options)
|
||||
|
||||
werkzeug.serving.run_simple(
|
||||
'0.0.0.0', options.socket_port, app,
|
||||
use_reloader=True, threaded=True)
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
from openerpweb import *
|
||||
@@ -1,497 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
import datetime
|
||||
import urllib
|
||||
import dateutil.relativedelta
|
||||
import functools
|
||||
import optparse
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import traceback
|
||||
import uuid
|
||||
import xmlrpclib
|
||||
|
||||
import cherrypy
|
||||
import cherrypy.lib.static
|
||||
import simplejson
|
||||
|
||||
import nonliterals
|
||||
import logging
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# Globals
|
||||
#-----------------------------------------------------------
|
||||
|
||||
path_root = os.path.dirname(os.path.dirname(os.path.normpath(__file__)))
|
||||
path_addons = os.path.join(path_root, 'addons')
|
||||
cherrypy_root = None
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# Per Database Globals (might move into a pool if needed)
|
||||
#-----------------------------------------------------------
|
||||
|
||||
applicationsession = {}
|
||||
addons_module = {}
|
||||
addons_manifest = {}
|
||||
controllers_class = {}
|
||||
controllers_object = {}
|
||||
controllers_path = {}
|
||||
|
||||
#----------------------------------------------------------
|
||||
# OpenERP Client Library
|
||||
#----------------------------------------------------------
|
||||
class OpenERPUnboundException(Exception):
|
||||
pass
|
||||
|
||||
class OpenERPConnector(object):
|
||||
pass
|
||||
|
||||
class OpenERPAuth(object):
|
||||
pass
|
||||
|
||||
class OpenERPModel(object):
|
||||
def __init__(self, session, model):
|
||||
self._session = session
|
||||
self._model = model
|
||||
|
||||
def __getattr__(self, name):
|
||||
return lambda *l:self._session.execute(self._model, name, *l)
|
||||
|
||||
class OpenERPSession(object):
|
||||
"""
|
||||
An OpenERP RPC session, a given user can own multiple such sessions
|
||||
in a web session.
|
||||
|
||||
.. attribute:: context
|
||||
|
||||
The session context, a ``dict``. Can be reloaded by calling
|
||||
:meth:`openerpweb.openerpweb.OpenERPSession.get_context`
|
||||
|
||||
.. attribute:: domains_store
|
||||
|
||||
A ``dict`` matching domain keys to evaluable (but non-literal) domains.
|
||||
|
||||
Used to store references to non-literal domains which need to be
|
||||
round-tripped to the client browser.
|
||||
"""
|
||||
def __init__(self, server='127.0.0.1', port=8069, model_factory=OpenERPModel):
|
||||
self._server = server
|
||||
self._port = port
|
||||
self._db = False
|
||||
self._uid = False
|
||||
self._login = False
|
||||
self._password = False
|
||||
self.model_factory = model_factory
|
||||
self._locale = 'en_US'
|
||||
self.context = {}
|
||||
self.contexts_store = {}
|
||||
self.domains_store = {}
|
||||
self._lang = {}
|
||||
self.remote_timezone = 'utc'
|
||||
self.client_timezone = False
|
||||
|
||||
def proxy(self, service):
|
||||
s = xmlrpclib.ServerProxy('http://%s:%s/xmlrpc/%s' % (self._server, self._port, service))
|
||||
return s
|
||||
|
||||
def bind(self, db, uid, password):
|
||||
self._db = db
|
||||
self._uid = uid
|
||||
self._password = password
|
||||
|
||||
def login(self, db, login, password):
|
||||
uid = self.proxy('common').login(db, login, password)
|
||||
self.bind(db, uid, password)
|
||||
self._login = login
|
||||
|
||||
if uid: self.get_context()
|
||||
return uid
|
||||
|
||||
def assert_valid(self):
|
||||
"""
|
||||
Ensures this session is valid (logged into the openerp server)
|
||||
"""
|
||||
if not (self._db and self._uid and self._password):
|
||||
raise OpenERPUnboundException()
|
||||
|
||||
def execute(self, model, func, *l, **d):
|
||||
self.assert_valid()
|
||||
r = self.proxy('object').execute(self._db, self._uid, self._password, model, func, *l, **d)
|
||||
return r
|
||||
|
||||
def exec_workflow(self, model, id, signal):
|
||||
self.assert_valid()
|
||||
r = self.proxy('object').exec_workflow(self._db, self._uid, self._password, model, signal, id)
|
||||
return r
|
||||
|
||||
def model(self, model):
|
||||
""" Get an RPC proxy for the object ``model``, bound to this session.
|
||||
|
||||
:param model: an OpenERP model name
|
||||
:type model: str
|
||||
:rtype: :class:`openerpweb.openerpweb.OpenERPModel`
|
||||
"""
|
||||
return self.model_factory(self, model)
|
||||
|
||||
def get_context(self):
|
||||
""" Re-initializes the current user's session context (based on
|
||||
his preferences) by calling res.users.get_context() with the old
|
||||
context
|
||||
|
||||
:returns: the new context
|
||||
"""
|
||||
assert self._uid, "The user needs to be logged-in to initialize his context"
|
||||
self.context = self.model('res.users').context_get(self.context)
|
||||
self.context = self.context or {}
|
||||
|
||||
self.client_timezone = self.context.get("tz", False)
|
||||
# invalid code, anyway we decided the server will be in UTC
|
||||
#if self.client_timezone:
|
||||
# self.remote_timezone = self.execute('common', 'timezone_get')
|
||||
|
||||
self._locale = self.context.get('lang','en_US')
|
||||
lang_ids = self.execute('res.lang','search', [('code', '=', self._locale)])
|
||||
if lang_ids:
|
||||
self._lang = self.execute('res.lang', 'read',lang_ids[0], [])
|
||||
return self.context
|
||||
|
||||
@property
|
||||
def base_eval_context(self):
|
||||
""" Default evaluation context for the session.
|
||||
|
||||
Used to evaluate contexts and domains.
|
||||
"""
|
||||
base = dict(
|
||||
uid=self._uid,
|
||||
current_date=datetime.date.today().strftime('%Y-%m-%d'),
|
||||
time=time,
|
||||
datetime=datetime,
|
||||
relativedelta=dateutil.relativedelta.relativedelta
|
||||
)
|
||||
base.update(self.context)
|
||||
return base
|
||||
|
||||
def evaluation_context(self, context=None):
|
||||
""" Returns the session's evaluation context, augmented with the
|
||||
provided context if any.
|
||||
|
||||
:param dict context: to add merge in the session's base eval context
|
||||
:returns: the augmented context
|
||||
:rtype: dict
|
||||
"""
|
||||
d = dict(self.base_eval_context)
|
||||
if context:
|
||||
d.update(context)
|
||||
d['context'] = d
|
||||
return d
|
||||
|
||||
def eval_context(self, context_to_eval, context=None):
|
||||
""" Evaluates the provided context_to_eval in the context (haha) of
|
||||
the context. Also merges the evaluated context with the session's context.
|
||||
|
||||
:param context_to_eval: a context to evaluate. Must be a dict or a
|
||||
non-literal context. If it's a dict, will be
|
||||
returned as-is
|
||||
:type context_to_eval: openerpweb.nonliterals.Context
|
||||
:returns: the evaluated context
|
||||
:rtype: dict
|
||||
|
||||
:raises: ``TypeError`` if ``context_to_eval`` is neither a dict nor
|
||||
a Context
|
||||
"""
|
||||
ctx = dict(
|
||||
self.base_eval_context,
|
||||
**(context or {}))
|
||||
|
||||
# adding the context of the session to send to the openerp server
|
||||
ccontext = nonliterals.CompoundContext(self.context, context_to_eval or {})
|
||||
ccontext.session = self
|
||||
return ccontext.evaluate(ctx)
|
||||
|
||||
def eval_domain(self, domain, context=None):
|
||||
""" Evaluates the provided domain using the provided context
|
||||
(merged with the session's evaluation context)
|
||||
|
||||
:param domain: an OpenERP domain as a list or as a
|
||||
:class:`openerpweb.nonliterals.Domain` instance
|
||||
|
||||
In the second case, it will be evaluated and returned.
|
||||
:type domain: openerpweb.nonliterals.Domain
|
||||
:param dict context: the context to use in the evaluation, if any.
|
||||
:returns: the evaluated domain
|
||||
:rtype: list
|
||||
|
||||
:raises: ``TypeError`` if ``domain`` is neither a list nor a Domain
|
||||
"""
|
||||
if isinstance(domain, list):
|
||||
return domain
|
||||
|
||||
cdomain = nonliterals.CompoundDomain(domain)
|
||||
cdomain.session = self
|
||||
return cdomain.evaluate(context or {})
|
||||
|
||||
#----------------------------------------------------------
|
||||
# OpenERP Web RequestHandler
|
||||
#----------------------------------------------------------
|
||||
class CherryPyRequest(object):
|
||||
""" CherryPy request handling
|
||||
"""
|
||||
def init(self,params):
|
||||
self.params = params
|
||||
# Move cherrypy thread local objects to attributes
|
||||
self.applicationsession = applicationsession
|
||||
self.httprequest = cherrypy.request
|
||||
self.httpresponse = cherrypy.response
|
||||
self.httpsession = cherrypy.session
|
||||
self.httpsession_id = "cookieid"
|
||||
# OpenERP session setup
|
||||
self.session_id = self.params.pop("session_id", None) or uuid.uuid4().hex
|
||||
host = cherrypy.config['openerp.server.host']
|
||||
port = cherrypy.config['openerp.server.port']
|
||||
self.session = self.httpsession.setdefault(self.session_id, OpenERPSession(host, port))
|
||||
# Request attributes
|
||||
self.context = self.params.pop('context', None)
|
||||
self.debug = self.params.pop('debug',False) != False
|
||||
|
||||
class JsonRequest(CherryPyRequest):
|
||||
""" JSON-RPC2 over HTTP.
|
||||
|
||||
Sucessful request::
|
||||
|
||||
--> {"jsonrpc": "2.0",
|
||||
"method": "call",
|
||||
"params": {"session_id": "SID",
|
||||
"context": {},
|
||||
"arg1": "val1" },
|
||||
"id": null}
|
||||
|
||||
<-- {"jsonrpc": "2.0",
|
||||
"result": { "res1": "val1" },
|
||||
"id": null}
|
||||
|
||||
Request producing a error::
|
||||
|
||||
--> {"jsonrpc": "2.0",
|
||||
"method": "call",
|
||||
"params": {"session_id": "SID",
|
||||
"context": {},
|
||||
"arg1": "val1" },
|
||||
"id": null}
|
||||
|
||||
<-- {"jsonrpc": "2.0",
|
||||
"error": {"code": 1,
|
||||
"message": "End user error message.",
|
||||
"data": {"code": "codestring",
|
||||
"debug": "traceback" } },
|
||||
"id": null}
|
||||
|
||||
"""
|
||||
|
||||
def dispatch(self, controller, method, requestf=None, request=None):
|
||||
""" Calls the method asked for by the JSON-RPC2 request
|
||||
|
||||
:param controller: the instance of the controller which received the request
|
||||
:param method: the method which received the request
|
||||
:param requestf: a file-like object containing an encoded JSON-RPC2 request
|
||||
:param request: a JSON-RPC2 request
|
||||
|
||||
:returns: an utf8 encoded JSON-RPC2 reply
|
||||
"""
|
||||
response = {"jsonrpc": "2.0" }
|
||||
error = None
|
||||
try:
|
||||
# Read POST content or POST Form Data named "request"
|
||||
if requestf:
|
||||
self.jsonrequest = simplejson.load(requestf, object_hook=nonliterals.non_literal_decoder)
|
||||
else:
|
||||
self.jsonrequest = simplejson.loads(request, object_hook=nonliterals.non_literal_decoder)
|
||||
self.init(self.jsonrequest.get("params", {}))
|
||||
if self.debug or 1:
|
||||
print "--> %s.%s %s" % (controller.__class__.__name__, method.__name__, self.jsonrequest)
|
||||
response['id'] = self.jsonrequest.get('id')
|
||||
response["result"] = method(controller, self, **self.params)
|
||||
except OpenERPUnboundException:
|
||||
error = {
|
||||
'code': 100,
|
||||
'message': "OpenERP Session Invalid",
|
||||
'data': {
|
||||
'type': 'session_invalid',
|
||||
'debug': traceback.format_exc()
|
||||
}
|
||||
}
|
||||
except xmlrpclib.Fault, e:
|
||||
error = {
|
||||
'code': 200,
|
||||
'message': "OpenERP Server Error",
|
||||
'data': {
|
||||
'type': 'server_exception',
|
||||
'fault_code': e.faultCode,
|
||||
'debug': "Client %s\nServer %s" % (
|
||||
"".join(traceback.format_exception("", None, sys.exc_traceback)), e.faultString)
|
||||
}
|
||||
}
|
||||
except Exception:
|
||||
cherrypy.log("An error occured while handling a json request",
|
||||
severity=logging.ERROR, traceback=True)
|
||||
error = {
|
||||
'code': 300,
|
||||
'message': "OpenERP WebClient Error",
|
||||
'data': {
|
||||
'type': 'client_exception',
|
||||
'debug': "Client %s" % traceback.format_exc()
|
||||
}
|
||||
}
|
||||
if error:
|
||||
response["error"] = error
|
||||
|
||||
if self.debug or 1:
|
||||
print "<--", response
|
||||
print
|
||||
|
||||
content = simplejson.dumps(response, cls=nonliterals.NonLiteralEncoder)
|
||||
cherrypy.response.headers['Content-Type'] = 'application/json'
|
||||
cherrypy.response.headers['Content-Length'] = len(content)
|
||||
return content
|
||||
|
||||
def jsonrequest(f):
|
||||
@cherrypy.expose
|
||||
@functools.wraps(f)
|
||||
def json_handler(controller):
|
||||
return JsonRequest().dispatch(controller, f, requestf=cherrypy.request.body)
|
||||
return json_handler
|
||||
|
||||
class HttpRequest(CherryPyRequest):
|
||||
""" Regular GET/POST request
|
||||
"""
|
||||
def dispatch(self, controller, method, **kw):
|
||||
self.init(kw)
|
||||
akw = {}
|
||||
for key in kw.keys():
|
||||
if isinstance(kw[key], basestring) and len(kw[key]) < 1024:
|
||||
akw[key] = kw[key]
|
||||
else:
|
||||
akw[key] = type(kw[key])
|
||||
if self.debug or 1:
|
||||
print "%s --> %s.%s %r" % (self.httprequest.method, controller.__class__.__name__, method.__name__, akw)
|
||||
r = method(controller, self, **kw)
|
||||
if self.debug or 1:
|
||||
print "<--", 'size:', len(r)
|
||||
print
|
||||
return r
|
||||
|
||||
def httprequest(f):
|
||||
# check cleaner wrapping:
|
||||
# functools.wraps(f)(lambda x: JsonRequest().dispatch(x, f))
|
||||
def http_handler(controller,*l, **kw):
|
||||
return HttpRequest().dispatch(controller, f, **kw)
|
||||
http_handler.exposed = 1
|
||||
return http_handler
|
||||
|
||||
#-----------------------------------------------------------
|
||||
# Cherrypy stuff
|
||||
#-----------------------------------------------------------
|
||||
|
||||
class ControllerType(type):
|
||||
def __init__(cls, name, bases, attrs):
|
||||
super(ControllerType, cls).__init__(name, bases, attrs)
|
||||
controllers_class["%s.%s" % (cls.__module__, cls.__name__)] = cls
|
||||
|
||||
class Controller(object):
|
||||
__metaclass__ = ControllerType
|
||||
|
||||
class Root(object):
|
||||
def __init__(self):
|
||||
self.addons = {}
|
||||
self._load_addons()
|
||||
|
||||
def _load_addons(self):
|
||||
if path_addons not in sys.path:
|
||||
sys.path.insert(0, path_addons)
|
||||
for i in os.listdir(path_addons):
|
||||
if i not in addons_module:
|
||||
manifest_path = os.path.join(path_addons, i, '__openerp__.py')
|
||||
if os.path.isfile(manifest_path):
|
||||
manifest = eval(open(manifest_path).read())
|
||||
print "Loading", i
|
||||
m = __import__(i)
|
||||
addons_module[i] = m
|
||||
addons_manifest[i] = manifest
|
||||
for k, v in controllers_class.items():
|
||||
if k not in controllers_object:
|
||||
o = v()
|
||||
controllers_object[k] = o
|
||||
if hasattr(o, '_cp_path'):
|
||||
controllers_path[o._cp_path] = o
|
||||
|
||||
def default(self, *l, **kw):
|
||||
#print "default",l,kw
|
||||
# handle static files
|
||||
if len(l) > 2 and l[1] == 'static':
|
||||
# sanitize path
|
||||
p = os.path.normpath(os.path.join(*l))
|
||||
return cherrypy.lib.static.serve_file(os.path.join(path_addons, p))
|
||||
elif len(l) > 1:
|
||||
for i in range(len(l), 1, -1):
|
||||
ps = "/" + "/".join(l[0:i])
|
||||
if ps in controllers_path:
|
||||
c = controllers_path[ps]
|
||||
rest = l[i:] or ['index']
|
||||
meth = rest[0]
|
||||
m = getattr(c, meth)
|
||||
if getattr(m, 'exposed', 0):
|
||||
print "Calling", ps, c, meth, m
|
||||
return m(**kw)
|
||||
raise cherrypy.NotFound('/' + '/'.join(l))
|
||||
elif l and l[0] == 'mobile':
|
||||
#for the mobile web client we are supposed to use a different url to just add '/mobile'
|
||||
raise cherrypy.HTTPRedirect('/web_mobile/static/src/web_mobile.html', 301)
|
||||
else:
|
||||
if kw:
|
||||
qs = '?' + urllib.urlencode(kw)
|
||||
else:
|
||||
qs = ''
|
||||
raise cherrypy.HTTPRedirect('/base/webclient/home' + qs, 301)
|
||||
default.exposed = True
|
||||
|
||||
def main(argv):
|
||||
# change the timezone of the program to the OpenERP server's assumed timezone
|
||||
os.environ["TZ"] = "UTC"
|
||||
|
||||
DEFAULT_CONFIG = {
|
||||
'server.socket_host': '0.0.0.0',
|
||||
'tools.sessions.on': True,
|
||||
'tools.sessions.storage_type': 'file',
|
||||
'tools.sessions.timeout': 60
|
||||
}
|
||||
|
||||
# Parse config
|
||||
op = optparse.OptionParser()
|
||||
op.add_option("-p", "--port", dest="server.socket_port", default=8002, help="listening port", type="int", metavar="NUMBER")
|
||||
op.add_option("-s", "--session-path", dest="tools.sessions.storage_path", default=os.path.join(tempfile.gettempdir(), "cpsessions"), help="directory used for session storage", metavar="DIR")
|
||||
op.add_option("--server-host", dest="openerp.server.host", default='127.0.0.1', help="OpenERP server hostname", metavar="HOST")
|
||||
op.add_option("--server-port", dest="openerp.server.port", default=8069, help="OpenERP server port", type="int", metavar="NUMBER")
|
||||
op.add_option("--db-filter", dest="openerp.dbfilter", default='.*', help="Filter listed database", metavar="REGEXP")
|
||||
(o, args) = op.parse_args(argv[1:])
|
||||
o = vars(o)
|
||||
for k in o.keys():
|
||||
if o[k] is None:
|
||||
del(o[k])
|
||||
|
||||
# Setup and run cherrypy
|
||||
cherrypy.tree.mount(Root())
|
||||
|
||||
cherrypy.config.update(config=DEFAULT_CONFIG)
|
||||
if os.path.exists(os.path.join(path_root,'openerp-web.cfg')):
|
||||
cherrypy.config.update(os.path.join(path_root,'openerp-web.cfg'))
|
||||
if os.path.exists(os.path.expanduser('~/.openerp_webrc')):
|
||||
cherrypy.config.update(os.path.expanduser('~/.openerp_webrc'))
|
||||
cherrypy.config.update(o)
|
||||
|
||||
if not os.path.exists(cherrypy.config['tools.sessions.storage_path']):
|
||||
os.makedirs(cherrypy.config['tools.sessions.storage_path'], 0700)
|
||||
|
||||
cherrypy.server.subscribe()
|
||||
cherrypy.engine.start()
|
||||
cherrypy.engine.block()
|
||||
|
||||
Reference in New Issue
Block a user