diff --git a/.bzrignore b/.bzrignore index 62f8a05c90f..a797d0cfc05 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1,23 +1,12 @@ -*.pyc -.*.swp -.bzrignore -openerp/addons/* -openerp/filestore* -.Python -include -lib -bin/activate -bin/activate_this.py -bin/easy_install -bin/easy_install-2.6 -bin/pip -bin/python -bin/python2.6 -*.pyc -*.pyo +.* +*.egg-info +*.orig +*.vim build/ -bin/yolk -bin/pil*.py -.project -.pydevproject -.settings +RE:^bin/ +RE:^dist/ +RE:^include/ + +RE:^share/ +RE:^man/ +RE:^lib/ diff --git a/addons/web/__openerp__.py b/addons/web/__openerp__.py index 41a58cd3a07..75c3bbd766f 100644 --- a/addons/web/__openerp__.py +++ b/addons/web/__openerp__.py @@ -7,7 +7,7 @@ This module provides the core of the OpenERP web client. """, "depends" : [], - 'active': True, + 'auto_install': True, 'post_load' : 'wsgi_postload', 'js' : [ "static/lib/datejs/globalization/en-US.js", @@ -15,7 +15,8 @@ "static/lib/datejs/parser.js", "static/lib/datejs/sugarpak.js", "static/lib/datejs/extras.js", - "static/lib/jquery/jquery-1.6.4.js", + #"static/lib/jquery/jquery-1.6.4.js", + "static/lib/jquery/jquery-1.7.2b1.js", "static/lib/jquery.MD5/jquery.md5.js", "static/lib/jquery.form/jquery.form.js", "static/lib/jquery.validate/jquery.validate.js", @@ -35,7 +36,8 @@ "static/lib/underscore/underscore.js", "static/lib/underscore/underscore.string.js", "static/lib/labjs/LAB.src.js", - "static/lib/py.parse/lib/py.js", + "static/lib/py.js/lib/py.js", + "static/lib/novajs/src/nova.js", "static/src/js/boot.js", "static/src/js/core.js", "static/src/js/dates.js", @@ -59,6 +61,7 @@ "static/lib/jquery.ui.timepicker/css/jquery-ui-timepicker-addon.css", "static/lib/jquery.ui.notify/css/ui.notify.css", "static/lib/jquery.tipsy/tipsy.css", + "static/src/css/base_old.css", "static/src/css/base.css", "static/src/css/data_export.css", "static/src/css/data_import.css", diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 6a143d58231..e074445187c 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -98,19 +98,72 @@ html_template = """ OpenERP + %(css)s %(js)s - + """ +def sass2scss(src): + # Validated by diff -u of sass2scss against: + # sass-convert -F sass -T scss openerp.sass openerp.scss + block = [] + sass = ('', block) + reComment = re.compile(r'//.*$') + reIndent = re.compile(r'^\s+') + reIgnore = re.compile(r'^\s*(//.*)?$') + reFixes = { re.compile(r'\(\((.*)\)\)') : r'(\1)', } + lastLevel = 0 + prevBlocks = {} + for l in src.split('\n'): + l = l.rstrip() + if reIgnore.search(l): continue + l = reComment.sub('', l) + l = l.rstrip() + indent = reIndent.match(l) + level = indent.end() if indent else 0 + l = l[level:] + if level>lastLevel: + prevBlocks[lastLevel] = block + newBlock = [] + block[-1] = (block[-1], newBlock) + block = newBlock + elif level=0: + out += indent+sass[0]+" {\n" + for e in sass[1]: + out += write(e, level+1) + if level>=0: + out = out.rstrip(" \n") + out += ' }\n' + if level==0: + out += "\n" + else: + out += indent+sass+";\n" + return out + return write(sass) + class WebClient(openerpweb.Controller): _cp_path = "/web/webclient" @@ -270,7 +323,6 @@ class WebClient(openerpweb.Controller): 'js': js, 'css': css, 'modules': simplejson.dumps(self.server_wide_modules(req)), - 'init': 'new s.web.WebClient().start();', } return r @@ -351,19 +403,14 @@ class Database(openerpweb.Controller): def get_list(self, req): proxy = req.session.proxy("db") dbs = proxy.list() - h = req.httprequest.headers['Host'].split(':')[0] + h = req.httprequest.environ['HTTP_HOST'].split(':')[0] d = h.split('.')[0] 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} - @openerpweb.jsonrequest - def progress(self, req, password, id): - return req.session.proxy('db').get_progress(password, id) - @openerpweb.jsonrequest def create(self, req, fields): - params = dict(map(operator.itemgetter('name', 'value'), fields)) create_attrs = ( params['super_admin_pwd'], @@ -373,17 +420,7 @@ class Database(openerpweb.Controller): params['create_admin_pwd'] ) - try: - return req.session.proxy("db").create(*create_attrs) - except xmlrpclib.Fault, e: - if e.faultCode and isinstance(e.faultCode, str)\ - and e.faultCode.split(':')[0] == 'AccessDenied': - return {'error': e.faultCode, 'title': 'Database creation error'} - return { - 'error': "Could not create database '%s': %s" % ( - params['db_name'], e.faultString), - 'title': 'Database creation error' - } + return req.session.proxy("db").create_database(*create_attrs) @openerpweb.jsonrequest def drop(self, req, fields): @@ -435,6 +472,50 @@ class Database(openerpweb.Controller): return {'error': e.faultCode, 'title': 'Change Password'} return {'error': 'Error, password not changed !', 'title': 'Change Password'} +def topological_sort(modules): + """ Return a list of module names sorted so that their dependencies of the + modules are listed before the module itself + + modules is a dict of {module_name: dependencies} + + :param modules: modules to sort + :type modules: dict + :returns: list(str) + """ + + dependencies = set(itertools.chain.from_iterable(modules.itervalues())) + # incoming edge: dependency on other module (if a depends on b, a has an + # incoming edge from b, aka there's an edge from b to a) + # outgoing edge: other module depending on this one + + # [Tarjan 1976], http://en.wikipedia.org/wiki/Topological_sorting#Algorithms + #L ← Empty list that will contain the sorted nodes + L = [] + #S ← Set of all nodes with no outgoing edges (modules on which no other + # module depends) + S = set(module for module in modules if module not in dependencies) + + visited = set() + #function visit(node n) + def visit(n): + #if n has not been visited yet then + if n not in visited: + #mark n as visited + visited.add(n) + #change: n not web module, can not be resolved, ignore + if n not in modules: return + #for each node m with an edge from m to n do (dependencies of n) + for m in modules[n]: + #visit(m) + visit(m) + #add n to L + L.append(n) + #for each node n in S do + for n in S: + #visit(n) + visit(n) + return L + class Session(openerpweb.Controller): _cp_path = "/web/session" @@ -502,20 +583,32 @@ class Session(openerpweb.Controller): def modules(self, req): # Compute available candidates module loadable = openerpweb.addons_manifest - loaded = req.config.server_wide_modules + loaded = set(req.config.server_wide_modules) candidates = [mod for mod in loadable if mod not in loaded] - # Compute active true modules that might be on the web side only - active = set(name for name in candidates - if openerpweb.addons_manifest[name].get('active')) + # already installed modules have no dependencies + modules = dict.fromkeys(loaded, []) + + # Compute auto_install modules that might be on the web side only + modules.update((name, openerpweb.addons_manifest[name].get('depends', [])) + for name in candidates + if openerpweb.addons_manifest[name].get('auto_install')) # Retrieve database installed modules Modules = req.session.model('ir.module.module') - installed = set(module['name'] for module in Modules.search_read( - [('state','=','installed'), ('name','in', candidates)], ['name'])) + for module in Modules.search_read( + [('state','=','installed'), ('name','in', candidates)], + ['name', 'dependencies_id']): + deps = module.get('dependencies_id') + if deps: + dependencies = map( + operator.itemgetter('name'), + req.session.model('ir.module.module.dependency').read(deps, ['name'])) + modules[module['name']] = list( + set(modules.get(module['name'], []) + dependencies)) - # Merge both - return list(active | installed) + sorted_modules = topological_sort(modules) + return [module for module in sorted_modules if module not in loaded] @openerpweb.jsonrequest def eval_domain_and_context(self, req, contexts, domains, @@ -762,11 +855,13 @@ class Menu(openerpweb.Controller): Menus = s.model('ir.ui.menu') # If a menu action is defined use its domain to get the root menu items user_menu_id = s.model('res.users').read([s._uid], ['menu_id'], context)[0]['menu_id'] + + menu_domain = [('parent_id', '=', False)] if user_menu_id: - menu_domain = s.model('ir.actions.act_window').read([user_menu_id[0]], ['domain'], context)[0]['domain'] - menu_domain = ast.literal_eval(menu_domain) - else: - menu_domain = [('parent_id', '=', False)] + domain_string = s.model('ir.actions.act_window').read([user_menu_id[0]], ['domain'], context)[0]['domain'] + if domain_string: + menu_domain = ast.literal_eval(domain_string) + return Menus.search(menu_domain, 0, False, False, context) def do_load(self, req): @@ -780,13 +875,13 @@ class Menu(openerpweb.Controller): context = req.session.eval_context(req.context) Menus = req.session.model('ir.ui.menu') - menu_roots = Menus.read(self.do_get_user_roots(req), ['name', 'sequence', 'parent_id'], context) + menu_roots = Menus.read(self.do_get_user_roots(req), ['name', 'sequence', 'parent_id', 'action'], context) menu_root = {'id': False, 'name': 'root', 'parent_id': [-1, ''], 'children' : menu_roots} # menus are loaded fully unlike a regular tree view, cause there are a # limited number of items (752 when all 6.1 addons are installed) menu_ids = Menus.search([], 0, False, False, context) - menu_items = Menus.read(menu_ids, ['name', 'sequence', 'parent_id'], context) + menu_items = Menus.read(menu_ids, ['name', 'sequence', 'parent_id', 'action'], context) # adds roots at the end of the sequence, so that they will overwrite # equivalent menu items from full menu read when put into id:item # mapping, resulting in children being correctly set on the roots. @@ -1179,10 +1274,15 @@ class SearchView(View): filters = Model.get_filters(model) for filter in filters: try: - filter["context"] = req.session.eval_context( - parse_context(filter["context"], req.session)) - filter["domain"] = req.session.eval_domain( - parse_domain(filter["domain"], req.session)) + parsed_context = parse_context(filter["context"], req.session) + filter["context"] = (parsed_context + if not isinstance(parsed_context, common.nonliterals.BaseContext) + else req.session.eval_context(parsed_context)) + + parsed_domain = parse_domain(filter["domain"], req.session) + filter["domain"] = (parsed_domain + if not isinstance(parsed_domain, common.nonliterals.BaseDomain) + else req.session.eval_domain(parsed_domain)) except Exception: logger.exception("Failed to parse custom filter %s in %s", filter['name'], model) @@ -1215,6 +1315,7 @@ class SearchView(View): ctx = common.nonliterals.CompoundContext(context_to_save) ctx.session = req.session ctx = ctx.evaluate() + ctx['dashboard_merge_domains_contexts'] = False # TODO: replace this 6.1 workaround by attribute on domain = common.nonliterals.CompoundDomain(domain) domain.session = req.session domain = domain.evaluate() @@ -1230,7 +1331,7 @@ class SearchView(View): if board and 'arch' in board: xml = ElementTree.fromstring(board['arch']) column = xml.find('./board/column') - if column: + if column is not None: new_action = ElementTree.Element('action', { 'name' : str(action_id), 'string' : name, diff --git a/addons/web/i18n/es.po b/addons/web/i18n/es.po index fc86d3f1368..586fa1574cd 100644 --- a/addons/web/i18n/es.po +++ b/addons/web/i18n/es.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-14 15:27+0100\n" -"PO-Revision-Date: 2012-02-15 07:48+0000\n" -"Last-Translator: Jorge L Tupac-Yupanqui \n" +"PO-Revision-Date: 2012-02-16 11:00+0000\n" +"Last-Translator: Vicente \n" "Language-Team: Spanish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-16 05:21+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:172 @@ -657,7 +657,7 @@ msgstr "Traducciones" #. openerp-web #: addons/web/static/src/xml/base.xml:44 addons/web/static/src/xml/base.xml:315 msgid "Powered by" -msgstr "Desarrollado por" +msgstr "Con tecnoloxía de" #. openerp-web #: addons/web/static/src/xml/base.xml:44 addons/web/static/src/xml/base.xml:315 @@ -1118,7 +1118,7 @@ msgstr "Limpiar" #: addons/web/static/src/xml/base.xml:1172 #: addons/web/static/src/xml/base.xml:1223 msgid "Uploading ..." -msgstr "Subiendo ..." +msgstr "Cargando..." #. openerp-web #: addons/web/static/src/xml/base.xml:1200 diff --git a/addons/web/i18n/es_CR.po b/addons/web/i18n/es_CR.po index 5696e9d855c..5e358001e68 100644 --- a/addons/web/i18n/es_CR.po +++ b/addons/web/i18n/es_CR.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2012-02-14 15:27+0100\n" -"PO-Revision-Date: 2012-02-10 20:39+0000\n" +"PO-Revision-Date: 2012-02-16 19:06+0000\n" "Last-Translator: Freddy Gonzalez \n" "Language-Team: Spanish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-15 05:43+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" "Language: es\n" #. openerp-web @@ -194,7 +194,7 @@ msgstr "Descargar \"%s\"" #. openerp-web #: addons/web/static/src/js/search.js:191 msgid "Filter disabled due to invalid syntax" -msgstr "" +msgstr "Filtro desactivado debido a sintaxis inválida" #. openerp-web #: addons/web/static/src/js/search.js:237 @@ -384,12 +384,12 @@ msgstr "Ver Editor de%d -%s" #. openerp-web #: addons/web/static/src/js/view_editor.js:367 msgid "Inherited View" -msgstr "" +msgstr "Vista heredada" #. openerp-web #: addons/web/static/src/js/view_editor.js:371 msgid "Do you really wants to create an inherited view here?" -msgstr "" +msgstr "¿Realmente desea crear una vista heredada aquí?" #. openerp-web #: addons/web/static/src/js/view_editor.js:381 diff --git a/addons/web/i18n/fi.po b/addons/web/i18n/fi.po new file mode 100644 index 00000000000..ded41159f14 --- /dev/null +++ b/addons/web/i18n/fi.po @@ -0,0 +1,1458 @@ +# Finnish translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-02-20 11:03+0000\n" +"Last-Translator: Juha Kotamäki \n" +"Language-Team: Finnish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-02-21 06:10+0000\n" +"X-Generator: Launchpad (build 14838)\n" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:172 +#: addons/web/static/src/js/chrome.js:198 +#: addons/web/static/src/js/chrome.js:414 +#: addons/web/static/src/js/view_form.js:419 +#: addons/web/static/src/js/view_form.js:1233 +#: addons/web/static/src/xml/base.xml:1695 +msgid "Ok" +msgstr "Ok" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:180 +msgid "Send OpenERP Enterprise Report" +msgstr "Lähetä OpenERP Yritys Raportti" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:194 +msgid "Dont send" +msgstr "Älä lähetä" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:256 +#, python-format +msgid "Loading (%d)" +msgstr "Ladataan (%d)" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:288 +msgid "Invalid database name" +msgstr "Virheellinen tietokannan nimi" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:483 +msgid "Backed" +msgstr "Varmistetaan" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:484 +msgid "Database backed up successfully" +msgstr "Tietokanta varmistettu onnistuneesti" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:527 +msgid "Restored" +msgstr "Palautettu" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:527 +msgid "Database restored successfully" +msgstr "Tietokanta palautettu onnistuneesti" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:708 +#: addons/web/static/src/xml/base.xml:359 +msgid "About" +msgstr "Tietoja" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:787 +#: addons/web/static/src/xml/base.xml:356 +msgid "Preferences" +msgstr "Asetukset" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:790 +#: addons/web/static/src/js/search.js:239 +#: addons/web/static/src/js/search.js:288 +#: addons/web/static/src/js/view_editor.js:95 +#: addons/web/static/src/js/view_editor.js:836 +#: addons/web/static/src/js/view_editor.js:962 +#: addons/web/static/src/js/view_form.js:1228 +#: addons/web/static/src/xml/base.xml:738 +#: addons/web/static/src/xml/base.xml:1496 +#: addons/web/static/src/xml/base.xml:1506 +#: addons/web/static/src/xml/base.xml:1515 +msgid "Cancel" +msgstr "Keskeytä" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:791 +msgid "Change password" +msgstr "Vaihda salasana" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:792 +#: addons/web/static/src/js/view_editor.js:73 +#: addons/web/static/src/js/views.js:962 addons/web/static/src/xml/base.xml:737 +#: addons/web/static/src/xml/base.xml:1500 +#: addons/web/static/src/xml/base.xml:1514 +msgid "Save" +msgstr "Tallenna" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:811 +#: addons/web/static/src/xml/base.xml:226 +#: addons/web/static/src/xml/base.xml:1729 +msgid "Change Password" +msgstr "Vaihda salasana" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:1096 +msgid "OpenERP - Unsupported/Community Version" +msgstr "OpenERP - ei tuettu yhteisöversio" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:1131 +msgid "Client Error" +msgstr "Asiakasohjelmiston virhe" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:6 +msgid "Export Data" +msgstr "Vie tiedot" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:19 +#: addons/web/static/src/js/data_import.js:69 +#: addons/web/static/src/js/view_editor.js:49 +#: addons/web/static/src/js/view_editor.js:398 +#: addons/web/static/src/js/view_form.js:692 +#: addons/web/static/src/js/view_form.js:3044 +#: addons/web/static/src/js/views.js:963 +msgid "Close" +msgstr "Sulje" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:20 +msgid "Export To File" +msgstr "Vie tiedostoon" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:125 +msgid "Please enter save field list name" +msgstr "Ole hyvä ja anna tallennus kentän listan nimi" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:360 +msgid "Please select fields to save export list..." +msgstr "Ole hyvä ja valitse kentät vientiluetteloon." + +#. openerp-web +#: addons/web/static/src/js/data_export.js:373 +msgid "Please select fields to export..." +msgstr "Valitse vietävät kentät..." + +#. openerp-web +#: addons/web/static/src/js/data_import.js:34 +msgid "Import Data" +msgstr "Tuo tiedot" + +#. openerp-web +#: addons/web/static/src/js/data_import.js:70 +msgid "Import File" +msgstr "Tuo tiedosto" + +#. openerp-web +#: addons/web/static/src/js/data_import.js:105 +msgid "External ID" +msgstr "Ulkoinen ID" + +#. openerp-web +#: addons/web/static/src/js/formats.js:300 +#: addons/web/static/src/js/view_page.js:245 +msgid "Download" +msgstr "Lataa" + +#. openerp-web +#: addons/web/static/src/js/formats.js:305 +#, python-format +msgid "Download \"%s\"" +msgstr "Lataa \"%s\"" + +#. openerp-web +#: addons/web/static/src/js/search.js:191 +msgid "Filter disabled due to invalid syntax" +msgstr "Suodin poistettu käytöstä virheellisen syntaksin takia" + +#. openerp-web +#: addons/web/static/src/js/search.js:237 +msgid "Filter Entry" +msgstr "Suodin vaihtoehto" + +#. openerp-web +#: addons/web/static/src/js/search.js:242 +#: addons/web/static/src/js/search.js:291 +msgid "OK" +msgstr "OK" + +#. openerp-web +#: addons/web/static/src/js/search.js:286 +#: addons/web/static/src/xml/base.xml:1292 +msgid "Add to Dashboard" +msgstr "Lisää työpöydälle" + +#. openerp-web +#: addons/web/static/src/js/search.js:415 +msgid "Invalid Search" +msgstr "Vriheellinen haku" + +#. openerp-web +#: addons/web/static/src/js/search.js:415 +msgid "triggered from search view" +msgstr "liipaistu hakunäkymästä" + +#. openerp-web +#: addons/web/static/src/js/search.js:503 +#, python-format +msgid "Incorrect value for field %(fieldname)s: [%(value)s] is %(message)s" +msgstr "Virheellinen arvo kentälle %(fieldname)s: [%(value)s] is %(message)s" + +#. openerp-web +#: addons/web/static/src/js/search.js:839 +msgid "not a valid integer" +msgstr "Ei sallittu kokonaisluku" + +#. openerp-web +#: addons/web/static/src/js/search.js:853 +msgid "not a valid number" +msgstr "Ei sallittu numeo" + +#. openerp-web +#: addons/web/static/src/js/search.js:931 +#: addons/web/static/src/xml/base.xml:968 +msgid "Yes" +msgstr "Kyllä" + +#. openerp-web +#: addons/web/static/src/js/search.js:932 +msgid "No" +msgstr "Ei" + +#. openerp-web +#: addons/web/static/src/js/search.js:1290 +msgid "contains" +msgstr "sisältää" + +#. openerp-web +#: addons/web/static/src/js/search.js:1291 +msgid "doesn't contain" +msgstr "ei sisällä" + +#. openerp-web +#: addons/web/static/src/js/search.js:1292 +#: addons/web/static/src/js/search.js:1306 +#: addons/web/static/src/js/search.js:1325 +#: addons/web/static/src/js/search.js:1344 +#: addons/web/static/src/js/search.js:1365 +msgid "is equal to" +msgstr "on yhtäsuuri kuin" + +#. openerp-web +#: addons/web/static/src/js/search.js:1293 +#: addons/web/static/src/js/search.js:1307 +#: addons/web/static/src/js/search.js:1326 +#: addons/web/static/src/js/search.js:1345 +#: addons/web/static/src/js/search.js:1366 +msgid "is not equal to" +msgstr "ei ole yhtäsuuri kuin" + +#. openerp-web +#: addons/web/static/src/js/search.js:1294 +#: addons/web/static/src/js/search.js:1308 +#: addons/web/static/src/js/search.js:1327 +#: addons/web/static/src/js/search.js:1346 +#: addons/web/static/src/js/search.js:1367 +msgid "greater than" +msgstr "suurempi kuin" + +#. openerp-web +#: addons/web/static/src/js/search.js:1295 +#: addons/web/static/src/js/search.js:1309 +#: addons/web/static/src/js/search.js:1328 +#: addons/web/static/src/js/search.js:1347 +#: addons/web/static/src/js/search.js:1368 +msgid "less than" +msgstr "pienempi kuin" + +#. openerp-web +#: addons/web/static/src/js/search.js:1296 +#: addons/web/static/src/js/search.js:1310 +#: addons/web/static/src/js/search.js:1329 +#: addons/web/static/src/js/search.js:1348 +#: addons/web/static/src/js/search.js:1369 +msgid "greater or equal than" +msgstr "Suurempi tai yhtäsuuri kuin" + +#. openerp-web +#: addons/web/static/src/js/search.js:1297 +#: addons/web/static/src/js/search.js:1311 +#: addons/web/static/src/js/search.js:1330 +#: addons/web/static/src/js/search.js:1349 +#: addons/web/static/src/js/search.js:1370 +msgid "less or equal than" +msgstr "pienempi tai yhtäsuuri kuin" + +#. openerp-web +#: addons/web/static/src/js/search.js:1360 +#: addons/web/static/src/js/search.js:1383 +msgid "is" +msgstr "on" + +#. openerp-web +#: addons/web/static/src/js/search.js:1384 +msgid "is not" +msgstr "ei ole" + +#. openerp-web +#: addons/web/static/src/js/search.js:1396 +msgid "is true" +msgstr "on tosi" + +#. openerp-web +#: addons/web/static/src/js/search.js:1397 +msgid "is false" +msgstr "on epätosi" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:20 +#, python-format +msgid "Manage Views (%s)" +msgstr "Hallitse näkymiä (%s)" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:46 +#: addons/web/static/src/js/view_list.js:17 +#: addons/web/static/src/xml/base.xml:100 +#: addons/web/static/src/xml/base.xml:327 +#: addons/web/static/src/xml/base.xml:756 +msgid "Create" +msgstr "Luo" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:47 +#: addons/web/static/src/xml/base.xml:483 +#: addons/web/static/src/xml/base.xml:755 +msgid "Edit" +msgstr "Muokkaa" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:48 +#: addons/web/static/src/xml/base.xml:1647 +msgid "Remove" +msgstr "Poista" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:71 +#, python-format +msgid "Create a view (%s)" +msgstr "Luo näkymä (%s)" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:168 +msgid "Do you really want to remove this view?" +msgstr "Haluatko varmasti poistaa tämän näkymän" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:364 +#, python-format +msgid "View Editor %d - %s" +msgstr "Näkymä editori %d - %s" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:367 +msgid "Inherited View" +msgstr "Peritty näkymä" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:371 +msgid "Do you really wants to create an inherited view here?" +msgstr "Haluatko luoda periytyvän näkymän?" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:381 +msgid "Preview" +msgstr "Esikatselu" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:501 +msgid "Do you really want to remove this node?" +msgstr "Haluatko poistaa tämän liitoksen?" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:815 +#: addons/web/static/src/js/view_editor.js:939 +msgid "Properties" +msgstr "Ominaisuudet" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:818 +#: addons/web/static/src/js/view_editor.js:942 +msgid "Update" +msgstr "Päivitä" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:16 +msgid "Form" +msgstr "Lomake" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:121 +#: addons/web/static/src/js/views.js:803 +msgid "Customize" +msgstr "Mukauta" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:123 +#: addons/web/static/src/js/view_form.js:686 +msgid "Set Default" +msgstr "Aseta Oletukseksi" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:469 +msgid "" +"Warning, the record has been modified, your changes will be discarded." +msgstr "Varoitus, tietuetta on muutettu, muutoksesi hylätään." + +#. openerp-web +#: addons/web/static/src/js/view_form.js:693 +msgid "Save default" +msgstr "Tallenna oletusarvo" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:754 +msgid "Attachments" +msgstr "Liitteet" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:792 +#, python-format +msgid "Do you really want to delete the attachment %s?" +msgstr "Oletko varma että haluat poistaa liitteen %s?" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:822 +#, python-format +msgid "Unknown operator %s in domain %s" +msgstr "Tuntematon operaattori %s toimialueella %s" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:830 +#, python-format +msgid "Unknown field %s in domain %s" +msgstr "Tuntematon kenttä %s toimialueella %s" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:868 +#, python-format +msgid "Unsupported operator %s in domain %s" +msgstr "Ei tuettu operaattori %s toimialueella %s" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:1225 +msgid "Confirm" +msgstr "Hyväksy" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:1921 +#: addons/web/static/src/js/view_form.js:2578 +#: addons/web/static/src/js/view_form.js:2741 +msgid "Open: " +msgstr "Avaa: " + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2049 +msgid "   Search More..." +msgstr "   hae lisää..." + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2062 +#, python-format +msgid "   Create \"%s\"" +msgstr "   Luo \"%s\"" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2068 +msgid "   Create and Edit..." +msgstr "   Luo ja muokkaa..." + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2101 +#: addons/web/static/src/js/views.js:675 +msgid "Search: " +msgstr "Etsi: " + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2101 +#: addons/web/static/src/js/view_form.js:2550 +msgid "Create: " +msgstr "Luo: " + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2661 +#: addons/web/static/src/xml/base.xml:750 +#: addons/web/static/src/xml/base.xml:772 +#: addons/web/static/src/xml/base.xml:1646 +msgid "Add" +msgstr "LIsää" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2721 +msgid "Add: " +msgstr "Lisää: " + +#. openerp-web +#: addons/web/static/src/js/view_list.js:8 +msgid "List" +msgstr "Lista" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:269 +msgid "Unlimited" +msgstr "Ei rajoitettu" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:305 +#, python-format +msgid "[%(first_record)d to %(last_record)d] of %(records_count)d" +msgstr "[%(first_record)d to %(last_record)d] of %(records_count)d" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:524 +msgid "Do you really want to remove these records?" +msgstr "Oletko varma että haluat poistaa nämä tietueet?" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:1230 +msgid "Undefined" +msgstr "Määrittämätön" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:1327 +#, python-format +msgid "%(page)d/%(page_count)d" +msgstr "%(page)d/%(page_count)d" + +#. openerp-web +#: addons/web/static/src/js/view_page.js:8 +msgid "Page" +msgstr "Sivu" + +#. openerp-web +#: addons/web/static/src/js/view_page.js:52 +msgid "Do you really want to delete this record?" +msgstr "Haluatko poistaa tämän tietueen?" + +#. openerp-web +#: addons/web/static/src/js/view_tree.js:11 +msgid "Tree" +msgstr "Puu" + +#. openerp-web +#: addons/web/static/src/js/views.js:565 addons/web/static/src/xml/base.xml:480 +msgid "Fields View Get" +msgstr "Hae Kenttänäkymä" + +#. openerp-web +#: addons/web/static/src/js/views.js:573 +#, python-format +msgid "View Log (%s)" +msgstr "Katso lokia (%s)" + +#. openerp-web +#: addons/web/static/src/js/views.js:600 +#, python-format +msgid "Model %s fields" +msgstr "Malli %s kentät" + +#. openerp-web +#: addons/web/static/src/js/views.js:610 addons/web/static/src/xml/base.xml:482 +msgid "Manage Views" +msgstr "Muokkaa näkymiä" + +#. openerp-web +#: addons/web/static/src/js/views.js:611 +msgid "Could not find current view declaration" +msgstr "Ei löydy nykyistä näkymämäärittelyä" + +#. openerp-web +#: addons/web/static/src/js/views.js:805 +msgid "Translate" +msgstr "Käännä" + +#. openerp-web +#: addons/web/static/src/js/views.js:807 +msgid "Technical translation" +msgstr "Tekninen käännös" + +#. openerp-web +#: addons/web/static/src/js/views.js:811 +msgid "Other Options" +msgstr "Muut valinnat" + +#. openerp-web +#: addons/web/static/src/js/views.js:814 +#: addons/web/static/src/xml/base.xml:1736 +msgid "Import" +msgstr "Tuo" + +#. openerp-web +#: addons/web/static/src/js/views.js:817 +#: addons/web/static/src/xml/base.xml:1606 +msgid "Export" +msgstr "Vie" + +#. openerp-web +#: addons/web/static/src/js/views.js:825 +msgid "Reports" +msgstr "Raportit" + +#. openerp-web +#: addons/web/static/src/js/views.js:825 +msgid "Actions" +msgstr "Tehtävät" + +#. openerp-web +#: addons/web/static/src/js/views.js:825 +msgid "Links" +msgstr "Linkit" + +#. openerp-web +#: addons/web/static/src/js/views.js:919 +msgid "You must choose at least one record." +msgstr "Sinun tulee valita ainakin yksi tietue" + +#. openerp-web +#: addons/web/static/src/js/views.js:920 +msgid "Warning" +msgstr "Varoitus" + +#. openerp-web +#: addons/web/static/src/js/views.js:957 +msgid "Translations" +msgstr "Käännökset" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:44 addons/web/static/src/xml/base.xml:315 +msgid "Powered by" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:44 addons/web/static/src/xml/base.xml:315 +#: addons/web/static/src/xml/base.xml:1813 +msgid "OpenERP" +msgstr "OpenERP" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:52 +msgid "Loading..." +msgstr "Lataa..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:61 +msgid "CREATE DATABASE" +msgstr "LUO TIETOKANTA" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:68 addons/web/static/src/xml/base.xml:211 +msgid "Master password:" +msgstr "Pääsalasana:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:72 addons/web/static/src/xml/base.xml:191 +msgid "New database name:" +msgstr "Uuden tietokannan nimi:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:77 +msgid "Load Demonstration data:" +msgstr "Lataa demo tiedot:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:81 +msgid "Default language:" +msgstr "Oletuskieli:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:91 +msgid "Admin password:" +msgstr "Pääkäyttäjän salasana:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:95 +msgid "Confirm password:" +msgstr "Vahvista salasana:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:109 +msgid "DROP DATABASE" +msgstr "TIPUTA TIETOKANTA" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:116 +#: addons/web/static/src/xml/base.xml:150 +#: addons/web/static/src/xml/base.xml:301 +msgid "Database:" +msgstr "Tietokanta:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:128 +#: addons/web/static/src/xml/base.xml:162 +#: addons/web/static/src/xml/base.xml:187 +msgid "Master Password:" +msgstr "Pääsalasana:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:132 +#: addons/web/static/src/xml/base.xml:328 +msgid "Drop" +msgstr "Pudota" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:143 +msgid "BACKUP DATABASE" +msgstr "VARMISTA TIETOKANTA" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:166 +#: addons/web/static/src/xml/base.xml:329 +msgid "Backup" +msgstr "Varmuuskopioi" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:175 +msgid "RESTORE DATABASE" +msgstr "PALAUTA TIETOKANTA" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:182 +msgid "File:" +msgstr "Tiedosto:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:195 +#: addons/web/static/src/xml/base.xml:330 +msgid "Restore" +msgstr "Palauta" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:204 +msgid "CHANGE MASTER PASSWORD" +msgstr "VAIHDA PÄÄSALASANA" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:216 +msgid "New master password:" +msgstr "Uusi pääsalasana" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:221 +msgid "Confirm new master password:" +msgstr "Vahvista uusi pääsalasana" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:251 +msgid "" +"Your version of OpenERP is unsupported. Support & maintenance services are " +"available here:" +msgstr "" +"Käyttämäsi versio OpenERP järejstelmästä ei ole tuettu. Tukea ja ylläpitoa " +"on saatavilla täältä:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:251 +msgid "OpenERP Entreprise" +msgstr "OpenERP yritys" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:256 +msgid "OpenERP Enterprise Contract." +msgstr "OpenERP yritys yhteystiedot." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:257 +msgid "Your report will be sent to the OpenERP Enterprise team." +msgstr "Raporttisi lähetetään OpenERP yritystiimille." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:259 +msgid "Summary:" +msgstr "Yhteenveto" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:263 +msgid "Description:" +msgstr "Kuvaus:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:267 +msgid "What you did:" +msgstr "Mitä teit:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:297 +msgid "Invalid username or password" +msgstr "Virheellinen käyttäjänimi tai salasana" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:306 +msgid "Username" +msgstr "Käyttäjänimi" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:308 +#: addons/web/static/src/xml/base.xml:331 +msgid "Password" +msgstr "Salasana" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:310 +msgid "Log in" +msgstr "Kirjaudu sisään" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:314 +msgid "Manage Databases" +msgstr "Hallitse tietokantoja" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:332 +msgid "Back to Login" +msgstr "Paluu kirjautumiseen" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:353 +msgid "Home" +msgstr "Alkuun" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:363 +msgid "LOGOUT" +msgstr "KIRJAUDU ULOS" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:388 +msgid "Fold menu" +msgstr "Sulje valikko" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:389 +msgid "Unfold menu" +msgstr "Avaa valikko" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:454 +msgid "Hide this tip" +msgstr "Piilota tämä vihje" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:455 +msgid "Disable all tips" +msgstr "Poista kaikki vihjeet käytöstä" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:463 +msgid "Add / Remove Shortcut..." +msgstr "Lisää / Poista pikakuvake..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:471 +msgid "More…" +msgstr "Lisää..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:477 +msgid "Debug View#" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:478 +msgid "View Log (perm_read)" +msgstr "Näytä loki (perm_read)" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:479 +msgid "View Fields" +msgstr "Näytä kentät" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:483 +msgid "View" +msgstr "Näkymä" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:484 +msgid "Edit SearchView" +msgstr "Muokkaa hakunäkymää" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:485 +msgid "Edit Action" +msgstr "Muokkaa toimintoa" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:486 +msgid "Edit Workflow" +msgstr "Muokkaa työnkulkua" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:491 +msgid "ID:" +msgstr "ID:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:494 +msgid "XML ID:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:497 +msgid "Creation User:" +msgstr "Luonut käyttäjä:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:500 +msgid "Creation Date:" +msgstr "Luontipäivämäärä:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:503 +msgid "Latest Modification by:" +msgstr "Viimeisin muutos:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:506 +msgid "Latest Modification Date:" +msgstr "Viimeisin muutospäivämäärä:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:542 +msgid "Field" +msgstr "Kenttä" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:632 +#: addons/web/static/src/xml/base.xml:758 +#: addons/web/static/src/xml/base.xml:1708 +msgid "Delete" +msgstr "Poista" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:757 +msgid "Duplicate" +msgstr "Kopioi" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:775 +msgid "Add attachment" +msgstr "Lisää liitetiedosto" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:801 +msgid "Default:" +msgstr "Oletus:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:818 +msgid "Condition:" +msgstr "Ehto:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:837 +msgid "Only you" +msgstr "Vain sinä" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:844 +msgid "All users" +msgstr "Kaikki käyttäjät" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:851 +msgid "Unhandled widget" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:900 +msgid "Notebook Page \"" +msgstr "Muistion sivu \"" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:905 +#: addons/web/static/src/xml/base.xml:964 +msgid "Modifiers:" +msgstr "Muuttujat:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:931 +msgid "(nolabel)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:936 +msgid "Field:" +msgstr "Kenttä:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:940 +msgid "Object:" +msgstr "Objekti:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:944 +msgid "Type:" +msgstr "Tyyppi:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:948 +msgid "Widget:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:952 +msgid "Size:" +msgstr "Koko:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:956 +msgid "Context:" +msgstr "Konteksti:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:960 +msgid "Domain:" +msgstr "Toimialue:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:968 +msgid "Change default:" +msgstr "Vaihda oletusarvo:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:972 +msgid "On change:" +msgstr "Vaihdettaessa:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:976 +msgid "Relation:" +msgstr "Suhde:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:980 +msgid "Selection:" +msgstr "Valinta:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1020 +msgid "Send an e-mail with your default e-mail client" +msgstr "Lähetä sähköpostia oletussähköpostiohjelmallasi" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1034 +msgid "Open this resource" +msgstr "Avaa tämä resurssi" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1056 +msgid "Select date" +msgstr "Valitse päiväys" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1090 +msgid "Open..." +msgstr "Avaa..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1091 +msgid "Create..." +msgstr "Luo..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1092 +msgid "Search..." +msgstr "Etsi..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1095 +msgid "..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1155 +#: addons/web/static/src/xml/base.xml:1198 +msgid "Set Image" +msgstr "Aseta kuva" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1163 +#: addons/web/static/src/xml/base.xml:1213 +#: addons/web/static/src/xml/base.xml:1215 +#: addons/web/static/src/xml/base.xml:1272 +msgid "Clear" +msgstr "Pyyhi" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1172 +#: addons/web/static/src/xml/base.xml:1223 +msgid "Uploading ..." +msgstr "Lähetetään..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1200 +#: addons/web/static/src/xml/base.xml:1495 +msgid "Select" +msgstr "Valitse" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1207 +#: addons/web/static/src/xml/base.xml:1209 +msgid "Save As" +msgstr "Tallenna nimellä" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1238 +msgid "Button" +msgstr "Nappi" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1241 +msgid "(no string)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1248 +msgid "Special:" +msgstr "Erityinen:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1253 +msgid "Button Type:" +msgstr "Napin tyyppi:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1257 +msgid "Method:" +msgstr "Menetelmä:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1261 +msgid "Action ID:" +msgstr "Toiminnon ID:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1271 +msgid "Search" +msgstr "Etsi" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1279 +msgid "Filters" +msgstr "Suotimet" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1280 +msgid "-- Filters --" +msgstr "-- Suotimet --" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1289 +msgid "-- Actions --" +msgstr "-- Toiminnot --" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1290 +msgid "Add Advanced Filter" +msgstr "Lisää kehittynyt suodin" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1291 +msgid "Save Filter" +msgstr "Tallenna suodin" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1293 +msgid "Manage Filters" +msgstr "Hallitse Suotimia" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1298 +msgid "Filter Name:" +msgstr "Suotimen nimi:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1300 +msgid "(Any existing filter with the same name will be replaced)" +msgstr "(jo olemassaoleva samanniminen suodin korvataan)" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1305 +msgid "Select Dashboard to add this filter to:" +msgstr "Valitse työpöytä jolle tämä suodin lisätään:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1309 +msgid "Title of new Dashboard item:" +msgstr "Uuden työpöytäkohteen nimi:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1416 +msgid "Advanced Filters" +msgstr "Kehittyneet suotimet" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1426 +msgid "Any of the following conditions must match" +msgstr "Mikä tahansa seuraavista ehdoista tulee täyttyä" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1427 +msgid "All the following conditions must match" +msgstr "Kaikki seuraavat ehdot tulee täyttyä" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1428 +msgid "None of the following conditions must match" +msgstr "Mikään seuraavista ehdoista ei saa täyttyä" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1435 +msgid "Add condition" +msgstr "Lisää ehto" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1436 +msgid "and" +msgstr "ja" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1503 +msgid "Save & New" +msgstr "Tallenna & Uusi" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1504 +msgid "Save & Close" +msgstr "Tallenna & Sulje" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1611 +msgid "" +"This wizard will export all data that matches the current search criteria to " +"a CSV file.\n" +" You can export all data or only the fields that can be " +"reimported after modification." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1618 +msgid "Export Type:" +msgstr "Viennin tyyppi:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1620 +msgid "Import Compatible Export" +msgstr "Tuonnin kanssa yhteensopiva vienti" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1621 +msgid "Export all Data" +msgstr "Vie kaikki tiedot" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1624 +msgid "Export Formats" +msgstr "Vie muotoilut" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1630 +msgid "Available fields" +msgstr "Mahdolliset kentät" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1632 +msgid "Fields to export" +msgstr "Vietävät kentät" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1634 +msgid "Save fields list" +msgstr "Tallenna kenttäluettelo" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1648 +msgid "Remove All" +msgstr "Poista kaikki" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1660 +msgid "Name" +msgstr "Nimi" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1693 +msgid "Save as:" +msgstr "Tallenna nimellä:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1700 +msgid "Saved exports:" +msgstr "Tallennetut viennit:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1714 +msgid "Old Password:" +msgstr "Vanha salasana:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1719 +msgid "New Password:" +msgstr "Uusi salasana:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1724 +msgid "Confirm Password:" +msgstr "Vahvista salasana:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1742 +msgid "1. Import a .CSV file" +msgstr "1. Tuo .CSV tiedosto" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1743 +msgid "" +"Select a .CSV file to import. If you need a sample of file to import,\n" +" you should use the export tool with the \"Import Compatible\" option." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1747 +msgid "CSV File:" +msgstr "CSV tiedosto:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1750 +msgid "2. Check your file format" +msgstr "2. Tarkista tiedostomuoto" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1753 +msgid "Import Options" +msgstr "Tuonnin valinnat" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1757 +msgid "Does your file have titles?" +msgstr "Onko tiedostossasi otsikot?" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1763 +msgid "Separator:" +msgstr "Erotin:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1765 +msgid "Delimiter:" +msgstr "Rajoitin:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1769 +msgid "Encoding:" +msgstr "Merkistö:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1772 +msgid "UTF-8" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1773 +msgid "Latin 1" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1776 +msgid "Lines to skip" +msgstr "Ohitettavat rivit" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1776 +msgid "" +"For use if CSV files have titles on multiple lines, skips more than a single " +"line during import" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1803 +msgid "The import failed due to:" +msgstr "Tuonti epäonnistui, koska:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1805 +msgid "Here is a preview of the file we could not import:" +msgstr "Tässä on näyte tiedostosta jota ei voitu tuoda:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1812 +msgid "Activate the developper mode" +msgstr "Aktivoi kehittäjämoodi" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1814 +msgid "Version" +msgstr "Versio" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1815 +msgid "Copyright © 2004-TODAY OpenERP SA. All Rights Reserved." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1816 +msgid "OpenERP is a trademark of the" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1817 +msgid "OpenERP SA Company" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1819 +msgid "Licenced under the terms of" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1820 +msgid "GNU Affero General Public License" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1822 +msgid "For more information visit" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1823 +msgid "OpenERP.com" +msgstr "" diff --git a/addons/web/i18n/gl.po b/addons/web/i18n/gl.po index 8064f77a01e..847536db8b4 100644 --- a/addons/web/i18n/gl.po +++ b/addons/web/i18n/gl.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-14 15:27+0100\n" -"PO-Revision-Date: 2012-02-13 23:41+0000\n" -"Last-Translator: Amós Oviedo \n" +"PO-Revision-Date: 2012-02-16 10:02+0000\n" +"Last-Translator: Vicente \n" "Language-Team: Galician \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-15 05:43+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:172 @@ -193,7 +193,7 @@ msgstr "Descargar \"%s\"" #. openerp-web #: addons/web/static/src/js/search.js:191 msgid "Filter disabled due to invalid syntax" -msgstr "" +msgstr "Filtro desactivado debido a sintaxis inválida" #. openerp-web #: addons/web/static/src/js/search.js:237 @@ -383,12 +383,12 @@ msgstr "Ver Editor %d - %s" #. openerp-web #: addons/web/static/src/js/view_editor.js:367 msgid "Inherited View" -msgstr "" +msgstr "Vista Herdada" #. openerp-web #: addons/web/static/src/js/view_editor.js:371 msgid "Do you really wants to create an inherited view here?" -msgstr "" +msgstr "¿Realmente quere crear unha vista herdada aquí?" #. openerp-web #: addons/web/static/src/js/view_editor.js:381 @@ -427,7 +427,7 @@ msgstr "Persoalizar" #: addons/web/static/src/js/view_form.js:123 #: addons/web/static/src/js/view_form.js:686 msgid "Set Default" -msgstr "" +msgstr "Estabelecer como predeterminado" #. openerp-web #: addons/web/static/src/js/view_form.js:469 @@ -438,7 +438,7 @@ msgstr "Advertencia, o rexistro modificouse, os cambios serán descartados." #. openerp-web #: addons/web/static/src/js/view_form.js:693 msgid "Save default" -msgstr "" +msgstr "Gardar como predeterminado" #. openerp-web #: addons/web/static/src/js/view_form.js:754 @@ -904,47 +904,47 @@ msgstr "Vista" #. openerp-web #: addons/web/static/src/xml/base.xml:484 msgid "Edit SearchView" -msgstr "" +msgstr "Editar SearchView" #. openerp-web #: addons/web/static/src/xml/base.xml:485 msgid "Edit Action" -msgstr "" +msgstr "Editar a acción" #. openerp-web #: addons/web/static/src/xml/base.xml:486 msgid "Edit Workflow" -msgstr "" +msgstr "Editar Fluxo de Traballo" #. openerp-web #: addons/web/static/src/xml/base.xml:491 msgid "ID:" -msgstr "" +msgstr "ID:" #. openerp-web #: addons/web/static/src/xml/base.xml:494 msgid "XML ID:" -msgstr "" +msgstr "XML ID:" #. openerp-web #: addons/web/static/src/xml/base.xml:497 msgid "Creation User:" -msgstr "" +msgstr "Usuario de Creación:" #. openerp-web #: addons/web/static/src/xml/base.xml:500 msgid "Creation Date:" -msgstr "" +msgstr "Data de Creación:" #. openerp-web #: addons/web/static/src/xml/base.xml:503 msgid "Latest Modification by:" -msgstr "" +msgstr "Última Modificación por:" #. openerp-web #: addons/web/static/src/xml/base.xml:506 msgid "Latest Modification Date:" -msgstr "" +msgstr "Última data de modificación:" #. openerp-web #: addons/web/static/src/xml/base.xml:542 @@ -966,27 +966,27 @@ msgstr "Duplicar" #. openerp-web #: addons/web/static/src/xml/base.xml:775 msgid "Add attachment" -msgstr "" +msgstr "Engadir anexo" #. openerp-web #: addons/web/static/src/xml/base.xml:801 msgid "Default:" -msgstr "" +msgstr "Predeterminado:" #. openerp-web #: addons/web/static/src/xml/base.xml:818 msgid "Condition:" -msgstr "" +msgstr "Estado:" #. openerp-web #: addons/web/static/src/xml/base.xml:837 msgid "Only you" -msgstr "" +msgstr "So vostede" #. openerp-web #: addons/web/static/src/xml/base.xml:844 msgid "All users" -msgstr "" +msgstr "Todos os usuarios" #. openerp-web #: addons/web/static/src/xml/base.xml:851 @@ -996,88 +996,88 @@ msgstr "Widget non controlado" #. openerp-web #: addons/web/static/src/xml/base.xml:900 msgid "Notebook Page \"" -msgstr "" +msgstr "Páxina de Caderno \"" #. openerp-web #: addons/web/static/src/xml/base.xml:905 #: addons/web/static/src/xml/base.xml:964 msgid "Modifiers:" -msgstr "" +msgstr "Modificadores:" #. openerp-web #: addons/web/static/src/xml/base.xml:931 msgid "(nolabel)" -msgstr "" +msgstr "(sin etiqueta)" #. openerp-web #: addons/web/static/src/xml/base.xml:936 msgid "Field:" -msgstr "" +msgstr "Campo:" #. openerp-web #: addons/web/static/src/xml/base.xml:940 msgid "Object:" -msgstr "" +msgstr "Obxecto:" #. openerp-web #: addons/web/static/src/xml/base.xml:944 msgid "Type:" -msgstr "" +msgstr "Tipo:" #. openerp-web #: addons/web/static/src/xml/base.xml:948 msgid "Widget:" -msgstr "" +msgstr "Widget:" #. openerp-web #: addons/web/static/src/xml/base.xml:952 msgid "Size:" -msgstr "" +msgstr "Tamaño:" #. openerp-web #: addons/web/static/src/xml/base.xml:956 msgid "Context:" -msgstr "" +msgstr "Contexto:" #. openerp-web #: addons/web/static/src/xml/base.xml:960 msgid "Domain:" -msgstr "" +msgstr "Dominio:" #. openerp-web #: addons/web/static/src/xml/base.xml:968 msgid "Change default:" -msgstr "" +msgstr "Cambiar predeterminado:" #. openerp-web #: addons/web/static/src/xml/base.xml:972 msgid "On change:" -msgstr "" +msgstr "Cando cambie:" #. openerp-web #: addons/web/static/src/xml/base.xml:976 msgid "Relation:" -msgstr "" +msgstr "Relación:" #. openerp-web #: addons/web/static/src/xml/base.xml:980 msgid "Selection:" -msgstr "" +msgstr "Selección:" #. openerp-web #: addons/web/static/src/xml/base.xml:1020 msgid "Send an e-mail with your default e-mail client" -msgstr "" +msgstr "Envíe un correo electrónico co seu cliente de correo predefinido" #. openerp-web #: addons/web/static/src/xml/base.xml:1034 msgid "Open this resource" -msgstr "" +msgstr "Abrir este recurso" #. openerp-web #: addons/web/static/src/xml/base.xml:1056 msgid "Select date" -msgstr "" +msgstr "Seleccionar data" #. openerp-web #: addons/web/static/src/xml/base.xml:1090 @@ -1103,7 +1103,7 @@ msgstr "…" #: addons/web/static/src/xml/base.xml:1155 #: addons/web/static/src/xml/base.xml:1198 msgid "Set Image" -msgstr "" +msgstr "Estabelecer imaxe" #. openerp-web #: addons/web/static/src/xml/base.xml:1163 @@ -1134,57 +1134,57 @@ msgstr "Gardar como" #. openerp-web #: addons/web/static/src/xml/base.xml:1238 msgid "Button" -msgstr "" +msgstr "Botón" #. openerp-web #: addons/web/static/src/xml/base.xml:1241 msgid "(no string)" -msgstr "" +msgstr "(sin cadena)" #. openerp-web #: addons/web/static/src/xml/base.xml:1248 msgid "Special:" -msgstr "" +msgstr "Especial:" #. openerp-web #: addons/web/static/src/xml/base.xml:1253 msgid "Button Type:" -msgstr "" +msgstr "Tipo de Botón" #. openerp-web #: addons/web/static/src/xml/base.xml:1257 msgid "Method:" -msgstr "" +msgstr "Método:" #. openerp-web #: addons/web/static/src/xml/base.xml:1261 msgid "Action ID:" -msgstr "" +msgstr "Acción ID:" #. openerp-web #: addons/web/static/src/xml/base.xml:1271 msgid "Search" -msgstr "" +msgstr "Busca" #. openerp-web #: addons/web/static/src/xml/base.xml:1279 msgid "Filters" -msgstr "" +msgstr "Filtros" #. openerp-web #: addons/web/static/src/xml/base.xml:1280 msgid "-- Filters --" -msgstr "" +msgstr "-- Filtros --" #. openerp-web #: addons/web/static/src/xml/base.xml:1289 msgid "-- Actions --" -msgstr "" +msgstr "-- Accions --" #. openerp-web #: addons/web/static/src/xml/base.xml:1290 msgid "Add Advanced Filter" -msgstr "" +msgstr "Engadir Filtro Avanzado" #. openerp-web #: addons/web/static/src/xml/base.xml:1291 @@ -1209,17 +1209,17 @@ msgstr "(Calquer filtro existente co mesmo nome será reemplazado)" #. openerp-web #: addons/web/static/src/xml/base.xml:1305 msgid "Select Dashboard to add this filter to:" -msgstr "" +msgstr "Seleccionar tableiro para engadirlle este filtro:" #. openerp-web #: addons/web/static/src/xml/base.xml:1309 msgid "Title of new Dashboard item:" -msgstr "" +msgstr "Título de novo elemento de Tableiro:" #. openerp-web #: addons/web/static/src/xml/base.xml:1416 msgid "Advanced Filters" -msgstr "" +msgstr "Filtros Avanzados" #. openerp-web #: addons/web/static/src/xml/base.xml:1426 @@ -1411,6 +1411,8 @@ msgid "" "For use if CSV files have titles on multiple lines, skips more than a single " "line during import" msgstr "" +"Para o seu uso se os ficheiros CSV teñen títulos en varias liñas, omitense " +"mais de una soa liña durante a importación" #. openerp-web #: addons/web/static/src/xml/base.xml:1803 @@ -1425,7 +1427,7 @@ msgstr "Esta é a vista previa do arquivo que non se pode importar:" #. openerp-web #: addons/web/static/src/xml/base.xml:1812 msgid "Activate the developper mode" -msgstr "" +msgstr "Activar modo de desenvolvedor" #. openerp-web #: addons/web/static/src/xml/base.xml:1814 @@ -1435,7 +1437,7 @@ msgstr "Versión" #. openerp-web #: addons/web/static/src/xml/base.xml:1815 msgid "Copyright © 2004-TODAY OpenERP SA. All Rights Reserved." -msgstr "" +msgstr "Copyright © 2004-HOY OpenERP SA. Todos os dereitos reservados." #. openerp-web #: addons/web/static/src/xml/base.xml:1816 @@ -1460,9 +1462,9 @@ msgstr "GNU Affero General Public License" #. openerp-web #: addons/web/static/src/xml/base.xml:1822 msgid "For more information visit" -msgstr "" +msgstr "Para mais información visite" #. openerp-web #: addons/web/static/src/xml/base.xml:1823 msgid "OpenERP.com" -msgstr "" +msgstr "OpenERP.com" diff --git a/addons/web/i18n/it.po b/addons/web/i18n/it.po index 6c9f6bb6c13..83e5d704ab4 100644 --- a/addons/web/i18n/it.po +++ b/addons/web/i18n/it.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-14 15:27+0100\n" -"PO-Revision-Date: 2011-10-08 13:39+0000\n" -"Last-Translator: Nicola Riolini - Micronaet \n" +"PO-Revision-Date: 2012-02-16 21:49+0000\n" +"Last-Translator: Davide Corio - agilebg.com \n" "Language-Team: Italian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-15 05:43+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:172 @@ -30,55 +30,55 @@ msgstr "Ok" #. openerp-web #: addons/web/static/src/js/chrome.js:180 msgid "Send OpenERP Enterprise Report" -msgstr "" +msgstr "Invia OpenERP Enterprise Report" #. openerp-web #: addons/web/static/src/js/chrome.js:194 msgid "Dont send" -msgstr "" +msgstr "Non inviare" #. openerp-web #: addons/web/static/src/js/chrome.js:256 #, python-format msgid "Loading (%d)" -msgstr "" +msgstr "Caricamento (%d)" #. openerp-web #: addons/web/static/src/js/chrome.js:288 msgid "Invalid database name" -msgstr "" +msgstr "Nome database non valido" #. openerp-web #: addons/web/static/src/js/chrome.js:483 msgid "Backed" -msgstr "" +msgstr "Salvato" #. openerp-web #: addons/web/static/src/js/chrome.js:484 msgid "Database backed up successfully" -msgstr "" +msgstr "Backup eseguito correttamente" #. openerp-web #: addons/web/static/src/js/chrome.js:527 msgid "Restored" -msgstr "" +msgstr "Ripristinato" #. openerp-web #: addons/web/static/src/js/chrome.js:527 msgid "Database restored successfully" -msgstr "" +msgstr "Database ripristinato correttamente" #. openerp-web #: addons/web/static/src/js/chrome.js:708 #: addons/web/static/src/xml/base.xml:359 msgid "About" -msgstr "" +msgstr "Informazioni" #. openerp-web #: addons/web/static/src/js/chrome.js:787 #: addons/web/static/src/xml/base.xml:356 msgid "Preferences" -msgstr "" +msgstr "Preferenze" #. openerp-web #: addons/web/static/src/js/chrome.js:790 @@ -98,7 +98,7 @@ msgstr "Annulla" #. openerp-web #: addons/web/static/src/js/chrome.js:791 msgid "Change password" -msgstr "" +msgstr "Cambia password" #. openerp-web #: addons/web/static/src/js/chrome.js:792 @@ -114,22 +114,22 @@ msgstr "Salva" #: addons/web/static/src/xml/base.xml:226 #: addons/web/static/src/xml/base.xml:1729 msgid "Change Password" -msgstr "" +msgstr "Cambia Password" #. openerp-web #: addons/web/static/src/js/chrome.js:1096 msgid "OpenERP - Unsupported/Community Version" -msgstr "" +msgstr "OpenERP - Unsupported/Community Version" #. openerp-web #: addons/web/static/src/js/chrome.js:1131 msgid "Client Error" -msgstr "" +msgstr "Errore Client" #. openerp-web #: addons/web/static/src/js/data_export.js:6 msgid "Export Data" -msgstr "" +msgstr "Esporta Dati" #. openerp-web #: addons/web/static/src/js/data_export.js:19 @@ -145,118 +145,118 @@ msgstr "Chiudi" #. openerp-web #: addons/web/static/src/js/data_export.js:20 msgid "Export To File" -msgstr "" +msgstr "Esporta in un file" #. openerp-web #: addons/web/static/src/js/data_export.js:125 msgid "Please enter save field list name" -msgstr "" +msgstr "Inserire il nome per la lista salvata" #. openerp-web #: addons/web/static/src/js/data_export.js:360 msgid "Please select fields to save export list..." -msgstr "" +msgstr "Selezionare l'elenco dei campi da esportare..." #. openerp-web #: addons/web/static/src/js/data_export.js:373 msgid "Please select fields to export..." -msgstr "" +msgstr "Selezionare i campi da esportare..." #. openerp-web #: addons/web/static/src/js/data_import.js:34 msgid "Import Data" -msgstr "" +msgstr "Importa Dati" #. openerp-web #: addons/web/static/src/js/data_import.js:70 msgid "Import File" -msgstr "" +msgstr "Importa File" #. openerp-web #: addons/web/static/src/js/data_import.js:105 msgid "External ID" -msgstr "" +msgstr "ID Esterno" #. openerp-web #: addons/web/static/src/js/formats.js:300 #: addons/web/static/src/js/view_page.js:245 msgid "Download" -msgstr "" +msgstr "Download" #. openerp-web #: addons/web/static/src/js/formats.js:305 #, python-format msgid "Download \"%s\"" -msgstr "" +msgstr "Download \"%s\"" #. openerp-web #: addons/web/static/src/js/search.js:191 msgid "Filter disabled due to invalid syntax" -msgstr "" +msgstr "Filtro disabilitato a causa di sintassi errata" #. openerp-web #: addons/web/static/src/js/search.js:237 msgid "Filter Entry" -msgstr "" +msgstr "Voce Filtro" #. openerp-web #: addons/web/static/src/js/search.js:242 #: addons/web/static/src/js/search.js:291 msgid "OK" -msgstr "" +msgstr "OK" #. openerp-web #: addons/web/static/src/js/search.js:286 #: addons/web/static/src/xml/base.xml:1292 msgid "Add to Dashboard" -msgstr "" +msgstr "Aggiungi a Dashboard" #. openerp-web #: addons/web/static/src/js/search.js:415 msgid "Invalid Search" -msgstr "" +msgstr "Ricerca Non Valida" #. openerp-web #: addons/web/static/src/js/search.js:415 msgid "triggered from search view" -msgstr "" +msgstr "avviato da vista ricerca" #. openerp-web #: addons/web/static/src/js/search.js:503 #, python-format msgid "Incorrect value for field %(fieldname)s: [%(value)s] is %(message)s" -msgstr "" +msgstr "Valore non valido per campo %(fieldname)s: [%(value)s] è %(message)s" #. openerp-web #: addons/web/static/src/js/search.js:839 msgid "not a valid integer" -msgstr "" +msgstr "intero non valido" #. openerp-web #: addons/web/static/src/js/search.js:853 msgid "not a valid number" -msgstr "" +msgstr "numero non valido" #. openerp-web #: addons/web/static/src/js/search.js:931 #: addons/web/static/src/xml/base.xml:968 msgid "Yes" -msgstr "" +msgstr "Sì" #. openerp-web #: addons/web/static/src/js/search.js:932 msgid "No" -msgstr "" +msgstr "No" #. openerp-web #: addons/web/static/src/js/search.js:1290 msgid "contains" -msgstr "" +msgstr "contiene" #. openerp-web #: addons/web/static/src/js/search.js:1291 msgid "doesn't contain" -msgstr "" +msgstr "non contiene" #. openerp-web #: addons/web/static/src/js/search.js:1292 @@ -265,7 +265,7 @@ msgstr "" #: addons/web/static/src/js/search.js:1344 #: addons/web/static/src/js/search.js:1365 msgid "is equal to" -msgstr "" +msgstr "è uguale a" #. openerp-web #: addons/web/static/src/js/search.js:1293 @@ -274,7 +274,7 @@ msgstr "" #: addons/web/static/src/js/search.js:1345 #: addons/web/static/src/js/search.js:1366 msgid "is not equal to" -msgstr "" +msgstr "è diverso da" #. openerp-web #: addons/web/static/src/js/search.js:1294 @@ -283,7 +283,7 @@ msgstr "" #: addons/web/static/src/js/search.js:1346 #: addons/web/static/src/js/search.js:1367 msgid "greater than" -msgstr "" +msgstr "maggiore di" #. openerp-web #: addons/web/static/src/js/search.js:1295 @@ -292,7 +292,7 @@ msgstr "" #: addons/web/static/src/js/search.js:1347 #: addons/web/static/src/js/search.js:1368 msgid "less than" -msgstr "" +msgstr "minore di" #. openerp-web #: addons/web/static/src/js/search.js:1296 @@ -301,7 +301,7 @@ msgstr "" #: addons/web/static/src/js/search.js:1348 #: addons/web/static/src/js/search.js:1369 msgid "greater or equal than" -msgstr "" +msgstr "maggiore o uguale a" #. openerp-web #: addons/web/static/src/js/search.js:1297 @@ -310,34 +310,34 @@ msgstr "" #: addons/web/static/src/js/search.js:1349 #: addons/web/static/src/js/search.js:1370 msgid "less or equal than" -msgstr "" +msgstr "minore o uguale a" #. openerp-web #: addons/web/static/src/js/search.js:1360 #: addons/web/static/src/js/search.js:1383 msgid "is" -msgstr "" +msgstr "è" #. openerp-web #: addons/web/static/src/js/search.js:1384 msgid "is not" -msgstr "" +msgstr "non è" #. openerp-web #: addons/web/static/src/js/search.js:1396 msgid "is true" -msgstr "" +msgstr "è vero" #. openerp-web #: addons/web/static/src/js/search.js:1397 msgid "is false" -msgstr "" +msgstr "è falso" #. openerp-web #: addons/web/static/src/js/view_editor.js:20 #, python-format msgid "Manage Views (%s)" -msgstr "" +msgstr "Gestisci Viste (%s)" #. openerp-web #: addons/web/static/src/js/view_editor.js:46 @@ -353,7 +353,7 @@ msgstr "Crea" #: addons/web/static/src/xml/base.xml:483 #: addons/web/static/src/xml/base.xml:755 msgid "Edit" -msgstr "" +msgstr "Modifica" #. openerp-web #: addons/web/static/src/js/view_editor.js:48 @@ -365,67 +365,67 @@ msgstr "Rimuovi" #: addons/web/static/src/js/view_editor.js:71 #, python-format msgid "Create a view (%s)" -msgstr "" +msgstr "Crea una vista (%s)" #. openerp-web #: addons/web/static/src/js/view_editor.js:168 msgid "Do you really want to remove this view?" -msgstr "" +msgstr "Vuoi veramente cancellare questa vista?" #. openerp-web #: addons/web/static/src/js/view_editor.js:364 #, python-format msgid "View Editor %d - %s" -msgstr "" +msgstr "Editor Vista %d - %s" #. openerp-web #: addons/web/static/src/js/view_editor.js:367 msgid "Inherited View" -msgstr "" +msgstr "Vista Ereditata" #. openerp-web #: addons/web/static/src/js/view_editor.js:371 msgid "Do you really wants to create an inherited view here?" -msgstr "" +msgstr "Vuoi veramente creare una vista ereditata in questa posizione?" #. openerp-web #: addons/web/static/src/js/view_editor.js:381 msgid "Preview" -msgstr "" +msgstr "Anteprima" #. openerp-web #: addons/web/static/src/js/view_editor.js:501 msgid "Do you really want to remove this node?" -msgstr "" +msgstr "Vuoi veramente eliminare questo nodo?" #. openerp-web #: addons/web/static/src/js/view_editor.js:815 #: addons/web/static/src/js/view_editor.js:939 msgid "Properties" -msgstr "" +msgstr "Proprietà" #. openerp-web #: addons/web/static/src/js/view_editor.js:818 #: addons/web/static/src/js/view_editor.js:942 msgid "Update" -msgstr "" +msgstr "Aggiorna" #. openerp-web #: addons/web/static/src/js/view_form.js:16 msgid "Form" -msgstr "" +msgstr "Form" #. openerp-web #: addons/web/static/src/js/view_form.js:121 #: addons/web/static/src/js/views.js:803 msgid "Customize" -msgstr "" +msgstr "Personalizza" #. openerp-web #: addons/web/static/src/js/view_form.js:123 #: addons/web/static/src/js/view_form.js:686 msgid "Set Default" -msgstr "" +msgstr "Imposta Default" #. openerp-web #: addons/web/static/src/js/view_form.js:469 @@ -438,48 +438,48 @@ msgstr "" #. openerp-web #: addons/web/static/src/js/view_form.js:693 msgid "Save default" -msgstr "" +msgstr "Salva Default" #. openerp-web #: addons/web/static/src/js/view_form.js:754 msgid "Attachments" -msgstr "" +msgstr "Allegati" #. openerp-web #: addons/web/static/src/js/view_form.js:792 #, python-format msgid "Do you really want to delete the attachment %s?" -msgstr "" +msgstr "Vuoi veramente cancellare l'allegato %s?" #. openerp-web #: addons/web/static/src/js/view_form.js:822 #, python-format msgid "Unknown operator %s in domain %s" -msgstr "" +msgstr "Operatore %s sconosciuto nel dominio %s" #. openerp-web #: addons/web/static/src/js/view_form.js:830 #, python-format msgid "Unknown field %s in domain %s" -msgstr "" +msgstr "Campo %s sconosciuto nel dominio %s" #. openerp-web #: addons/web/static/src/js/view_form.js:868 #, python-format msgid "Unsupported operator %s in domain %s" -msgstr "" +msgstr "Operatore %s non supportato nel dominio %s" #. openerp-web #: addons/web/static/src/js/view_form.js:1225 msgid "Confirm" -msgstr "" +msgstr "Conferma" #. openerp-web #: addons/web/static/src/js/view_form.js:1921 #: addons/web/static/src/js/view_form.js:2578 #: addons/web/static/src/js/view_form.js:2741 msgid "Open: " -msgstr "" +msgstr "Apri: " #. openerp-web #: addons/web/static/src/js/view_form.js:2049 @@ -501,13 +501,13 @@ msgstr "   Crea e modifica..." #: addons/web/static/src/js/view_form.js:2101 #: addons/web/static/src/js/views.js:675 msgid "Search: " -msgstr "" +msgstr "Cerca: " #. openerp-web #: addons/web/static/src/js/view_form.js:2101 #: addons/web/static/src/js/view_form.js:2550 msgid "Create: " -msgstr "" +msgstr "Crea: " #. openerp-web #: addons/web/static/src/js/view_form.js:2661 @@ -520,96 +520,96 @@ msgstr "Aggiungi" #. openerp-web #: addons/web/static/src/js/view_form.js:2721 msgid "Add: " -msgstr "" +msgstr "Aggiungi: " #. openerp-web #: addons/web/static/src/js/view_list.js:8 msgid "List" -msgstr "" +msgstr "Lista" #. openerp-web #: addons/web/static/src/js/view_list.js:269 msgid "Unlimited" -msgstr "" +msgstr "Illimitato" #. openerp-web #: addons/web/static/src/js/view_list.js:305 #, python-format msgid "[%(first_record)d to %(last_record)d] of %(records_count)d" -msgstr "" +msgstr "[%(first_record)d di %(last_record)d] di %(records_count)d" #. openerp-web #: addons/web/static/src/js/view_list.js:524 msgid "Do you really want to remove these records?" -msgstr "" +msgstr "Vuoi veramente cancellare questi record?" #. openerp-web #: addons/web/static/src/js/view_list.js:1230 msgid "Undefined" -msgstr "" +msgstr "Non definito" #. openerp-web #: addons/web/static/src/js/view_list.js:1327 #, python-format msgid "%(page)d/%(page_count)d" -msgstr "" +msgstr "%(page)d/%(page_count)d" #. openerp-web #: addons/web/static/src/js/view_page.js:8 msgid "Page" -msgstr "" +msgstr "Pagina" #. openerp-web #: addons/web/static/src/js/view_page.js:52 msgid "Do you really want to delete this record?" -msgstr "" +msgstr "Vuoi veramente eliminare questo record?" #. openerp-web #: addons/web/static/src/js/view_tree.js:11 msgid "Tree" -msgstr "" +msgstr "Albero" #. openerp-web #: addons/web/static/src/js/views.js:565 addons/web/static/src/xml/base.xml:480 msgid "Fields View Get" -msgstr "" +msgstr "Fields View Get" #. openerp-web #: addons/web/static/src/js/views.js:573 #, python-format msgid "View Log (%s)" -msgstr "" +msgstr "Vedi Log (%s)" #. openerp-web #: addons/web/static/src/js/views.js:600 #, python-format msgid "Model %s fields" -msgstr "" +msgstr "Campi modello %s" #. openerp-web #: addons/web/static/src/js/views.js:610 addons/web/static/src/xml/base.xml:482 msgid "Manage Views" -msgstr "" +msgstr "Gestisci Viste" #. openerp-web #: addons/web/static/src/js/views.js:611 msgid "Could not find current view declaration" -msgstr "" +msgstr "Impossibile trovare la definizione della vista corrente" #. openerp-web #: addons/web/static/src/js/views.js:805 msgid "Translate" -msgstr "" +msgstr "Traduci" #. openerp-web #: addons/web/static/src/js/views.js:807 msgid "Technical translation" -msgstr "" +msgstr "Traduzione tecnica" #. openerp-web #: addons/web/static/src/js/views.js:811 msgid "Other Options" -msgstr "" +msgstr "Altre Opzioni" #. openerp-web #: addons/web/static/src/js/views.js:814 @@ -626,17 +626,17 @@ msgstr "Esporta" #. openerp-web #: addons/web/static/src/js/views.js:825 msgid "Reports" -msgstr "" +msgstr "Reports" #. openerp-web #: addons/web/static/src/js/views.js:825 msgid "Actions" -msgstr "" +msgstr "Azioni" #. openerp-web #: addons/web/static/src/js/views.js:825 msgid "Links" -msgstr "" +msgstr "Links" #. openerp-web #: addons/web/static/src/js/views.js:919 @@ -777,46 +777,48 @@ msgid "" "Your version of OpenERP is unsupported. Support & maintenance services are " "available here:" msgstr "" +"La tua versione di OpenERP non è supportata. Servizi di supporto & " +"manutenzione sono disponibili qui:" #. openerp-web #: addons/web/static/src/xml/base.xml:251 msgid "OpenERP Entreprise" -msgstr "" +msgstr "OpenERP Entreprise" #. openerp-web #: addons/web/static/src/xml/base.xml:256 msgid "OpenERP Enterprise Contract." -msgstr "" +msgstr "Contratto OpenERP Enterprise." #. openerp-web #: addons/web/static/src/xml/base.xml:257 msgid "Your report will be sent to the OpenERP Enterprise team." -msgstr "" +msgstr "Il tuo report verrà inviato all'OpenERP Enterprise team." #. openerp-web #: addons/web/static/src/xml/base.xml:259 msgid "Summary:" -msgstr "" +msgstr "Riepilogo:" #. openerp-web #: addons/web/static/src/xml/base.xml:263 msgid "Description:" -msgstr "" +msgstr "Descrizione:" #. openerp-web #: addons/web/static/src/xml/base.xml:267 msgid "What you did:" -msgstr "" +msgstr "Cosa hai fatto:" #. openerp-web #: addons/web/static/src/xml/base.xml:297 msgid "Invalid username or password" -msgstr "" +msgstr "Password o nome utente non validi" #. openerp-web #: addons/web/static/src/xml/base.xml:306 msgid "Username" -msgstr "" +msgstr "Utente" #. openerp-web #: addons/web/static/src/xml/base.xml:308 @@ -827,12 +829,12 @@ msgstr "Password" #. openerp-web #: addons/web/static/src/xml/base.xml:310 msgid "Log in" -msgstr "" +msgstr "Accedi" #. openerp-web #: addons/web/static/src/xml/base.xml:314 msgid "Manage Databases" -msgstr "" +msgstr "Gestisci Database" #. openerp-web #: addons/web/static/src/xml/base.xml:332 @@ -842,7 +844,7 @@ msgstr "Ritorno al Login" #. openerp-web #: addons/web/static/src/xml/base.xml:353 msgid "Home" -msgstr "" +msgstr "Home" #. openerp-web #: addons/web/static/src/xml/base.xml:363 @@ -852,12 +854,12 @@ msgstr "LOGOUT" #. openerp-web #: addons/web/static/src/xml/base.xml:388 msgid "Fold menu" -msgstr "" +msgstr "Comprimi menù" #. openerp-web #: addons/web/static/src/xml/base.xml:389 msgid "Unfold menu" -msgstr "" +msgstr "Espandi menù" #. openerp-web #: addons/web/static/src/xml/base.xml:454 @@ -872,77 +874,77 @@ msgstr "Disabilita tutti i consigli" #. openerp-web #: addons/web/static/src/xml/base.xml:463 msgid "Add / Remove Shortcut..." -msgstr "" +msgstr "Aggiunti / Rimuovi Scorciatoia..." #. openerp-web #: addons/web/static/src/xml/base.xml:471 msgid "More…" -msgstr "" +msgstr "Altro..." #. openerp-web #: addons/web/static/src/xml/base.xml:477 msgid "Debug View#" -msgstr "" +msgstr "Debug Vista#" #. openerp-web #: addons/web/static/src/xml/base.xml:478 msgid "View Log (perm_read)" -msgstr "" +msgstr "Vedi Log (perm_read)" #. openerp-web #: addons/web/static/src/xml/base.xml:479 msgid "View Fields" -msgstr "" +msgstr "Campi Vista" #. openerp-web #: addons/web/static/src/xml/base.xml:483 msgid "View" -msgstr "" +msgstr "Vista" #. openerp-web #: addons/web/static/src/xml/base.xml:484 msgid "Edit SearchView" -msgstr "" +msgstr "Modifica Search View" #. openerp-web #: addons/web/static/src/xml/base.xml:485 msgid "Edit Action" -msgstr "" +msgstr "Modifica Azione" #. openerp-web #: addons/web/static/src/xml/base.xml:486 msgid "Edit Workflow" -msgstr "" +msgstr "Modifica Workflow" #. openerp-web #: addons/web/static/src/xml/base.xml:491 msgid "ID:" -msgstr "" +msgstr "ID:" #. openerp-web #: addons/web/static/src/xml/base.xml:494 msgid "XML ID:" -msgstr "" +msgstr "XML ID:" #. openerp-web #: addons/web/static/src/xml/base.xml:497 msgid "Creation User:" -msgstr "" +msgstr "Creazione Utente:" #. openerp-web #: addons/web/static/src/xml/base.xml:500 msgid "Creation Date:" -msgstr "" +msgstr "Data Creazione:" #. openerp-web #: addons/web/static/src/xml/base.xml:503 msgid "Latest Modification by:" -msgstr "" +msgstr "Ultima Modifica fatta da:" #. openerp-web #: addons/web/static/src/xml/base.xml:506 msgid "Latest Modification Date:" -msgstr "" +msgstr "Data Ultima Modifica:" #. openerp-web #: addons/web/static/src/xml/base.xml:542 @@ -964,118 +966,118 @@ msgstr "Duplica" #. openerp-web #: addons/web/static/src/xml/base.xml:775 msgid "Add attachment" -msgstr "" +msgstr "Aggiungi allegato" #. openerp-web #: addons/web/static/src/xml/base.xml:801 msgid "Default:" -msgstr "" +msgstr "Default:" #. openerp-web #: addons/web/static/src/xml/base.xml:818 msgid "Condition:" -msgstr "" +msgstr "Condizione:" #. openerp-web #: addons/web/static/src/xml/base.xml:837 msgid "Only you" -msgstr "" +msgstr "Solo tu" #. openerp-web #: addons/web/static/src/xml/base.xml:844 msgid "All users" -msgstr "" +msgstr "Tutti gli utenti" #. openerp-web #: addons/web/static/src/xml/base.xml:851 msgid "Unhandled widget" -msgstr "" +msgstr "Widget non gestito" #. openerp-web #: addons/web/static/src/xml/base.xml:900 msgid "Notebook Page \"" -msgstr "" +msgstr "Notebook Page \"" #. openerp-web #: addons/web/static/src/xml/base.xml:905 #: addons/web/static/src/xml/base.xml:964 msgid "Modifiers:" -msgstr "" +msgstr "Modificatori:" #. openerp-web #: addons/web/static/src/xml/base.xml:931 msgid "(nolabel)" -msgstr "" +msgstr "(senza etichetta)" #. openerp-web #: addons/web/static/src/xml/base.xml:936 msgid "Field:" -msgstr "" +msgstr "Campo:" #. openerp-web #: addons/web/static/src/xml/base.xml:940 msgid "Object:" -msgstr "" +msgstr "Oggetto:" #. openerp-web #: addons/web/static/src/xml/base.xml:944 msgid "Type:" -msgstr "" +msgstr "Tipo:" #. openerp-web #: addons/web/static/src/xml/base.xml:948 msgid "Widget:" -msgstr "" +msgstr "Widget:" #. openerp-web #: addons/web/static/src/xml/base.xml:952 msgid "Size:" -msgstr "" +msgstr "Dimensione:" #. openerp-web #: addons/web/static/src/xml/base.xml:956 msgid "Context:" -msgstr "" +msgstr "Context:" #. openerp-web #: addons/web/static/src/xml/base.xml:960 msgid "Domain:" -msgstr "" +msgstr "Domain:" #. openerp-web #: addons/web/static/src/xml/base.xml:968 msgid "Change default:" -msgstr "" +msgstr "Cambia default:" #. openerp-web #: addons/web/static/src/xml/base.xml:972 msgid "On change:" -msgstr "" +msgstr "On change:" #. openerp-web #: addons/web/static/src/xml/base.xml:976 msgid "Relation:" -msgstr "" +msgstr "Relazione:" #. openerp-web #: addons/web/static/src/xml/base.xml:980 msgid "Selection:" -msgstr "" +msgstr "Selezione:" #. openerp-web #: addons/web/static/src/xml/base.xml:1020 msgid "Send an e-mail with your default e-mail client" -msgstr "" +msgstr "Invia un'email con il tuo client email predefinito" #. openerp-web #: addons/web/static/src/xml/base.xml:1034 msgid "Open this resource" -msgstr "" +msgstr "Apri questa risorsa" #. openerp-web #: addons/web/static/src/xml/base.xml:1056 msgid "Select date" -msgstr "" +msgstr "Seleziona data" #. openerp-web #: addons/web/static/src/xml/base.xml:1090 @@ -1101,7 +1103,7 @@ msgstr "..." #: addons/web/static/src/xml/base.xml:1155 #: addons/web/static/src/xml/base.xml:1198 msgid "Set Image" -msgstr "" +msgstr "Imposta Immagine" #. openerp-web #: addons/web/static/src/xml/base.xml:1163 @@ -1115,7 +1117,7 @@ msgstr "Pulisci" #: addons/web/static/src/xml/base.xml:1172 #: addons/web/static/src/xml/base.xml:1223 msgid "Uploading ..." -msgstr "" +msgstr "Caricando ..." #. openerp-web #: addons/web/static/src/xml/base.xml:1200 @@ -1132,57 +1134,57 @@ msgstr "Salva come" #. openerp-web #: addons/web/static/src/xml/base.xml:1238 msgid "Button" -msgstr "" +msgstr "Pulsante" #. openerp-web #: addons/web/static/src/xml/base.xml:1241 msgid "(no string)" -msgstr "" +msgstr "(no string)" #. openerp-web #: addons/web/static/src/xml/base.xml:1248 msgid "Special:" -msgstr "" +msgstr "Speciale:" #. openerp-web #: addons/web/static/src/xml/base.xml:1253 msgid "Button Type:" -msgstr "" +msgstr "Tipo Pulsante:" #. openerp-web #: addons/web/static/src/xml/base.xml:1257 msgid "Method:" -msgstr "" +msgstr "Metodo:" #. openerp-web #: addons/web/static/src/xml/base.xml:1261 msgid "Action ID:" -msgstr "" +msgstr "Action ID:" #. openerp-web #: addons/web/static/src/xml/base.xml:1271 msgid "Search" -msgstr "" +msgstr "Cerca" #. openerp-web #: addons/web/static/src/xml/base.xml:1279 msgid "Filters" -msgstr "" +msgstr "Filtri" #. openerp-web #: addons/web/static/src/xml/base.xml:1280 msgid "-- Filters --" -msgstr "" +msgstr "-- Filtri --" #. openerp-web #: addons/web/static/src/xml/base.xml:1289 msgid "-- Actions --" -msgstr "" +msgstr "-- Azioni --" #. openerp-web #: addons/web/static/src/xml/base.xml:1290 msgid "Add Advanced Filter" -msgstr "" +msgstr "Aggiungi Filtro Avanzato" #. openerp-web #: addons/web/static/src/xml/base.xml:1291 @@ -1207,22 +1209,22 @@ msgstr "(Eventuali filtri esistenti con lo stesso nome saranno rimpiazzati)" #. openerp-web #: addons/web/static/src/xml/base.xml:1305 msgid "Select Dashboard to add this filter to:" -msgstr "" +msgstr "Seleziona la Dashboard alla quale aggiungere questo filtro:" #. openerp-web #: addons/web/static/src/xml/base.xml:1309 msgid "Title of new Dashboard item:" -msgstr "" +msgstr "Titolo del nuovo elemento Dashboard" #. openerp-web #: addons/web/static/src/xml/base.xml:1416 msgid "Advanced Filters" -msgstr "" +msgstr "Filtri Avanzati" #. openerp-web #: addons/web/static/src/xml/base.xml:1426 msgid "Any of the following conditions must match" -msgstr "" +msgstr "Una delle seguenti condizioni deve essere vera" #. openerp-web #: addons/web/static/src/xml/base.xml:1427 @@ -1262,6 +1264,10 @@ msgid "" " You can export all data or only the fields that can be " "reimported after modification." msgstr "" +"Questo wizard esporterà in un file CSV tutti i dati che soddisfano il " +"criterio di ricerca corrente.\n" +" Puoi esportare tutti i dati o solo i campi che possono essere " +"importati dopo la modifica." #. openerp-web #: addons/web/static/src/xml/base.xml:1618 @@ -1271,7 +1277,7 @@ msgstr "Tipo di esportazione:" #. openerp-web #: addons/web/static/src/xml/base.xml:1620 msgid "Import Compatible Export" -msgstr "" +msgstr "Importa Export Compatibile" #. openerp-web #: addons/web/static/src/xml/base.xml:1621 @@ -1344,6 +1350,9 @@ msgid "" "Select a .CSV file to import. If you need a sample of file to import,\n" " you should use the export tool with the \"Import Compatible\" option." msgstr "" +"Seleziona un CSV da importare. Se hai bisogno di un esempio da importare,\n" +" puoi usare il tool di esportazione usando l'opzione \"Import " +"Compatibile\"." #. openerp-web #: addons/web/static/src/xml/base.xml:1747 @@ -1388,7 +1397,7 @@ msgstr "UTF-8" #. openerp-web #: addons/web/static/src/xml/base.xml:1773 msgid "Latin 1" -msgstr "" +msgstr "Latin 1" #. openerp-web #: addons/web/static/src/xml/base.xml:1776 @@ -1401,6 +1410,8 @@ msgid "" "For use if CSV files have titles on multiple lines, skips more than a single " "line during import" msgstr "" +"Da usare se i file CSV hanno i titoli su linee multiple, salta le linee non " +"singole durante l'import" #. openerp-web #: addons/web/static/src/xml/base.xml:1803 @@ -1415,7 +1426,7 @@ msgstr "Ecco un anteprima del file che non si è riuscito ad importare:" #. openerp-web #: addons/web/static/src/xml/base.xml:1812 msgid "Activate the developper mode" -msgstr "" +msgstr "Attiva il modo sviluppatore" #. openerp-web #: addons/web/static/src/xml/base.xml:1814 @@ -1425,7 +1436,7 @@ msgstr "Versione" #. openerp-web #: addons/web/static/src/xml/base.xml:1815 msgid "Copyright © 2004-TODAY OpenERP SA. All Rights Reserved." -msgstr "" +msgstr "Copyright © 2004-TODAY OpenERP SA. All Rights Reserved." #. openerp-web #: addons/web/static/src/xml/base.xml:1816 @@ -1440,7 +1451,7 @@ msgstr "OpenERP SA Company" #. openerp-web #: addons/web/static/src/xml/base.xml:1819 msgid "Licenced under the terms of" -msgstr "" +msgstr "Rilasciato sotto i termini della" #. openerp-web #: addons/web/static/src/xml/base.xml:1820 @@ -1450,9 +1461,9 @@ msgstr "GNU Affero General Public License" #. openerp-web #: addons/web/static/src/xml/base.xml:1822 msgid "For more information visit" -msgstr "" +msgstr "Per maggiori informazioni visita" #. openerp-web #: addons/web/static/src/xml/base.xml:1823 msgid "OpenERP.com" -msgstr "" +msgstr "OpenERP.com" diff --git a/addons/web/i18n/ja.po b/addons/web/i18n/ja.po index f9433662bfe..df8e5be9202 100644 --- a/addons/web/i18n/ja.po +++ b/addons/web/i18n/ja.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-14 15:27+0100\n" -"PO-Revision-Date: 2012-02-11 21:36+0000\n" +"PO-Revision-Date: 2012-03-14 07:11+0000\n" "Last-Translator: Masaki Yamaya \n" "Language-Team: Japanese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-15 05:43+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-03-15 04:53+0000\n" +"X-Generator: Launchpad (build 14933)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:172 @@ -24,8 +24,10 @@ msgstr "" #: addons/web/static/src/js/view_form.js:419 #: addons/web/static/src/js/view_form.js:1233 #: addons/web/static/src/xml/base.xml:1695 +#: addons/web/static/src/js/view_form.js:424 +#: addons/web/static/src/js/view_form.js:1239 msgid "Ok" -msgstr "" +msgstr "正常" #. openerp-web #: addons/web/static/src/js/chrome.js:180 @@ -35,18 +37,18 @@ msgstr "OpenERPエンタープライズレポートを送る" #. openerp-web #: addons/web/static/src/js/chrome.js:194 msgid "Dont send" -msgstr "" +msgstr "送らない" #. openerp-web #: addons/web/static/src/js/chrome.js:256 #, python-format msgid "Loading (%d)" -msgstr "" +msgstr "ロード中 (%d)" #. openerp-web #: addons/web/static/src/js/chrome.js:288 msgid "Invalid database name" -msgstr "" +msgstr "無効なデータベース名" #. openerp-web #: addons/web/static/src/js/chrome.js:483 @@ -56,29 +58,29 @@ msgstr "" #. openerp-web #: addons/web/static/src/js/chrome.js:484 msgid "Database backed up successfully" -msgstr "" +msgstr "データベースは正常にバックアップされました" #. openerp-web #: addons/web/static/src/js/chrome.js:527 msgid "Restored" -msgstr "" +msgstr "リストアされました" #. openerp-web #: addons/web/static/src/js/chrome.js:527 msgid "Database restored successfully" -msgstr "" +msgstr "データベースは正常にリストアされました" #. openerp-web #: addons/web/static/src/js/chrome.js:708 #: addons/web/static/src/xml/base.xml:359 msgid "About" -msgstr "" +msgstr "について" #. openerp-web #: addons/web/static/src/js/chrome.js:787 #: addons/web/static/src/xml/base.xml:356 msgid "Preferences" -msgstr "" +msgstr "個人設定" #. openerp-web #: addons/web/static/src/js/chrome.js:790 @@ -92,44 +94,49 @@ msgstr "" #: addons/web/static/src/xml/base.xml:1496 #: addons/web/static/src/xml/base.xml:1506 #: addons/web/static/src/xml/base.xml:1515 +#: addons/web/static/src/js/search.js:293 +#: addons/web/static/src/js/view_form.js:1234 msgid "Cancel" -msgstr "" +msgstr "キャンセル" #. openerp-web #: addons/web/static/src/js/chrome.js:791 msgid "Change password" -msgstr "" +msgstr "パスワードの変更" #. openerp-web #: addons/web/static/src/js/chrome.js:792 #: addons/web/static/src/js/view_editor.js:73 -#: addons/web/static/src/js/views.js:962 addons/web/static/src/xml/base.xml:737 +#: addons/web/static/src/js/views.js:962 +#: addons/web/static/src/xml/base.xml:737 #: addons/web/static/src/xml/base.xml:1500 #: addons/web/static/src/xml/base.xml:1514 msgid "Save" -msgstr "" +msgstr "保存" #. openerp-web #: addons/web/static/src/js/chrome.js:811 #: addons/web/static/src/xml/base.xml:226 #: addons/web/static/src/xml/base.xml:1729 msgid "Change Password" -msgstr "" +msgstr "パスワードの変更" #. openerp-web #: addons/web/static/src/js/chrome.js:1096 +#: addons/web/static/src/js/chrome.js:1100 msgid "OpenERP - Unsupported/Community Version" -msgstr "" +msgstr "OpenERP - サポート無し/コミュニティバージョン" #. openerp-web #: addons/web/static/src/js/chrome.js:1131 +#: addons/web/static/src/js/chrome.js:1135 msgid "Client Error" -msgstr "" +msgstr "クライアントのエラー" #. openerp-web #: addons/web/static/src/js/data_export.js:6 msgid "Export Data" -msgstr "" +msgstr "データのエクスポート" #. openerp-web #: addons/web/static/src/js/data_export.js:19 @@ -139,13 +146,15 @@ msgstr "" #: addons/web/static/src/js/view_form.js:692 #: addons/web/static/src/js/view_form.js:3044 #: addons/web/static/src/js/views.js:963 +#: addons/web/static/src/js/view_form.js:698 +#: addons/web/static/src/js/view_form.js:3067 msgid "Close" -msgstr "" +msgstr "閉じる" #. openerp-web #: addons/web/static/src/js/data_export.js:20 msgid "Export To File" -msgstr "" +msgstr "ファイルにエクスポート" #. openerp-web #: addons/web/static/src/js/data_export.js:125 @@ -165,29 +174,32 @@ msgstr "" #. openerp-web #: addons/web/static/src/js/data_import.js:34 msgid "Import Data" -msgstr "" +msgstr "データをインポート" #. openerp-web #: addons/web/static/src/js/data_import.js:70 msgid "Import File" -msgstr "" +msgstr "ファイルをインポート" #. openerp-web #: addons/web/static/src/js/data_import.js:105 msgid "External ID" -msgstr "" +msgstr "外部ID" #. openerp-web #: addons/web/static/src/js/formats.js:300 #: addons/web/static/src/js/view_page.js:245 +#: addons/web/static/src/js/formats.js:322 +#: addons/web/static/src/js/view_page.js:251 msgid "Download" -msgstr "" +msgstr "ダウンロード" #. openerp-web #: addons/web/static/src/js/formats.js:305 +#: addons/web/static/src/js/formats.js:327 #, python-format msgid "Download \"%s\"" -msgstr "" +msgstr "ダウンロード \"%s\"" #. openerp-web #: addons/web/static/src/js/search.js:191 @@ -197,66 +209,77 @@ msgstr "" #. openerp-web #: addons/web/static/src/js/search.js:237 msgid "Filter Entry" -msgstr "" +msgstr "フィルター項目" #. openerp-web #: addons/web/static/src/js/search.js:242 #: addons/web/static/src/js/search.js:291 +#: addons/web/static/src/js/search.js:296 msgid "OK" -msgstr "" +msgstr "はい" #. openerp-web #: addons/web/static/src/js/search.js:286 #: addons/web/static/src/xml/base.xml:1292 +#: addons/web/static/src/js/search.js:291 msgid "Add to Dashboard" -msgstr "" +msgstr "ダッシュボードに追加" #. openerp-web #: addons/web/static/src/js/search.js:415 +#: addons/web/static/src/js/search.js:420 msgid "Invalid Search" -msgstr "" +msgstr "無効な検索" #. openerp-web #: addons/web/static/src/js/search.js:415 +#: addons/web/static/src/js/search.js:420 msgid "triggered from search view" msgstr "" #. openerp-web #: addons/web/static/src/js/search.js:503 +#: addons/web/static/src/js/search.js:508 #, python-format msgid "Incorrect value for field %(fieldname)s: [%(value)s] is %(message)s" msgstr "" #. openerp-web #: addons/web/static/src/js/search.js:839 +#: addons/web/static/src/js/search.js:844 msgid "not a valid integer" -msgstr "" +msgstr "無効な整数" #. openerp-web #: addons/web/static/src/js/search.js:853 +#: addons/web/static/src/js/search.js:858 msgid "not a valid number" -msgstr "" +msgstr "無効な数値" #. openerp-web #: addons/web/static/src/js/search.js:931 #: addons/web/static/src/xml/base.xml:968 +#: addons/web/static/src/js/search.js:936 msgid "Yes" -msgstr "" +msgstr "はい" #. openerp-web #: addons/web/static/src/js/search.js:932 +#: addons/web/static/src/js/search.js:937 msgid "No" -msgstr "" +msgstr "いいえ" #. openerp-web #: addons/web/static/src/js/search.js:1290 +#: addons/web/static/src/js/search.js:1295 msgid "contains" -msgstr "" +msgstr "次を含む" #. openerp-web #: addons/web/static/src/js/search.js:1291 +#: addons/web/static/src/js/search.js:1296 msgid "doesn't contain" -msgstr "" +msgstr "含まない" #. openerp-web #: addons/web/static/src/js/search.js:1292 @@ -264,8 +287,13 @@ msgstr "" #: addons/web/static/src/js/search.js:1325 #: addons/web/static/src/js/search.js:1344 #: addons/web/static/src/js/search.js:1365 +#: addons/web/static/src/js/search.js:1297 +#: addons/web/static/src/js/search.js:1311 +#: addons/web/static/src/js/search.js:1330 +#: addons/web/static/src/js/search.js:1349 +#: addons/web/static/src/js/search.js:1370 msgid "is equal to" -msgstr "" +msgstr "は次と一致する" #. openerp-web #: addons/web/static/src/js/search.js:1293 @@ -273,8 +301,13 @@ msgstr "" #: addons/web/static/src/js/search.js:1326 #: addons/web/static/src/js/search.js:1345 #: addons/web/static/src/js/search.js:1366 +#: addons/web/static/src/js/search.js:1298 +#: addons/web/static/src/js/search.js:1312 +#: addons/web/static/src/js/search.js:1331 +#: addons/web/static/src/js/search.js:1350 +#: addons/web/static/src/js/search.js:1371 msgid "is not equal to" -msgstr "" +msgstr "は次と一致しない" #. openerp-web #: addons/web/static/src/js/search.js:1294 @@ -282,8 +315,13 @@ msgstr "" #: addons/web/static/src/js/search.js:1327 #: addons/web/static/src/js/search.js:1346 #: addons/web/static/src/js/search.js:1367 +#: addons/web/static/src/js/search.js:1299 +#: addons/web/static/src/js/search.js:1313 +#: addons/web/static/src/js/search.js:1332 +#: addons/web/static/src/js/search.js:1351 +#: addons/web/static/src/js/search.js:1372 msgid "greater than" -msgstr "" +msgstr "次より大きい" #. openerp-web #: addons/web/static/src/js/search.js:1295 @@ -291,8 +329,13 @@ msgstr "" #: addons/web/static/src/js/search.js:1328 #: addons/web/static/src/js/search.js:1347 #: addons/web/static/src/js/search.js:1368 +#: addons/web/static/src/js/search.js:1300 +#: addons/web/static/src/js/search.js:1314 +#: addons/web/static/src/js/search.js:1333 +#: addons/web/static/src/js/search.js:1352 +#: addons/web/static/src/js/search.js:1373 msgid "less than" -msgstr "" +msgstr "次より小さい" #. openerp-web #: addons/web/static/src/js/search.js:1296 @@ -300,8 +343,13 @@ msgstr "" #: addons/web/static/src/js/search.js:1329 #: addons/web/static/src/js/search.js:1348 #: addons/web/static/src/js/search.js:1369 +#: addons/web/static/src/js/search.js:1301 +#: addons/web/static/src/js/search.js:1315 +#: addons/web/static/src/js/search.js:1334 +#: addons/web/static/src/js/search.js:1353 +#: addons/web/static/src/js/search.js:1374 msgid "greater or equal than" -msgstr "" +msgstr "次より大きいか等しい" #. openerp-web #: addons/web/static/src/js/search.js:1297 @@ -309,27 +357,37 @@ msgstr "" #: addons/web/static/src/js/search.js:1330 #: addons/web/static/src/js/search.js:1349 #: addons/web/static/src/js/search.js:1370 +#: addons/web/static/src/js/search.js:1302 +#: addons/web/static/src/js/search.js:1316 +#: addons/web/static/src/js/search.js:1335 +#: addons/web/static/src/js/search.js:1354 +#: addons/web/static/src/js/search.js:1375 msgid "less or equal than" -msgstr "" +msgstr "次より小さいか等しい" #. openerp-web #: addons/web/static/src/js/search.js:1360 #: addons/web/static/src/js/search.js:1383 +#: addons/web/static/src/js/search.js:1365 +#: addons/web/static/src/js/search.js:1388 msgid "is" -msgstr "" +msgstr "が次である" #. openerp-web #: addons/web/static/src/js/search.js:1384 +#: addons/web/static/src/js/search.js:1389 msgid "is not" -msgstr "" +msgstr "は次ではない" #. openerp-web #: addons/web/static/src/js/search.js:1396 +#: addons/web/static/src/js/search.js:1401 msgid "is true" -msgstr "" +msgstr "は正しい" #. openerp-web #: addons/web/static/src/js/search.js:1397 +#: addons/web/static/src/js/search.js:1402 msgid "is false" msgstr "" @@ -424,51 +482,60 @@ msgstr "" #. openerp-web #: addons/web/static/src/js/view_form.js:123 #: addons/web/static/src/js/view_form.js:686 +#: addons/web/static/src/js/view_form.js:692 msgid "Set Default" msgstr "" #. openerp-web #: addons/web/static/src/js/view_form.js:469 +#: addons/web/static/src/js/view_form.js:475 msgid "" "Warning, the record has been modified, your changes will be discarded." msgstr "" #. openerp-web #: addons/web/static/src/js/view_form.js:693 +#: addons/web/static/src/js/view_form.js:699 msgid "Save default" msgstr "" #. openerp-web #: addons/web/static/src/js/view_form.js:754 +#: addons/web/static/src/js/view_form.js:760 msgid "Attachments" msgstr "" #. openerp-web #: addons/web/static/src/js/view_form.js:792 +#: addons/web/static/src/js/view_form.js:798 #, python-format msgid "Do you really want to delete the attachment %s?" msgstr "" #. openerp-web #: addons/web/static/src/js/view_form.js:822 +#: addons/web/static/src/js/view_form.js:828 #, python-format msgid "Unknown operator %s in domain %s" msgstr "" #. openerp-web #: addons/web/static/src/js/view_form.js:830 +#: addons/web/static/src/js/view_form.js:836 #, python-format msgid "Unknown field %s in domain %s" msgstr "" #. openerp-web #: addons/web/static/src/js/view_form.js:868 +#: addons/web/static/src/js/view_form.js:874 #, python-format msgid "Unsupported operator %s in domain %s" msgstr "" #. openerp-web #: addons/web/static/src/js/view_form.js:1225 +#: addons/web/static/src/js/view_form.js:1231 msgid "Confirm" msgstr "" @@ -476,34 +543,43 @@ msgstr "" #: addons/web/static/src/js/view_form.js:1921 #: addons/web/static/src/js/view_form.js:2578 #: addons/web/static/src/js/view_form.js:2741 +#: addons/web/static/src/js/view_form.js:1933 +#: addons/web/static/src/js/view_form.js:2590 +#: addons/web/static/src/js/view_form.js:2760 msgid "Open: " msgstr "" #. openerp-web #: addons/web/static/src/js/view_form.js:2049 +#: addons/web/static/src/js/view_form.js:2061 msgid "   Search More..." msgstr "" #. openerp-web #: addons/web/static/src/js/view_form.js:2062 +#: addons/web/static/src/js/view_form.js:2074 #, python-format msgid "   Create \"%s\"" msgstr "" #. openerp-web #: addons/web/static/src/js/view_form.js:2068 +#: addons/web/static/src/js/view_form.js:2080 msgid "   Create and Edit..." msgstr "" #. openerp-web #: addons/web/static/src/js/view_form.js:2101 #: addons/web/static/src/js/views.js:675 +#: addons/web/static/src/js/view_form.js:2113 msgid "Search: " msgstr "" #. openerp-web #: addons/web/static/src/js/view_form.js:2101 #: addons/web/static/src/js/view_form.js:2550 +#: addons/web/static/src/js/view_form.js:2113 +#: addons/web/static/src/js/view_form.js:2562 msgid "Create: " msgstr "" @@ -512,11 +588,13 @@ msgstr "" #: addons/web/static/src/xml/base.xml:750 #: addons/web/static/src/xml/base.xml:772 #: addons/web/static/src/xml/base.xml:1646 +#: addons/web/static/src/js/view_form.js:2680 msgid "Add" msgstr "" #. openerp-web #: addons/web/static/src/js/view_form.js:2721 +#: addons/web/static/src/js/view_form.js:2740 msgid "Add: " msgstr "" @@ -532,22 +610,26 @@ msgstr "" #. openerp-web #: addons/web/static/src/js/view_list.js:305 +#: addons/web/static/src/js/view_list.js:309 #, python-format msgid "[%(first_record)d to %(last_record)d] of %(records_count)d" msgstr "" #. openerp-web #: addons/web/static/src/js/view_list.js:524 +#: addons/web/static/src/js/view_list.js:528 msgid "Do you really want to remove these records?" msgstr "" #. openerp-web #: addons/web/static/src/js/view_list.js:1230 +#: addons/web/static/src/js/view_list.js:1232 msgid "Undefined" msgstr "" #. openerp-web #: addons/web/static/src/js/view_list.js:1327 +#: addons/web/static/src/js/view_list.js:1331 #, python-format msgid "%(page)d/%(page_count)d" msgstr "" @@ -568,7 +650,8 @@ msgid "Tree" msgstr "" #. openerp-web -#: addons/web/static/src/js/views.js:565 addons/web/static/src/xml/base.xml:480 +#: addons/web/static/src/js/views.js:565 +#: addons/web/static/src/xml/base.xml:480 msgid "Fields View Get" msgstr "" @@ -585,7 +668,8 @@ msgid "Model %s fields" msgstr "" #. openerp-web -#: addons/web/static/src/js/views.js:610 addons/web/static/src/xml/base.xml:482 +#: addons/web/static/src/js/views.js:610 +#: addons/web/static/src/xml/base.xml:482 msgid "Manage Views" msgstr "" @@ -652,12 +736,14 @@ msgid "Translations" msgstr "" #. openerp-web -#: addons/web/static/src/xml/base.xml:44 addons/web/static/src/xml/base.xml:315 +#: addons/web/static/src/xml/base.xml:44 +#: addons/web/static/src/xml/base.xml:315 msgid "Powered by" msgstr "" #. openerp-web -#: addons/web/static/src/xml/base.xml:44 addons/web/static/src/xml/base.xml:315 +#: addons/web/static/src/xml/base.xml:44 +#: addons/web/static/src/xml/base.xml:315 #: addons/web/static/src/xml/base.xml:1813 msgid "OpenERP" msgstr "" @@ -673,12 +759,14 @@ msgid "CREATE DATABASE" msgstr "" #. openerp-web -#: addons/web/static/src/xml/base.xml:68 addons/web/static/src/xml/base.xml:211 +#: addons/web/static/src/xml/base.xml:68 +#: addons/web/static/src/xml/base.xml:211 msgid "Master password:" msgstr "" #. openerp-web -#: addons/web/static/src/xml/base.xml:72 addons/web/static/src/xml/base.xml:191 +#: addons/web/static/src/xml/base.xml:72 +#: addons/web/static/src/xml/base.xml:191 msgid "New database name:" msgstr "" diff --git a/addons/web/i18n/ka.po b/addons/web/i18n/ka.po new file mode 100644 index 00000000000..4052f49a96f --- /dev/null +++ b/addons/web/i18n/ka.po @@ -0,0 +1,1548 @@ +# Georgian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-03-14 22:10+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Georgian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-15 04:53+0000\n" +"X-Generator: Launchpad (build 14933)\n" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:172 +#: addons/web/static/src/js/chrome.js:198 +#: addons/web/static/src/js/chrome.js:414 +#: addons/web/static/src/js/view_form.js:419 +#: addons/web/static/src/js/view_form.js:1233 +#: addons/web/static/src/xml/base.xml:1695 +#: addons/web/static/src/js/view_form.js:424 +#: addons/web/static/src/js/view_form.js:1239 +msgid "Ok" +msgstr "ოკ" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:180 +msgid "Send OpenERP Enterprise Report" +msgstr "გააგზავნე OpenERP რეპორტი" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:194 +msgid "Dont send" +msgstr "არ გააგზავნო" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:256 +#, python-format +msgid "Loading (%d)" +msgstr "იტვირთება (%d)" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:288 +msgid "Invalid database name" +msgstr "არასწორი ბაზის სახელი" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:483 +msgid "Backed" +msgstr "დარეზერვებული" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:484 +msgid "Database backed up successfully" +msgstr "მონაცემთა ბაზა დარეზერვდა წარმატებით" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:527 +msgid "Restored" +msgstr "აღდგენილია" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:527 +msgid "Database restored successfully" +msgstr "მონაცემთა ბაზა აღდგენილია წარმატებით" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:708 +#: addons/web/static/src/xml/base.xml:359 +msgid "About" +msgstr "შესახებ" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:787 +#: addons/web/static/src/xml/base.xml:356 +msgid "Preferences" +msgstr "პარამეტრები" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:790 +#: addons/web/static/src/js/search.js:239 +#: addons/web/static/src/js/search.js:288 +#: addons/web/static/src/js/view_editor.js:95 +#: addons/web/static/src/js/view_editor.js:836 +#: addons/web/static/src/js/view_editor.js:962 +#: addons/web/static/src/js/view_form.js:1228 +#: addons/web/static/src/xml/base.xml:738 +#: addons/web/static/src/xml/base.xml:1496 +#: addons/web/static/src/xml/base.xml:1506 +#: addons/web/static/src/xml/base.xml:1515 +#: addons/web/static/src/js/search.js:293 +#: addons/web/static/src/js/view_form.js:1234 +msgid "Cancel" +msgstr "შეწყვეტა" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:791 +msgid "Change password" +msgstr "პაროლის შეცვლა" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:792 +#: addons/web/static/src/js/view_editor.js:73 +#: addons/web/static/src/js/views.js:962 +#: addons/web/static/src/xml/base.xml:737 +#: addons/web/static/src/xml/base.xml:1500 +#: addons/web/static/src/xml/base.xml:1514 +msgid "Save" +msgstr "შენახვა" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:811 +#: addons/web/static/src/xml/base.xml:226 +#: addons/web/static/src/xml/base.xml:1729 +msgid "Change Password" +msgstr "პაროლის შეცვლა" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:1096 +#: addons/web/static/src/js/chrome.js:1100 +msgid "OpenERP - Unsupported/Community Version" +msgstr "OpenERP - მხარდაჭერის გარეშე/საზოგადოებრივი ვერსია" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:1131 +#: addons/web/static/src/js/chrome.js:1135 +msgid "Client Error" +msgstr "შეცდომა მომხმარებლის მხარეს" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:6 +msgid "Export Data" +msgstr "მონაცემების ექსპორტი" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:19 +#: addons/web/static/src/js/data_import.js:69 +#: addons/web/static/src/js/view_editor.js:49 +#: addons/web/static/src/js/view_editor.js:398 +#: addons/web/static/src/js/view_form.js:692 +#: addons/web/static/src/js/view_form.js:3044 +#: addons/web/static/src/js/views.js:963 +#: addons/web/static/src/js/view_form.js:698 +#: addons/web/static/src/js/view_form.js:3067 +msgid "Close" +msgstr "დახურვა" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:20 +msgid "Export To File" +msgstr "ფაილში ექსპორტი" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:125 +msgid "Please enter save field list name" +msgstr "გთხოვთ განსაზღვროთ შესანახი ველის სიის სახელი" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:360 +msgid "Please select fields to save export list..." +msgstr "გთხოვთ აირჩიოთ ველები შესანახი სიის ექსპორტისთვის" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:373 +msgid "Please select fields to export..." +msgstr "გთხოვთ აირჩიოთ ველები ექსპორტისთვის..." + +#. openerp-web +#: addons/web/static/src/js/data_import.js:34 +msgid "Import Data" +msgstr "მონაცემების იმპორტი" + +#. openerp-web +#: addons/web/static/src/js/data_import.js:70 +msgid "Import File" +msgstr "ფაილის იმპორტი" + +#. openerp-web +#: addons/web/static/src/js/data_import.js:105 +msgid "External ID" +msgstr "გარე ID" + +#. openerp-web +#: addons/web/static/src/js/formats.js:300 +#: addons/web/static/src/js/view_page.js:245 +#: addons/web/static/src/js/formats.js:322 +#: addons/web/static/src/js/view_page.js:251 +msgid "Download" +msgstr "ჩამოტვირთვა" + +#. openerp-web +#: addons/web/static/src/js/formats.js:305 +#: addons/web/static/src/js/formats.js:327 +#, python-format +msgid "Download \"%s\"" +msgstr "ჩამოტვირთვა \"%s\"" + +#. openerp-web +#: addons/web/static/src/js/search.js:191 +msgid "Filter disabled due to invalid syntax" +msgstr "ფილტრი გაუქმდა არასწორი სინტაქსის მიზეზით" + +#. openerp-web +#: addons/web/static/src/js/search.js:237 +msgid "Filter Entry" +msgstr "ჩანაწერის გაფილტრვა" + +#. openerp-web +#: addons/web/static/src/js/search.js:242 +#: addons/web/static/src/js/search.js:291 +#: addons/web/static/src/js/search.js:296 +msgid "OK" +msgstr "ოკ" + +#. openerp-web +#: addons/web/static/src/js/search.js:286 +#: addons/web/static/src/xml/base.xml:1292 +#: addons/web/static/src/js/search.js:291 +msgid "Add to Dashboard" +msgstr "საინფორმაციო დაფის დამატება" + +#. openerp-web +#: addons/web/static/src/js/search.js:415 +#: addons/web/static/src/js/search.js:420 +msgid "Invalid Search" +msgstr "არასწორი ძებნა" + +#. openerp-web +#: addons/web/static/src/js/search.js:415 +#: addons/web/static/src/js/search.js:420 +msgid "triggered from search view" +msgstr "ინიცირებულია ძიების ვიუდან" + +#. openerp-web +#: addons/web/static/src/js/search.js:503 +#: addons/web/static/src/js/search.js:508 +#, python-format +msgid "Incorrect value for field %(fieldname)s: [%(value)s] is %(message)s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:839 +#: addons/web/static/src/js/search.js:844 +msgid "not a valid integer" +msgstr "არასწორი ინტეჯერი" + +#. openerp-web +#: addons/web/static/src/js/search.js:853 +#: addons/web/static/src/js/search.js:858 +msgid "not a valid number" +msgstr "არასწორი ციფრი" + +#. openerp-web +#: addons/web/static/src/js/search.js:931 +#: addons/web/static/src/xml/base.xml:968 +#: addons/web/static/src/js/search.js:936 +msgid "Yes" +msgstr "დიახ" + +#. openerp-web +#: addons/web/static/src/js/search.js:932 +#: addons/web/static/src/js/search.js:937 +msgid "No" +msgstr "არა" + +#. openerp-web +#: addons/web/static/src/js/search.js:1290 +#: addons/web/static/src/js/search.js:1295 +msgid "contains" +msgstr "შეიცავს" + +#. openerp-web +#: addons/web/static/src/js/search.js:1291 +#: addons/web/static/src/js/search.js:1296 +msgid "doesn't contain" +msgstr "არ შეიცავს" + +#. openerp-web +#: addons/web/static/src/js/search.js:1292 +#: addons/web/static/src/js/search.js:1306 +#: addons/web/static/src/js/search.js:1325 +#: addons/web/static/src/js/search.js:1344 +#: addons/web/static/src/js/search.js:1365 +#: addons/web/static/src/js/search.js:1297 +#: addons/web/static/src/js/search.js:1311 +#: addons/web/static/src/js/search.js:1330 +#: addons/web/static/src/js/search.js:1349 +#: addons/web/static/src/js/search.js:1370 +msgid "is equal to" +msgstr "უდრის" + +#. openerp-web +#: addons/web/static/src/js/search.js:1293 +#: addons/web/static/src/js/search.js:1307 +#: addons/web/static/src/js/search.js:1326 +#: addons/web/static/src/js/search.js:1345 +#: addons/web/static/src/js/search.js:1366 +#: addons/web/static/src/js/search.js:1298 +#: addons/web/static/src/js/search.js:1312 +#: addons/web/static/src/js/search.js:1331 +#: addons/web/static/src/js/search.js:1350 +#: addons/web/static/src/js/search.js:1371 +msgid "is not equal to" +msgstr "არ უდრის" + +#. openerp-web +#: addons/web/static/src/js/search.js:1294 +#: addons/web/static/src/js/search.js:1308 +#: addons/web/static/src/js/search.js:1327 +#: addons/web/static/src/js/search.js:1346 +#: addons/web/static/src/js/search.js:1367 +#: addons/web/static/src/js/search.js:1299 +#: addons/web/static/src/js/search.js:1313 +#: addons/web/static/src/js/search.js:1332 +#: addons/web/static/src/js/search.js:1351 +#: addons/web/static/src/js/search.js:1372 +msgid "greater than" +msgstr "მეტია ვიდრე" + +#. openerp-web +#: addons/web/static/src/js/search.js:1295 +#: addons/web/static/src/js/search.js:1309 +#: addons/web/static/src/js/search.js:1328 +#: addons/web/static/src/js/search.js:1347 +#: addons/web/static/src/js/search.js:1368 +#: addons/web/static/src/js/search.js:1300 +#: addons/web/static/src/js/search.js:1314 +#: addons/web/static/src/js/search.js:1333 +#: addons/web/static/src/js/search.js:1352 +#: addons/web/static/src/js/search.js:1373 +msgid "less than" +msgstr "ნაკლებია ვიდრე" + +#. openerp-web +#: addons/web/static/src/js/search.js:1296 +#: addons/web/static/src/js/search.js:1310 +#: addons/web/static/src/js/search.js:1329 +#: addons/web/static/src/js/search.js:1348 +#: addons/web/static/src/js/search.js:1369 +#: addons/web/static/src/js/search.js:1301 +#: addons/web/static/src/js/search.js:1315 +#: addons/web/static/src/js/search.js:1334 +#: addons/web/static/src/js/search.js:1353 +#: addons/web/static/src/js/search.js:1374 +msgid "greater or equal than" +msgstr "მეტია ან უდრის" + +#. openerp-web +#: addons/web/static/src/js/search.js:1297 +#: addons/web/static/src/js/search.js:1311 +#: addons/web/static/src/js/search.js:1330 +#: addons/web/static/src/js/search.js:1349 +#: addons/web/static/src/js/search.js:1370 +#: addons/web/static/src/js/search.js:1302 +#: addons/web/static/src/js/search.js:1316 +#: addons/web/static/src/js/search.js:1335 +#: addons/web/static/src/js/search.js:1354 +#: addons/web/static/src/js/search.js:1375 +msgid "less or equal than" +msgstr "უდრის ან ნაკლებია" + +#. openerp-web +#: addons/web/static/src/js/search.js:1360 +#: addons/web/static/src/js/search.js:1383 +#: addons/web/static/src/js/search.js:1365 +#: addons/web/static/src/js/search.js:1388 +msgid "is" +msgstr "არის" + +#. openerp-web +#: addons/web/static/src/js/search.js:1384 +#: addons/web/static/src/js/search.js:1389 +msgid "is not" +msgstr "არ არის" + +#. openerp-web +#: addons/web/static/src/js/search.js:1396 +#: addons/web/static/src/js/search.js:1401 +msgid "is true" +msgstr "არის სიმართლე" + +#. openerp-web +#: addons/web/static/src/js/search.js:1397 +#: addons/web/static/src/js/search.js:1402 +msgid "is false" +msgstr "არის სიცრუე" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:20 +#, python-format +msgid "Manage Views (%s)" +msgstr "ვიუების მართვა (%s)" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:46 +#: addons/web/static/src/js/view_list.js:17 +#: addons/web/static/src/xml/base.xml:100 +#: addons/web/static/src/xml/base.xml:327 +#: addons/web/static/src/xml/base.xml:756 +msgid "Create" +msgstr "შექმნა" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:47 +#: addons/web/static/src/xml/base.xml:483 +#: addons/web/static/src/xml/base.xml:755 +msgid "Edit" +msgstr "შეცვლა" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:48 +#: addons/web/static/src/xml/base.xml:1647 +msgid "Remove" +msgstr "მოცილება" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:71 +#, python-format +msgid "Create a view (%s)" +msgstr "ვიუს შექმნა (%s)" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:168 +msgid "Do you really want to remove this view?" +msgstr "ნამდვილად გსურთ ამ ვიუს მოცილება" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:364 +#, python-format +msgid "View Editor %d - %s" +msgstr "ვიუს რედაქტორი %d - %s" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:367 +msgid "Inherited View" +msgstr "თანდაყოლილი ვიუ" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:371 +msgid "Do you really wants to create an inherited view here?" +msgstr "ნამდვილად გსურთ აქ შექმნათ თანდაყოლილი ვიუ?" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:381 +msgid "Preview" +msgstr "გადახედვა" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:501 +msgid "Do you really want to remove this node?" +msgstr "ნამდვილად გსურთ ამ კვანძის მოცილება?" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:815 +#: addons/web/static/src/js/view_editor.js:939 +msgid "Properties" +msgstr "თვისებები" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:818 +#: addons/web/static/src/js/view_editor.js:942 +msgid "Update" +msgstr "განახლება" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:16 +msgid "Form" +msgstr "ფორმა" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:121 +#: addons/web/static/src/js/views.js:803 +msgid "Customize" +msgstr "პარამეტრიზირება" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:123 +#: addons/web/static/src/js/view_form.js:686 +#: addons/web/static/src/js/view_form.js:692 +msgid "Set Default" +msgstr "ნაგულისხმები" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:469 +#: addons/web/static/src/js/view_form.js:475 +msgid "" +"Warning, the record has been modified, your changes will be discarded." +msgstr "" +"ფრთხილად, ჩანაწერი მოდიფიცირებულია, თქვენს მიერ გაკეთებული ცვლილებები " +"დაიკარგება" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:693 +#: addons/web/static/src/js/view_form.js:699 +msgid "Save default" +msgstr "ნაგულისხმებად შენახვა" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:754 +#: addons/web/static/src/js/view_form.js:760 +msgid "Attachments" +msgstr "დანართი" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:792 +#: addons/web/static/src/js/view_form.js:798 +#, python-format +msgid "Do you really want to delete the attachment %s?" +msgstr "ნამდვილად გსურთ წაშალოთ დანართი %s?" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:822 +#: addons/web/static/src/js/view_form.js:828 +#, python-format +msgid "Unknown operator %s in domain %s" +msgstr "გაურკვეველი ოპერატორი %s დომენში %s" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:830 +#: addons/web/static/src/js/view_form.js:836 +#, python-format +msgid "Unknown field %s in domain %s" +msgstr "გაურკვეველი ველი %s დომენში %s" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:868 +#: addons/web/static/src/js/view_form.js:874 +#, python-format +msgid "Unsupported operator %s in domain %s" +msgstr "უცხო ოპერატორი %s დომენში %s" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:1225 +#: addons/web/static/src/js/view_form.js:1231 +msgid "Confirm" +msgstr "დამოწმება" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:1921 +#: addons/web/static/src/js/view_form.js:2578 +#: addons/web/static/src/js/view_form.js:2741 +#: addons/web/static/src/js/view_form.js:1933 +#: addons/web/static/src/js/view_form.js:2590 +#: addons/web/static/src/js/view_form.js:2760 +msgid "Open: " +msgstr "ღია: " + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2049 +#: addons/web/static/src/js/view_form.js:2061 +msgid "   Search More..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2062 +#: addons/web/static/src/js/view_form.js:2074 +#, python-format +msgid "   Create \"%s\"" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2068 +#: addons/web/static/src/js/view_form.js:2080 +msgid "   Create and Edit..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2101 +#: addons/web/static/src/js/views.js:675 +#: addons/web/static/src/js/view_form.js:2113 +msgid "Search: " +msgstr "ძიება: " + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2101 +#: addons/web/static/src/js/view_form.js:2550 +#: addons/web/static/src/js/view_form.js:2113 +#: addons/web/static/src/js/view_form.js:2562 +msgid "Create: " +msgstr "შექმნა: " + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2661 +#: addons/web/static/src/xml/base.xml:750 +#: addons/web/static/src/xml/base.xml:772 +#: addons/web/static/src/xml/base.xml:1646 +#: addons/web/static/src/js/view_form.js:2680 +msgid "Add" +msgstr "დამატება" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2721 +#: addons/web/static/src/js/view_form.js:2740 +msgid "Add: " +msgstr "დამატება: " + +#. openerp-web +#: addons/web/static/src/js/view_list.js:8 +msgid "List" +msgstr "სია" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:269 +msgid "Unlimited" +msgstr "შეუზღუდავი" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:305 +#: addons/web/static/src/js/view_list.js:309 +#, python-format +msgid "[%(first_record)d to %(last_record)d] of %(records_count)d" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:524 +#: addons/web/static/src/js/view_list.js:528 +msgid "Do you really want to remove these records?" +msgstr "ნამდვილად გსურთ ამ ჩანაწერები მოცილება?" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:1230 +#: addons/web/static/src/js/view_list.js:1232 +msgid "Undefined" +msgstr "განუსაზღვრელი" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:1327 +#: addons/web/static/src/js/view_list.js:1331 +#, python-format +msgid "%(page)d/%(page_count)d" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_page.js:8 +msgid "Page" +msgstr "გვერდი" + +#. openerp-web +#: addons/web/static/src/js/view_page.js:52 +msgid "Do you really want to delete this record?" +msgstr "ნამდვილად გსურთ ამ ჩანაწერის წაშლა?" + +#. openerp-web +#: addons/web/static/src/js/view_tree.js:11 +msgid "Tree" +msgstr "განშტოება" + +#. openerp-web +#: addons/web/static/src/js/views.js:565 +#: addons/web/static/src/xml/base.xml:480 +msgid "Fields View Get" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:573 +#, python-format +msgid "View Log (%s)" +msgstr "ლოგის ნახვა (%s)" + +#. openerp-web +#: addons/web/static/src/js/views.js:600 +#, python-format +msgid "Model %s fields" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:610 +#: addons/web/static/src/xml/base.xml:482 +msgid "Manage Views" +msgstr "ვიუების მართვა" + +#. openerp-web +#: addons/web/static/src/js/views.js:611 +msgid "Could not find current view declaration" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:805 +msgid "Translate" +msgstr "გადათარგმნა" + +#. openerp-web +#: addons/web/static/src/js/views.js:807 +msgid "Technical translation" +msgstr "ტექნიკური თარგმანი" + +#. openerp-web +#: addons/web/static/src/js/views.js:811 +msgid "Other Options" +msgstr "ხვა პარამეტრები" + +#. openerp-web +#: addons/web/static/src/js/views.js:814 +#: addons/web/static/src/xml/base.xml:1736 +msgid "Import" +msgstr "იმპორტი" + +#. openerp-web +#: addons/web/static/src/js/views.js:817 +#: addons/web/static/src/xml/base.xml:1606 +msgid "Export" +msgstr "ექსპორტი" + +#. openerp-web +#: addons/web/static/src/js/views.js:825 +msgid "Reports" +msgstr "რეპორტები" + +#. openerp-web +#: addons/web/static/src/js/views.js:825 +msgid "Actions" +msgstr "მოქმედებები" + +#. openerp-web +#: addons/web/static/src/js/views.js:825 +msgid "Links" +msgstr "ბმულები" + +#. openerp-web +#: addons/web/static/src/js/views.js:919 +msgid "You must choose at least one record." +msgstr "თქვენ მინიმუმ ერთი ჩანაწერი მაინც უნდა აირჩიოთ" + +#. openerp-web +#: addons/web/static/src/js/views.js:920 +msgid "Warning" +msgstr "გაფრთხილება" + +#. openerp-web +#: addons/web/static/src/js/views.js:957 +msgid "Translations" +msgstr "თარგმანები" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:44 +#: addons/web/static/src/xml/base.xml:315 +msgid "Powered by" +msgstr "მხარდაჭერილია" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:44 +#: addons/web/static/src/xml/base.xml:315 +#: addons/web/static/src/xml/base.xml:1813 +msgid "OpenERP" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:52 +msgid "Loading..." +msgstr "იტვირთება...." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:61 +msgid "CREATE DATABASE" +msgstr "მონაცემთა ბაზის შექმნა" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:68 +#: addons/web/static/src/xml/base.xml:211 +msgid "Master password:" +msgstr "მთავარი პაროლი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:72 +#: addons/web/static/src/xml/base.xml:191 +msgid "New database name:" +msgstr "ახალი ბაზის სახელი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:77 +msgid "Load Demonstration data:" +msgstr "ჩატვირთე სადემონსტრაციო მონაცემები:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:81 +msgid "Default language:" +msgstr "ნაგულისხმები ენა:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:91 +msgid "Admin password:" +msgstr "ადმინისტრატორის პაროლი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:95 +msgid "Confirm password:" +msgstr "დაადასტურეთ პაროლი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:109 +msgid "DROP DATABASE" +msgstr "მონაცემთა ბაზის წაშლა" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:116 +#: addons/web/static/src/xml/base.xml:150 +#: addons/web/static/src/xml/base.xml:301 +msgid "Database:" +msgstr "მონაცემთა ბაზა:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:128 +#: addons/web/static/src/xml/base.xml:162 +#: addons/web/static/src/xml/base.xml:187 +msgid "Master Password:" +msgstr "მთავარი პაროლი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:132 +#: addons/web/static/src/xml/base.xml:328 +msgid "Drop" +msgstr "წაშლა" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:143 +msgid "BACKUP DATABASE" +msgstr "მონაცემთა ბაზის სარეზერვო ასლის შექმნა" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:166 +#: addons/web/static/src/xml/base.xml:329 +msgid "Backup" +msgstr "სარეზერვო ასლი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:175 +msgid "RESTORE DATABASE" +msgstr "მონაცემთა ბაზის სარეზერვო ასლიდან აღდგენა" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:182 +msgid "File:" +msgstr "ფაილი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:195 +#: addons/web/static/src/xml/base.xml:330 +msgid "Restore" +msgstr "აღდგენა" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:204 +msgid "CHANGE MASTER PASSWORD" +msgstr "მთავარი პაროლის შეცვლა" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:216 +msgid "New master password:" +msgstr "ახალი მთავარი პაროლი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:221 +msgid "Confirm new master password:" +msgstr "დაადასტურეთ ახალი მთავარი პაროლი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:251 +msgid "" +"Your version of OpenERP is unsupported. Support & maintenance services are " +"available here:" +msgstr "" +"OpenERP-ის თქვენი ვერსია არ არის მხარდაჭერილი. ინფორმაცია მომსახურებისა და " +"მხარდაჭერის შესახებ იხილეთ აქ:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:251 +msgid "OpenERP Entreprise" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:256 +msgid "OpenERP Enterprise Contract." +msgstr "OpenERP Enterprise კონტრაქტი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:257 +msgid "Your report will be sent to the OpenERP Enterprise team." +msgstr "თქვენი რეპორტი გაეგზავნება OpenERP Enterprise გუნდს." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:259 +msgid "Summary:" +msgstr "რეზიუმე:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:263 +msgid "Description:" +msgstr "აღწერილობა:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:267 +msgid "What you did:" +msgstr "რა გააკეთეთ:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:297 +msgid "Invalid username or password" +msgstr "არასწორია მომხმარებელი ან პაროლი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:306 +msgid "Username" +msgstr "მომხმარებელი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:308 +#: addons/web/static/src/xml/base.xml:331 +msgid "Password" +msgstr "პაროლი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:310 +msgid "Log in" +msgstr "შესვლა" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:314 +msgid "Manage Databases" +msgstr "მონაცემთა ბაზების მართვა" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:332 +msgid "Back to Login" +msgstr "საწყის გვერდზე დაბრუნება შესასვლელად" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:353 +msgid "Home" +msgstr "მთავარი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:363 +msgid "LOGOUT" +msgstr "სისტემიდან გამოსვლა" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:388 +msgid "Fold menu" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:389 +msgid "Unfold menu" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:454 +msgid "Hide this tip" +msgstr "გააქრე ეს რჩევა" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:455 +msgid "Disable all tips" +msgstr "ყველა რჩევები გააუქმე" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:463 +msgid "Add / Remove Shortcut..." +msgstr "დაამატე/მოაცილე შორთქათები" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:471 +msgid "More…" +msgstr "მეტი..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:477 +msgid "Debug View#" +msgstr "დებაგ ვიუ#" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:478 +msgid "View Log (perm_read)" +msgstr "ლოგის ნახვა (perm_read)" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:479 +msgid "View Fields" +msgstr "ველების ნახვა" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:483 +msgid "View" +msgstr "ნახვა" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:484 +msgid "Edit SearchView" +msgstr "ძებნის ვიუს რედაქტირება" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:485 +msgid "Edit Action" +msgstr "მოქმედების რედაქტირება" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:486 +msgid "Edit Workflow" +msgstr "Workflow-ს რედაქტირება" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:491 +msgid "ID:" +msgstr "ID:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:494 +msgid "XML ID:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:497 +msgid "Creation User:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:500 +msgid "Creation Date:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:503 +msgid "Latest Modification by:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:506 +msgid "Latest Modification Date:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:542 +msgid "Field" +msgstr "ველი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:632 +#: addons/web/static/src/xml/base.xml:758 +#: addons/web/static/src/xml/base.xml:1708 +msgid "Delete" +msgstr "წაშალე" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:757 +msgid "Duplicate" +msgstr "გააკეთე დუბლირება." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:775 +msgid "Add attachment" +msgstr "დაამატე დანართი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:801 +msgid "Default:" +msgstr "ნაგულისხმევი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:818 +msgid "Condition:" +msgstr "პირობა:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:837 +msgid "Only you" +msgstr "მხოლოდ შენ" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:844 +msgid "All users" +msgstr "ყველა მომხმარებელი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:851 +msgid "Unhandled widget" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:900 +msgid "Notebook Page \"" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:905 +#: addons/web/static/src/xml/base.xml:964 +msgid "Modifiers:" +msgstr "მოდიფიკატორი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:931 +msgid "(nolabel)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:936 +msgid "Field:" +msgstr "ველი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:940 +msgid "Object:" +msgstr "ობიექტი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:944 +msgid "Type:" +msgstr "სახეობა:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:948 +msgid "Widget:" +msgstr "ვიჯეთი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:952 +msgid "Size:" +msgstr "ზომა:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:956 +msgid "Context:" +msgstr "კონტექსტი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:960 +msgid "Domain:" +msgstr "დომენი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:968 +msgid "Change default:" +msgstr "შეცვალე ნაგულისხმები:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:972 +msgid "On change:" +msgstr "ცვლილების დროს:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:976 +msgid "Relation:" +msgstr "რელაცია:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:980 +msgid "Selection:" +msgstr "არჩეული:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1020 +msgid "Send an e-mail with your default e-mail client" +msgstr "ელ.ფოსტის გაგზავნა თქვენი ნაგულისხმები ელ.ფოსტის კლიენტით" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1034 +msgid "Open this resource" +msgstr "ამ რესურსზე" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1056 +msgid "Select date" +msgstr "აირჩიეთ თარიღი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1090 +msgid "Open..." +msgstr "გახსნა..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1091 +msgid "Create..." +msgstr "შექმნა..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1092 +msgid "Search..." +msgstr "ძებნა..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1095 +msgid "..." +msgstr "..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1155 +#: addons/web/static/src/xml/base.xml:1198 +msgid "Set Image" +msgstr "განსაზღვრე სურათი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1163 +#: addons/web/static/src/xml/base.xml:1213 +#: addons/web/static/src/xml/base.xml:1215 +#: addons/web/static/src/xml/base.xml:1272 +msgid "Clear" +msgstr "გასუფთავება" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1172 +#: addons/web/static/src/xml/base.xml:1223 +msgid "Uploading ..." +msgstr "მიმდინარეობს ატვირთვა ..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1200 +#: addons/web/static/src/xml/base.xml:1495 +msgid "Select" +msgstr "არჩევა" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1207 +#: addons/web/static/src/xml/base.xml:1209 +msgid "Save As" +msgstr "შეინახე როგორც" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1238 +msgid "Button" +msgstr "ღილაკი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1241 +msgid "(no string)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1248 +msgid "Special:" +msgstr "სპეციალური:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1253 +msgid "Button Type:" +msgstr "ღილაკის სახეობა:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1257 +msgid "Method:" +msgstr "მეთოდი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1261 +msgid "Action ID:" +msgstr "მოქმედების ID:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1271 +msgid "Search" +msgstr "ძებნა" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1279 +msgid "Filters" +msgstr "ფილტრები" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1280 +msgid "-- Filters --" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1289 +msgid "-- Actions --" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1290 +msgid "Add Advanced Filter" +msgstr "დაამატე რთული ფილტრი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1291 +msgid "Save Filter" +msgstr "შეინახე ფილტრი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1293 +msgid "Manage Filters" +msgstr "მართე ფილტრები" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1298 +msgid "Filter Name:" +msgstr "ფილტრის სახელი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1300 +msgid "(Any existing filter with the same name will be replaced)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1305 +msgid "Select Dashboard to add this filter to:" +msgstr "აირჩიე საინფორმაციო დაფა რომელზეც გსურს ამ ფილტრის დამატება:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1309 +msgid "Title of new Dashboard item:" +msgstr "საინფორმაციო დაფის ახალი კომპონენტის დასახელება:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1416 +msgid "Advanced Filters" +msgstr "რთული ფილტრები:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1426 +msgid "Any of the following conditions must match" +msgstr "მოცემული პირობებიდან რომელიმე უნდა შესრულდეს" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1427 +msgid "All the following conditions must match" +msgstr "მოცემული პირობებიდან ყველა უნდა შესრულდეს" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1428 +msgid "None of the following conditions must match" +msgstr "მოცემული პირობებიდან არცერთი არ უნდა შესრულდეს" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1435 +msgid "Add condition" +msgstr "დაამატე პირობა" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1436 +msgid "and" +msgstr "და" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1503 +msgid "Save & New" +msgstr "შეინახე და ახალი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1504 +msgid "Save & Close" +msgstr "შეინახე და დახურე" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1611 +msgid "" +"This wizard will export all data that matches the current search criteria to " +"a CSV file.\n" +" You can export all data or only the fields that can be " +"reimported after modification." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1618 +msgid "Export Type:" +msgstr "ექსპორტის სახეობა:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1620 +msgid "Import Compatible Export" +msgstr "იმპორტზე თავსებადი ექსპორტი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1621 +msgid "Export all Data" +msgstr "დააექსპორტე ყველა მონაცემი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1624 +msgid "Export Formats" +msgstr "დააექსპორტე ფორმატები" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1630 +msgid "Available fields" +msgstr "ხელმისაწვდომი ველები" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1632 +msgid "Fields to export" +msgstr "დასაექსპორტებელი ველები" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1634 +msgid "Save fields list" +msgstr "ველების ჩამონათვალის შენახვა" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1648 +msgid "Remove All" +msgstr "ყველას მოცილება" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1660 +msgid "Name" +msgstr "დასახელება" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1693 +msgid "Save as:" +msgstr "შეინახე როგორც:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1700 +msgid "Saved exports:" +msgstr "შენახული ექსპორტები:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1714 +msgid "Old Password:" +msgstr "ძველი პაროლი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1719 +msgid "New Password:" +msgstr "ახალი პაროლი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1724 +msgid "Confirm Password:" +msgstr "დაადასტურეთ პაროლი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1742 +msgid "1. Import a .CSV file" +msgstr "1. დააიმპორტე .CSV ფაილი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1743 +msgid "" +"Select a .CSV file to import. If you need a sample of file to import,\n" +" you should use the export tool with the \"Import Compatible\" option." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1747 +msgid "CSV File:" +msgstr "CSV ფაილი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1750 +msgid "2. Check your file format" +msgstr "2. შეამოწმეთ თქვენი ფაილის ფორმატი" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1753 +msgid "Import Options" +msgstr "პარამეტრების იმპორტირება" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1757 +msgid "Does your file have titles?" +msgstr "თქვენს ფაილს აქვს სათაური?" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1763 +msgid "Separator:" +msgstr "გამყოფი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1765 +msgid "Delimiter:" +msgstr "გამყოფი:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1769 +msgid "Encoding:" +msgstr "კოდირება:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1772 +msgid "UTF-8" +msgstr "UTF-8" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1773 +msgid "Latin 1" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1776 +msgid "Lines to skip" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1776 +msgid "" +"For use if CSV files have titles on multiple lines, skips more than a single " +"line during import" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1803 +msgid "The import failed due to:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1805 +msgid "Here is a preview of the file we could not import:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1812 +msgid "Activate the developper mode" +msgstr "პროგრამისტის რეჟიმის აქტივაცია" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1814 +msgid "Version" +msgstr "ვერსია" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1815 +msgid "Copyright © 2004-TODAY OpenERP SA. All Rights Reserved." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1816 +msgid "OpenERP is a trademark of the" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1817 +msgid "OpenERP SA Company" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1819 +msgid "Licenced under the terms of" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1820 +msgid "GNU Affero General Public License" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1822 +msgid "For more information visit" +msgstr "მეტი ინფორმაციისთვის ეწვიეთ" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1823 +msgid "OpenERP.com" +msgstr "" diff --git a/addons/web/i18n/nb.po b/addons/web/i18n/nb.po new file mode 100644 index 00000000000..f2ec8057d22 --- /dev/null +++ b/addons/web/i18n/nb.po @@ -0,0 +1,1544 @@ +# Norwegian Bokmal translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-03-21 11:58+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Norwegian Bokmal \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-22 05:31+0000\n" +"X-Generator: Launchpad (build 14981)\n" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:172 +#: addons/web/static/src/js/chrome.js:198 +#: addons/web/static/src/js/chrome.js:414 +#: addons/web/static/src/js/view_form.js:419 +#: addons/web/static/src/js/view_form.js:1233 +#: addons/web/static/src/xml/base.xml:1695 +#: addons/web/static/src/js/view_form.js:424 +#: addons/web/static/src/js/view_form.js:1239 +msgid "Ok" +msgstr "Ok" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:180 +msgid "Send OpenERP Enterprise Report" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:194 +msgid "Dont send" +msgstr "Ikke send" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:256 +#, python-format +msgid "Loading (%d)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:288 +msgid "Invalid database name" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:483 +msgid "Backed" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:484 +msgid "Database backed up successfully" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:527 +msgid "Restored" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:527 +msgid "Database restored successfully" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:708 +#: addons/web/static/src/xml/base.xml:359 +msgid "About" +msgstr "Om" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:787 +#: addons/web/static/src/xml/base.xml:356 +msgid "Preferences" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:790 +#: addons/web/static/src/js/search.js:239 +#: addons/web/static/src/js/search.js:288 +#: addons/web/static/src/js/view_editor.js:95 +#: addons/web/static/src/js/view_editor.js:836 +#: addons/web/static/src/js/view_editor.js:962 +#: addons/web/static/src/js/view_form.js:1228 +#: addons/web/static/src/xml/base.xml:738 +#: addons/web/static/src/xml/base.xml:1496 +#: addons/web/static/src/xml/base.xml:1506 +#: addons/web/static/src/xml/base.xml:1515 +#: addons/web/static/src/js/search.js:293 +#: addons/web/static/src/js/view_form.js:1234 +msgid "Cancel" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:791 +msgid "Change password" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:792 +#: addons/web/static/src/js/view_editor.js:73 +#: addons/web/static/src/js/views.js:962 +#: addons/web/static/src/xml/base.xml:737 +#: addons/web/static/src/xml/base.xml:1500 +#: addons/web/static/src/xml/base.xml:1514 +msgid "Save" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:811 +#: addons/web/static/src/xml/base.xml:226 +#: addons/web/static/src/xml/base.xml:1729 +msgid "Change Password" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:1096 +#: addons/web/static/src/js/chrome.js:1100 +msgid "OpenERP - Unsupported/Community Version" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:1131 +#: addons/web/static/src/js/chrome.js:1135 +msgid "Client Error" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:6 +msgid "Export Data" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:19 +#: addons/web/static/src/js/data_import.js:69 +#: addons/web/static/src/js/view_editor.js:49 +#: addons/web/static/src/js/view_editor.js:398 +#: addons/web/static/src/js/view_form.js:692 +#: addons/web/static/src/js/view_form.js:3044 +#: addons/web/static/src/js/views.js:963 +#: addons/web/static/src/js/view_form.js:698 +#: addons/web/static/src/js/view_form.js:3067 +msgid "Close" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:20 +msgid "Export To File" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:125 +msgid "Please enter save field list name" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:360 +msgid "Please select fields to save export list..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:373 +msgid "Please select fields to export..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_import.js:34 +msgid "Import Data" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_import.js:70 +msgid "Import File" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_import.js:105 +msgid "External ID" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/formats.js:300 +#: addons/web/static/src/js/view_page.js:245 +#: addons/web/static/src/js/formats.js:322 +#: addons/web/static/src/js/view_page.js:251 +msgid "Download" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/formats.js:305 +#: addons/web/static/src/js/formats.js:327 +#, python-format +msgid "Download \"%s\"" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:191 +msgid "Filter disabled due to invalid syntax" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:237 +msgid "Filter Entry" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:242 +#: addons/web/static/src/js/search.js:291 +#: addons/web/static/src/js/search.js:296 +msgid "OK" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:286 +#: addons/web/static/src/xml/base.xml:1292 +#: addons/web/static/src/js/search.js:291 +msgid "Add to Dashboard" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:415 +#: addons/web/static/src/js/search.js:420 +msgid "Invalid Search" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:415 +#: addons/web/static/src/js/search.js:420 +msgid "triggered from search view" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:503 +#: addons/web/static/src/js/search.js:508 +#, python-format +msgid "Incorrect value for field %(fieldname)s: [%(value)s] is %(message)s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:839 +#: addons/web/static/src/js/search.js:844 +msgid "not a valid integer" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:853 +#: addons/web/static/src/js/search.js:858 +msgid "not a valid number" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:931 +#: addons/web/static/src/xml/base.xml:968 +#: addons/web/static/src/js/search.js:936 +msgid "Yes" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:932 +#: addons/web/static/src/js/search.js:937 +msgid "No" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1290 +#: addons/web/static/src/js/search.js:1295 +msgid "contains" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1291 +#: addons/web/static/src/js/search.js:1296 +msgid "doesn't contain" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1292 +#: addons/web/static/src/js/search.js:1306 +#: addons/web/static/src/js/search.js:1325 +#: addons/web/static/src/js/search.js:1344 +#: addons/web/static/src/js/search.js:1365 +#: addons/web/static/src/js/search.js:1297 +#: addons/web/static/src/js/search.js:1311 +#: addons/web/static/src/js/search.js:1330 +#: addons/web/static/src/js/search.js:1349 +#: addons/web/static/src/js/search.js:1370 +msgid "is equal to" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1293 +#: addons/web/static/src/js/search.js:1307 +#: addons/web/static/src/js/search.js:1326 +#: addons/web/static/src/js/search.js:1345 +#: addons/web/static/src/js/search.js:1366 +#: addons/web/static/src/js/search.js:1298 +#: addons/web/static/src/js/search.js:1312 +#: addons/web/static/src/js/search.js:1331 +#: addons/web/static/src/js/search.js:1350 +#: addons/web/static/src/js/search.js:1371 +msgid "is not equal to" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1294 +#: addons/web/static/src/js/search.js:1308 +#: addons/web/static/src/js/search.js:1327 +#: addons/web/static/src/js/search.js:1346 +#: addons/web/static/src/js/search.js:1367 +#: addons/web/static/src/js/search.js:1299 +#: addons/web/static/src/js/search.js:1313 +#: addons/web/static/src/js/search.js:1332 +#: addons/web/static/src/js/search.js:1351 +#: addons/web/static/src/js/search.js:1372 +msgid "greater than" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1295 +#: addons/web/static/src/js/search.js:1309 +#: addons/web/static/src/js/search.js:1328 +#: addons/web/static/src/js/search.js:1347 +#: addons/web/static/src/js/search.js:1368 +#: addons/web/static/src/js/search.js:1300 +#: addons/web/static/src/js/search.js:1314 +#: addons/web/static/src/js/search.js:1333 +#: addons/web/static/src/js/search.js:1352 +#: addons/web/static/src/js/search.js:1373 +msgid "less than" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1296 +#: addons/web/static/src/js/search.js:1310 +#: addons/web/static/src/js/search.js:1329 +#: addons/web/static/src/js/search.js:1348 +#: addons/web/static/src/js/search.js:1369 +#: addons/web/static/src/js/search.js:1301 +#: addons/web/static/src/js/search.js:1315 +#: addons/web/static/src/js/search.js:1334 +#: addons/web/static/src/js/search.js:1353 +#: addons/web/static/src/js/search.js:1374 +msgid "greater or equal than" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1297 +#: addons/web/static/src/js/search.js:1311 +#: addons/web/static/src/js/search.js:1330 +#: addons/web/static/src/js/search.js:1349 +#: addons/web/static/src/js/search.js:1370 +#: addons/web/static/src/js/search.js:1302 +#: addons/web/static/src/js/search.js:1316 +#: addons/web/static/src/js/search.js:1335 +#: addons/web/static/src/js/search.js:1354 +#: addons/web/static/src/js/search.js:1375 +msgid "less or equal than" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1360 +#: addons/web/static/src/js/search.js:1383 +#: addons/web/static/src/js/search.js:1365 +#: addons/web/static/src/js/search.js:1388 +msgid "is" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1384 +#: addons/web/static/src/js/search.js:1389 +msgid "is not" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1396 +#: addons/web/static/src/js/search.js:1401 +msgid "is true" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1397 +#: addons/web/static/src/js/search.js:1402 +msgid "is false" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:20 +#, python-format +msgid "Manage Views (%s)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:46 +#: addons/web/static/src/js/view_list.js:17 +#: addons/web/static/src/xml/base.xml:100 +#: addons/web/static/src/xml/base.xml:327 +#: addons/web/static/src/xml/base.xml:756 +msgid "Create" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:47 +#: addons/web/static/src/xml/base.xml:483 +#: addons/web/static/src/xml/base.xml:755 +msgid "Edit" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:48 +#: addons/web/static/src/xml/base.xml:1647 +msgid "Remove" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:71 +#, python-format +msgid "Create a view (%s)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:168 +msgid "Do you really want to remove this view?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:364 +#, python-format +msgid "View Editor %d - %s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:367 +msgid "Inherited View" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:371 +msgid "Do you really wants to create an inherited view here?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:381 +msgid "Preview" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:501 +msgid "Do you really want to remove this node?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:815 +#: addons/web/static/src/js/view_editor.js:939 +msgid "Properties" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:818 +#: addons/web/static/src/js/view_editor.js:942 +msgid "Update" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:16 +msgid "Form" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:121 +#: addons/web/static/src/js/views.js:803 +msgid "Customize" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:123 +#: addons/web/static/src/js/view_form.js:686 +#: addons/web/static/src/js/view_form.js:692 +msgid "Set Default" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:469 +#: addons/web/static/src/js/view_form.js:475 +msgid "" +"Warning, the record has been modified, your changes will be discarded." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:693 +#: addons/web/static/src/js/view_form.js:699 +msgid "Save default" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:754 +#: addons/web/static/src/js/view_form.js:760 +msgid "Attachments" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:792 +#: addons/web/static/src/js/view_form.js:798 +#, python-format +msgid "Do you really want to delete the attachment %s?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:822 +#: addons/web/static/src/js/view_form.js:828 +#, python-format +msgid "Unknown operator %s in domain %s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:830 +#: addons/web/static/src/js/view_form.js:836 +#, python-format +msgid "Unknown field %s in domain %s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:868 +#: addons/web/static/src/js/view_form.js:874 +#, python-format +msgid "Unsupported operator %s in domain %s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:1225 +#: addons/web/static/src/js/view_form.js:1231 +msgid "Confirm" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:1921 +#: addons/web/static/src/js/view_form.js:2578 +#: addons/web/static/src/js/view_form.js:2741 +#: addons/web/static/src/js/view_form.js:1933 +#: addons/web/static/src/js/view_form.js:2590 +#: addons/web/static/src/js/view_form.js:2760 +msgid "Open: " +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2049 +#: addons/web/static/src/js/view_form.js:2061 +msgid "   Search More..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2062 +#: addons/web/static/src/js/view_form.js:2074 +#, python-format +msgid "   Create \"%s\"" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2068 +#: addons/web/static/src/js/view_form.js:2080 +msgid "   Create and Edit..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2101 +#: addons/web/static/src/js/views.js:675 +#: addons/web/static/src/js/view_form.js:2113 +msgid "Search: " +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2101 +#: addons/web/static/src/js/view_form.js:2550 +#: addons/web/static/src/js/view_form.js:2113 +#: addons/web/static/src/js/view_form.js:2562 +msgid "Create: " +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2661 +#: addons/web/static/src/xml/base.xml:750 +#: addons/web/static/src/xml/base.xml:772 +#: addons/web/static/src/xml/base.xml:1646 +#: addons/web/static/src/js/view_form.js:2680 +msgid "Add" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2721 +#: addons/web/static/src/js/view_form.js:2740 +msgid "Add: " +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:8 +msgid "List" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:269 +msgid "Unlimited" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:305 +#: addons/web/static/src/js/view_list.js:309 +#, python-format +msgid "[%(first_record)d to %(last_record)d] of %(records_count)d" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:524 +#: addons/web/static/src/js/view_list.js:528 +msgid "Do you really want to remove these records?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:1230 +#: addons/web/static/src/js/view_list.js:1232 +msgid "Undefined" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:1327 +#: addons/web/static/src/js/view_list.js:1331 +#, python-format +msgid "%(page)d/%(page_count)d" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_page.js:8 +msgid "Page" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_page.js:52 +msgid "Do you really want to delete this record?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_tree.js:11 +msgid "Tree" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:565 +#: addons/web/static/src/xml/base.xml:480 +msgid "Fields View Get" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:573 +#, python-format +msgid "View Log (%s)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:600 +#, python-format +msgid "Model %s fields" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:610 +#: addons/web/static/src/xml/base.xml:482 +msgid "Manage Views" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:611 +msgid "Could not find current view declaration" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:805 +msgid "Translate" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:807 +msgid "Technical translation" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:811 +msgid "Other Options" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:814 +#: addons/web/static/src/xml/base.xml:1736 +msgid "Import" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:817 +#: addons/web/static/src/xml/base.xml:1606 +msgid "Export" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:825 +msgid "Reports" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:825 +msgid "Actions" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:825 +msgid "Links" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:919 +msgid "You must choose at least one record." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:920 +msgid "Warning" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:957 +msgid "Translations" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:44 +#: addons/web/static/src/xml/base.xml:315 +msgid "Powered by" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:44 +#: addons/web/static/src/xml/base.xml:315 +#: addons/web/static/src/xml/base.xml:1813 +msgid "OpenERP" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:52 +msgid "Loading..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:61 +msgid "CREATE DATABASE" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:68 +#: addons/web/static/src/xml/base.xml:211 +msgid "Master password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:72 +#: addons/web/static/src/xml/base.xml:191 +msgid "New database name:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:77 +msgid "Load Demonstration data:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:81 +msgid "Default language:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:91 +msgid "Admin password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:95 +msgid "Confirm password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:109 +msgid "DROP DATABASE" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:116 +#: addons/web/static/src/xml/base.xml:150 +#: addons/web/static/src/xml/base.xml:301 +msgid "Database:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:128 +#: addons/web/static/src/xml/base.xml:162 +#: addons/web/static/src/xml/base.xml:187 +msgid "Master Password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:132 +#: addons/web/static/src/xml/base.xml:328 +msgid "Drop" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:143 +msgid "BACKUP DATABASE" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:166 +#: addons/web/static/src/xml/base.xml:329 +msgid "Backup" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:175 +msgid "RESTORE DATABASE" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:182 +msgid "File:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:195 +#: addons/web/static/src/xml/base.xml:330 +msgid "Restore" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:204 +msgid "CHANGE MASTER PASSWORD" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:216 +msgid "New master password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:221 +msgid "Confirm new master password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:251 +msgid "" +"Your version of OpenERP is unsupported. Support & maintenance services are " +"available here:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:251 +msgid "OpenERP Entreprise" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:256 +msgid "OpenERP Enterprise Contract." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:257 +msgid "Your report will be sent to the OpenERP Enterprise team." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:259 +msgid "Summary:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:263 +msgid "Description:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:267 +msgid "What you did:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:297 +msgid "Invalid username or password" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:306 +msgid "Username" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:308 +#: addons/web/static/src/xml/base.xml:331 +msgid "Password" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:310 +msgid "Log in" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:314 +msgid "Manage Databases" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:332 +msgid "Back to Login" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:353 +msgid "Home" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:363 +msgid "LOGOUT" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:388 +msgid "Fold menu" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:389 +msgid "Unfold menu" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:454 +msgid "Hide this tip" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:455 +msgid "Disable all tips" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:463 +msgid "Add / Remove Shortcut..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:471 +msgid "More…" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:477 +msgid "Debug View#" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:478 +msgid "View Log (perm_read)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:479 +msgid "View Fields" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:483 +msgid "View" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:484 +msgid "Edit SearchView" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:485 +msgid "Edit Action" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:486 +msgid "Edit Workflow" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:491 +msgid "ID:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:494 +msgid "XML ID:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:497 +msgid "Creation User:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:500 +msgid "Creation Date:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:503 +msgid "Latest Modification by:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:506 +msgid "Latest Modification Date:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:542 +msgid "Field" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:632 +#: addons/web/static/src/xml/base.xml:758 +#: addons/web/static/src/xml/base.xml:1708 +msgid "Delete" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:757 +msgid "Duplicate" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:775 +msgid "Add attachment" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:801 +msgid "Default:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:818 +msgid "Condition:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:837 +msgid "Only you" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:844 +msgid "All users" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:851 +msgid "Unhandled widget" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:900 +msgid "Notebook Page \"" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:905 +#: addons/web/static/src/xml/base.xml:964 +msgid "Modifiers:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:931 +msgid "(nolabel)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:936 +msgid "Field:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:940 +msgid "Object:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:944 +msgid "Type:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:948 +msgid "Widget:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:952 +msgid "Size:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:956 +msgid "Context:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:960 +msgid "Domain:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:968 +msgid "Change default:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:972 +msgid "On change:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:976 +msgid "Relation:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:980 +msgid "Selection:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1020 +msgid "Send an e-mail with your default e-mail client" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1034 +msgid "Open this resource" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1056 +msgid "Select date" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1090 +msgid "Open..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1091 +msgid "Create..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1092 +msgid "Search..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1095 +msgid "..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1155 +#: addons/web/static/src/xml/base.xml:1198 +msgid "Set Image" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1163 +#: addons/web/static/src/xml/base.xml:1213 +#: addons/web/static/src/xml/base.xml:1215 +#: addons/web/static/src/xml/base.xml:1272 +msgid "Clear" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1172 +#: addons/web/static/src/xml/base.xml:1223 +msgid "Uploading ..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1200 +#: addons/web/static/src/xml/base.xml:1495 +msgid "Select" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1207 +#: addons/web/static/src/xml/base.xml:1209 +msgid "Save As" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1238 +msgid "Button" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1241 +msgid "(no string)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1248 +msgid "Special:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1253 +msgid "Button Type:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1257 +msgid "Method:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1261 +msgid "Action ID:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1271 +msgid "Search" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1279 +msgid "Filters" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1280 +msgid "-- Filters --" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1289 +msgid "-- Actions --" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1290 +msgid "Add Advanced Filter" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1291 +msgid "Save Filter" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1293 +msgid "Manage Filters" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1298 +msgid "Filter Name:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1300 +msgid "(Any existing filter with the same name will be replaced)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1305 +msgid "Select Dashboard to add this filter to:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1309 +msgid "Title of new Dashboard item:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1416 +msgid "Advanced Filters" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1426 +msgid "Any of the following conditions must match" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1427 +msgid "All the following conditions must match" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1428 +msgid "None of the following conditions must match" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1435 +msgid "Add condition" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1436 +msgid "and" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1503 +msgid "Save & New" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1504 +msgid "Save & Close" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1611 +msgid "" +"This wizard will export all data that matches the current search criteria to " +"a CSV file.\n" +" You can export all data or only the fields that can be " +"reimported after modification." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1618 +msgid "Export Type:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1620 +msgid "Import Compatible Export" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1621 +msgid "Export all Data" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1624 +msgid "Export Formats" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1630 +msgid "Available fields" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1632 +msgid "Fields to export" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1634 +msgid "Save fields list" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1648 +msgid "Remove All" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1660 +msgid "Name" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1693 +msgid "Save as:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1700 +msgid "Saved exports:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1714 +msgid "Old Password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1719 +msgid "New Password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1724 +msgid "Confirm Password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1742 +msgid "1. Import a .CSV file" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1743 +msgid "" +"Select a .CSV file to import. If you need a sample of file to import,\n" +" you should use the export tool with the \"Import Compatible\" option." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1747 +msgid "CSV File:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1750 +msgid "2. Check your file format" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1753 +msgid "Import Options" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1757 +msgid "Does your file have titles?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1763 +msgid "Separator:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1765 +msgid "Delimiter:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1769 +msgid "Encoding:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1772 +msgid "UTF-8" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1773 +msgid "Latin 1" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1776 +msgid "Lines to skip" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1776 +msgid "" +"For use if CSV files have titles on multiple lines, skips more than a single " +"line during import" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1803 +msgid "The import failed due to:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1805 +msgid "Here is a preview of the file we could not import:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1812 +msgid "Activate the developper mode" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1814 +msgid "Version" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1815 +msgid "Copyright © 2004-TODAY OpenERP SA. All Rights Reserved." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1816 +msgid "OpenERP is a trademark of the" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1817 +msgid "OpenERP SA Company" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1819 +msgid "Licenced under the terms of" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1820 +msgid "GNU Affero General Public License" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1822 +msgid "For more information visit" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1823 +msgid "OpenERP.com" +msgstr "" diff --git a/addons/web/i18n/nl.po b/addons/web/i18n/nl.po index 2fd5b65c468..2c60216ae37 100644 --- a/addons/web/i18n/nl.po +++ b/addons/web/i18n/nl.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-14 15:27+0100\n" -"PO-Revision-Date: 2012-02-15 14:37+0000\n" +"PO-Revision-Date: 2012-02-16 10:56+0000\n" "Last-Translator: Erwin \n" "Language-Team: Dutch \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-16 05:21+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:172 @@ -534,7 +534,7 @@ msgstr "Onbeperkt" #: addons/web/static/src/js/view_list.js:305 #, python-format msgid "[%(first_record)d to %(last_record)d] of %(records_count)d" -msgstr "[%(first_record)d tot %(last_record)d] van %(records_count)d" +msgstr "[%(first_record)d t/m %(last_record)d] van %(records_count)d" #. openerp-web #: addons/web/static/src/js/view_list.js:524 @@ -592,7 +592,7 @@ msgstr "Weergaven beheren" #. openerp-web #: addons/web/static/src/js/views.js:611 msgid "Could not find current view declaration" -msgstr "" +msgstr "Kan huidige weergave declaratie niet vinden" #. openerp-web #: addons/web/static/src/js/views.js:805 @@ -989,7 +989,7 @@ msgstr "Alle gebruikers" #. openerp-web #: addons/web/static/src/xml/base.xml:851 msgid "Unhandled widget" -msgstr "" +msgstr "Niet-verwerkte widget" #. openerp-web #: addons/web/static/src/xml/base.xml:900 diff --git a/addons/web/i18n/pt_BR.po b/addons/web/i18n/pt_BR.po index cfc3e9c4db3..140e00a8285 100644 --- a/addons/web/i18n/pt_BR.po +++ b/addons/web/i18n/pt_BR.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-16 05:21+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:172 diff --git a/addons/web/i18n/ro.po b/addons/web/i18n/ro.po new file mode 100644 index 00000000000..2a11cde1842 --- /dev/null +++ b/addons/web/i18n/ro.po @@ -0,0 +1,1548 @@ +# Romanian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-03-15 08:11+0000\n" +"Last-Translator: angelescu \n" +"Language-Team: Romanian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-16 05:14+0000\n" +"X-Generator: Launchpad (build 14951)\n" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:172 +#: addons/web/static/src/js/chrome.js:198 +#: addons/web/static/src/js/chrome.js:414 +#: addons/web/static/src/js/view_form.js:419 +#: addons/web/static/src/js/view_form.js:1233 +#: addons/web/static/src/xml/base.xml:1695 +#: addons/web/static/src/js/view_form.js:424 +#: addons/web/static/src/js/view_form.js:1239 +msgid "Ok" +msgstr "Ok" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:180 +msgid "Send OpenERP Enterprise Report" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:194 +msgid "Dont send" +msgstr "Nu trimite" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:256 +#, python-format +msgid "Loading (%d)" +msgstr "Încarcă (%d)" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:288 +msgid "Invalid database name" +msgstr "Nume bază de date invalid" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:483 +msgid "Backed" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:484 +msgid "Database backed up successfully" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:527 +msgid "Restored" +msgstr "Restaurat" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:527 +msgid "Database restored successfully" +msgstr "Baza de date restaurată cu succes" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:708 +#: addons/web/static/src/xml/base.xml:359 +msgid "About" +msgstr "Despre" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:787 +#: addons/web/static/src/xml/base.xml:356 +msgid "Preferences" +msgstr "Preferințe" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:790 +#: addons/web/static/src/js/search.js:239 +#: addons/web/static/src/js/search.js:288 +#: addons/web/static/src/js/view_editor.js:95 +#: addons/web/static/src/js/view_editor.js:836 +#: addons/web/static/src/js/view_editor.js:962 +#: addons/web/static/src/js/view_form.js:1228 +#: addons/web/static/src/xml/base.xml:738 +#: addons/web/static/src/xml/base.xml:1496 +#: addons/web/static/src/xml/base.xml:1506 +#: addons/web/static/src/xml/base.xml:1515 +#: addons/web/static/src/js/search.js:293 +#: addons/web/static/src/js/view_form.js:1234 +msgid "Cancel" +msgstr "Renunță" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:791 +msgid "Change password" +msgstr "Schimbare parolă" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:792 +#: addons/web/static/src/js/view_editor.js:73 +#: addons/web/static/src/js/views.js:962 +#: addons/web/static/src/xml/base.xml:737 +#: addons/web/static/src/xml/base.xml:1500 +#: addons/web/static/src/xml/base.xml:1514 +msgid "Save" +msgstr "Salvare" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:811 +#: addons/web/static/src/xml/base.xml:226 +#: addons/web/static/src/xml/base.xml:1729 +msgid "Change Password" +msgstr "Modifică parola" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:1096 +#: addons/web/static/src/js/chrome.js:1100 +msgid "OpenERP - Unsupported/Community Version" +msgstr "OpenERP - Versiune Nesuportată/Comunitate" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:1131 +#: addons/web/static/src/js/chrome.js:1135 +msgid "Client Error" +msgstr "Eroare la client" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:6 +msgid "Export Data" +msgstr "Exportă datele" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:19 +#: addons/web/static/src/js/data_import.js:69 +#: addons/web/static/src/js/view_editor.js:49 +#: addons/web/static/src/js/view_editor.js:398 +#: addons/web/static/src/js/view_form.js:692 +#: addons/web/static/src/js/view_form.js:3044 +#: addons/web/static/src/js/views.js:963 +#: addons/web/static/src/js/view_form.js:698 +#: addons/web/static/src/js/view_form.js:3067 +msgid "Close" +msgstr "Închide" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:20 +msgid "Export To File" +msgstr "Exportă în fișier" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:125 +msgid "Please enter save field list name" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:360 +msgid "Please select fields to save export list..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:373 +msgid "Please select fields to export..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_import.js:34 +msgid "Import Data" +msgstr "Importă date" + +#. openerp-web +#: addons/web/static/src/js/data_import.js:70 +msgid "Import File" +msgstr "Importă fișier" + +#. openerp-web +#: addons/web/static/src/js/data_import.js:105 +msgid "External ID" +msgstr "ID extern" + +#. openerp-web +#: addons/web/static/src/js/formats.js:300 +#: addons/web/static/src/js/view_page.js:245 +#: addons/web/static/src/js/formats.js:322 +#: addons/web/static/src/js/view_page.js:251 +msgid "Download" +msgstr "Descarcă" + +#. openerp-web +#: addons/web/static/src/js/formats.js:305 +#: addons/web/static/src/js/formats.js:327 +#, python-format +msgid "Download \"%s\"" +msgstr "Descărcat \"%s\"" + +#. openerp-web +#: addons/web/static/src/js/search.js:191 +msgid "Filter disabled due to invalid syntax" +msgstr "Filtrele sunt dezactivate datorită unei sintaxe nule" + +#. openerp-web +#: addons/web/static/src/js/search.js:237 +msgid "Filter Entry" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:242 +#: addons/web/static/src/js/search.js:291 +#: addons/web/static/src/js/search.js:296 +msgid "OK" +msgstr "OK" + +#. openerp-web +#: addons/web/static/src/js/search.js:286 +#: addons/web/static/src/xml/base.xml:1292 +#: addons/web/static/src/js/search.js:291 +msgid "Add to Dashboard" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:415 +#: addons/web/static/src/js/search.js:420 +msgid "Invalid Search" +msgstr "Căutare nulă" + +#. openerp-web +#: addons/web/static/src/js/search.js:415 +#: addons/web/static/src/js/search.js:420 +msgid "triggered from search view" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:503 +#: addons/web/static/src/js/search.js:508 +#, python-format +msgid "Incorrect value for field %(fieldname)s: [%(value)s] is %(message)s" +msgstr "" +"Valoare incorectă pentru câmpul %(fieldname)s: [%(value)s] este %(message)s" + +#. openerp-web +#: addons/web/static/src/js/search.js:839 +#: addons/web/static/src/js/search.js:844 +msgid "not a valid integer" +msgstr "nu este un număr întreg valabil" + +#. openerp-web +#: addons/web/static/src/js/search.js:853 +#: addons/web/static/src/js/search.js:858 +msgid "not a valid number" +msgstr "nu este un număr valabil" + +#. openerp-web +#: addons/web/static/src/js/search.js:931 +#: addons/web/static/src/xml/base.xml:968 +#: addons/web/static/src/js/search.js:936 +msgid "Yes" +msgstr "Da" + +#. openerp-web +#: addons/web/static/src/js/search.js:932 +#: addons/web/static/src/js/search.js:937 +msgid "No" +msgstr "Nu" + +#. openerp-web +#: addons/web/static/src/js/search.js:1290 +#: addons/web/static/src/js/search.js:1295 +msgid "contains" +msgstr "conține" + +#. openerp-web +#: addons/web/static/src/js/search.js:1291 +#: addons/web/static/src/js/search.js:1296 +msgid "doesn't contain" +msgstr "nu conține" + +#. openerp-web +#: addons/web/static/src/js/search.js:1292 +#: addons/web/static/src/js/search.js:1306 +#: addons/web/static/src/js/search.js:1325 +#: addons/web/static/src/js/search.js:1344 +#: addons/web/static/src/js/search.js:1365 +#: addons/web/static/src/js/search.js:1297 +#: addons/web/static/src/js/search.js:1311 +#: addons/web/static/src/js/search.js:1330 +#: addons/web/static/src/js/search.js:1349 +#: addons/web/static/src/js/search.js:1370 +msgid "is equal to" +msgstr "este egal cu" + +#. openerp-web +#: addons/web/static/src/js/search.js:1293 +#: addons/web/static/src/js/search.js:1307 +#: addons/web/static/src/js/search.js:1326 +#: addons/web/static/src/js/search.js:1345 +#: addons/web/static/src/js/search.js:1366 +#: addons/web/static/src/js/search.js:1298 +#: addons/web/static/src/js/search.js:1312 +#: addons/web/static/src/js/search.js:1331 +#: addons/web/static/src/js/search.js:1350 +#: addons/web/static/src/js/search.js:1371 +msgid "is not equal to" +msgstr "este diferit de" + +#. openerp-web +#: addons/web/static/src/js/search.js:1294 +#: addons/web/static/src/js/search.js:1308 +#: addons/web/static/src/js/search.js:1327 +#: addons/web/static/src/js/search.js:1346 +#: addons/web/static/src/js/search.js:1367 +#: addons/web/static/src/js/search.js:1299 +#: addons/web/static/src/js/search.js:1313 +#: addons/web/static/src/js/search.js:1332 +#: addons/web/static/src/js/search.js:1351 +#: addons/web/static/src/js/search.js:1372 +msgid "greater than" +msgstr "mai mare decât" + +#. openerp-web +#: addons/web/static/src/js/search.js:1295 +#: addons/web/static/src/js/search.js:1309 +#: addons/web/static/src/js/search.js:1328 +#: addons/web/static/src/js/search.js:1347 +#: addons/web/static/src/js/search.js:1368 +#: addons/web/static/src/js/search.js:1300 +#: addons/web/static/src/js/search.js:1314 +#: addons/web/static/src/js/search.js:1333 +#: addons/web/static/src/js/search.js:1352 +#: addons/web/static/src/js/search.js:1373 +msgid "less than" +msgstr "mai mic decât" + +#. openerp-web +#: addons/web/static/src/js/search.js:1296 +#: addons/web/static/src/js/search.js:1310 +#: addons/web/static/src/js/search.js:1329 +#: addons/web/static/src/js/search.js:1348 +#: addons/web/static/src/js/search.js:1369 +#: addons/web/static/src/js/search.js:1301 +#: addons/web/static/src/js/search.js:1315 +#: addons/web/static/src/js/search.js:1334 +#: addons/web/static/src/js/search.js:1353 +#: addons/web/static/src/js/search.js:1374 +msgid "greater or equal than" +msgstr "mai mare sau egal decât" + +#. openerp-web +#: addons/web/static/src/js/search.js:1297 +#: addons/web/static/src/js/search.js:1311 +#: addons/web/static/src/js/search.js:1330 +#: addons/web/static/src/js/search.js:1349 +#: addons/web/static/src/js/search.js:1370 +#: addons/web/static/src/js/search.js:1302 +#: addons/web/static/src/js/search.js:1316 +#: addons/web/static/src/js/search.js:1335 +#: addons/web/static/src/js/search.js:1354 +#: addons/web/static/src/js/search.js:1375 +msgid "less or equal than" +msgstr "mai mic sau egal decât" + +#. openerp-web +#: addons/web/static/src/js/search.js:1360 +#: addons/web/static/src/js/search.js:1383 +#: addons/web/static/src/js/search.js:1365 +#: addons/web/static/src/js/search.js:1388 +msgid "is" +msgstr "este" + +#. openerp-web +#: addons/web/static/src/js/search.js:1384 +#: addons/web/static/src/js/search.js:1389 +msgid "is not" +msgstr "nu este" + +#. openerp-web +#: addons/web/static/src/js/search.js:1396 +#: addons/web/static/src/js/search.js:1401 +msgid "is true" +msgstr "este adevărat" + +#. openerp-web +#: addons/web/static/src/js/search.js:1397 +#: addons/web/static/src/js/search.js:1402 +msgid "is false" +msgstr "este fals" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:20 +#, python-format +msgid "Manage Views (%s)" +msgstr "Gestionare View-uri (%s)" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:46 +#: addons/web/static/src/js/view_list.js:17 +#: addons/web/static/src/xml/base.xml:100 +#: addons/web/static/src/xml/base.xml:327 +#: addons/web/static/src/xml/base.xml:756 +msgid "Create" +msgstr "Crează" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:47 +#: addons/web/static/src/xml/base.xml:483 +#: addons/web/static/src/xml/base.xml:755 +msgid "Edit" +msgstr "Editare" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:48 +#: addons/web/static/src/xml/base.xml:1647 +msgid "Remove" +msgstr "Elimină" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:71 +#, python-format +msgid "Create a view (%s)" +msgstr "Creare view (%s)" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:168 +msgid "Do you really want to remove this view?" +msgstr "Doriți să eliminați această vedere?" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:364 +#, python-format +msgid "View Editor %d - %s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:367 +msgid "Inherited View" +msgstr "Vizualizare moștenită" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:371 +msgid "Do you really wants to create an inherited view here?" +msgstr "Sigur doriți crearea unui view moștenit ?" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:381 +msgid "Preview" +msgstr "Previzualizare" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:501 +msgid "Do you really want to remove this node?" +msgstr "Sigur doriți ștergerea acestui nod ?" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:815 +#: addons/web/static/src/js/view_editor.js:939 +msgid "Properties" +msgstr "Proprietăți" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:818 +#: addons/web/static/src/js/view_editor.js:942 +msgid "Update" +msgstr "Actualizează" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:16 +msgid "Form" +msgstr "Formular" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:121 +#: addons/web/static/src/js/views.js:803 +msgid "Customize" +msgstr "Personalizare" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:123 +#: addons/web/static/src/js/view_form.js:686 +#: addons/web/static/src/js/view_form.js:692 +msgid "Set Default" +msgstr "Setează ca implicit" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:469 +#: addons/web/static/src/js/view_form.js:475 +msgid "" +"Warning, the record has been modified, your changes will be discarded." +msgstr "" +"Atenție, înregistrarea a fost modificată, modificările vor fi eliminate." + +#. openerp-web +#: addons/web/static/src/js/view_form.js:693 +#: addons/web/static/src/js/view_form.js:699 +msgid "Save default" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:754 +#: addons/web/static/src/js/view_form.js:760 +msgid "Attachments" +msgstr "Atașamente" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:792 +#: addons/web/static/src/js/view_form.js:798 +#, python-format +msgid "Do you really want to delete the attachment %s?" +msgstr "Doriți ștergerea atașamentului %s?" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:822 +#: addons/web/static/src/js/view_form.js:828 +#, python-format +msgid "Unknown operator %s in domain %s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:830 +#: addons/web/static/src/js/view_form.js:836 +#, python-format +msgid "Unknown field %s in domain %s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:868 +#: addons/web/static/src/js/view_form.js:874 +#, python-format +msgid "Unsupported operator %s in domain %s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:1225 +#: addons/web/static/src/js/view_form.js:1231 +msgid "Confirm" +msgstr "Confirmă" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:1921 +#: addons/web/static/src/js/view_form.js:2578 +#: addons/web/static/src/js/view_form.js:2741 +#: addons/web/static/src/js/view_form.js:1933 +#: addons/web/static/src/js/view_form.js:2590 +#: addons/web/static/src/js/view_form.js:2760 +msgid "Open: " +msgstr "Deschide: " + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2049 +#: addons/web/static/src/js/view_form.js:2061 +msgid "   Search More..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2062 +#: addons/web/static/src/js/view_form.js:2074 +#, python-format +msgid "   Create \"%s\"" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2068 +#: addons/web/static/src/js/view_form.js:2080 +msgid "   Create and Edit..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2101 +#: addons/web/static/src/js/views.js:675 +#: addons/web/static/src/js/view_form.js:2113 +msgid "Search: " +msgstr "Caută: " + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2101 +#: addons/web/static/src/js/view_form.js:2550 +#: addons/web/static/src/js/view_form.js:2113 +#: addons/web/static/src/js/view_form.js:2562 +msgid "Create: " +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2661 +#: addons/web/static/src/xml/base.xml:750 +#: addons/web/static/src/xml/base.xml:772 +#: addons/web/static/src/xml/base.xml:1646 +#: addons/web/static/src/js/view_form.js:2680 +msgid "Add" +msgstr "Adaugă" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2721 +#: addons/web/static/src/js/view_form.js:2740 +msgid "Add: " +msgstr "Adaugă: " + +#. openerp-web +#: addons/web/static/src/js/view_list.js:8 +msgid "List" +msgstr "Listă" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:269 +msgid "Unlimited" +msgstr "Nelimitat" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:305 +#: addons/web/static/src/js/view_list.js:309 +#, python-format +msgid "[%(first_record)d to %(last_record)d] of %(records_count)d" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:524 +#: addons/web/static/src/js/view_list.js:528 +msgid "Do you really want to remove these records?" +msgstr "Doriți eliminarea acestor înregistrări?" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:1230 +#: addons/web/static/src/js/view_list.js:1232 +msgid "Undefined" +msgstr "Nedefinit" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:1327 +#: addons/web/static/src/js/view_list.js:1331 +#, python-format +msgid "%(page)d/%(page_count)d" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_page.js:8 +msgid "Page" +msgstr "Pagină" + +#. openerp-web +#: addons/web/static/src/js/view_page.js:52 +msgid "Do you really want to delete this record?" +msgstr "Sigur doriți ștergerea acestei înregistrări?" + +#. openerp-web +#: addons/web/static/src/js/view_tree.js:11 +msgid "Tree" +msgstr "Arbore" + +#. openerp-web +#: addons/web/static/src/js/views.js:565 +#: addons/web/static/src/xml/base.xml:480 +msgid "Fields View Get" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:573 +#, python-format +msgid "View Log (%s)" +msgstr "Arată jurnal (%s)" + +#. openerp-web +#: addons/web/static/src/js/views.js:600 +#, python-format +msgid "Model %s fields" +msgstr "Model %s câmpuri" + +#. openerp-web +#: addons/web/static/src/js/views.js:610 +#: addons/web/static/src/xml/base.xml:482 +msgid "Manage Views" +msgstr "Gestionare view-uri" + +#. openerp-web +#: addons/web/static/src/js/views.js:611 +msgid "Could not find current view declaration" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:805 +msgid "Translate" +msgstr "Traducere" + +#. openerp-web +#: addons/web/static/src/js/views.js:807 +msgid "Technical translation" +msgstr "Traducere tehnică" + +#. openerp-web +#: addons/web/static/src/js/views.js:811 +msgid "Other Options" +msgstr "Alte opțiuni" + +#. openerp-web +#: addons/web/static/src/js/views.js:814 +#: addons/web/static/src/xml/base.xml:1736 +msgid "Import" +msgstr "Importă" + +#. openerp-web +#: addons/web/static/src/js/views.js:817 +#: addons/web/static/src/xml/base.xml:1606 +msgid "Export" +msgstr "Exportă" + +#. openerp-web +#: addons/web/static/src/js/views.js:825 +msgid "Reports" +msgstr "Rapoarte" + +#. openerp-web +#: addons/web/static/src/js/views.js:825 +msgid "Actions" +msgstr "Acțiuni" + +#. openerp-web +#: addons/web/static/src/js/views.js:825 +msgid "Links" +msgstr "Linkuri" + +#. openerp-web +#: addons/web/static/src/js/views.js:919 +msgid "You must choose at least one record." +msgstr "Trebuie să alegeți cel puțin o înregistrare." + +#. openerp-web +#: addons/web/static/src/js/views.js:920 +msgid "Warning" +msgstr "Atenționare" + +#. openerp-web +#: addons/web/static/src/js/views.js:957 +msgid "Translations" +msgstr "Traduceri" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:44 +#: addons/web/static/src/xml/base.xml:315 +msgid "Powered by" +msgstr "Produs de" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:44 +#: addons/web/static/src/xml/base.xml:315 +#: addons/web/static/src/xml/base.xml:1813 +msgid "OpenERP" +msgstr "OpenERP" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:52 +msgid "Loading..." +msgstr "Se încarcă..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:61 +msgid "CREATE DATABASE" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:68 +#: addons/web/static/src/xml/base.xml:211 +msgid "Master password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:72 +#: addons/web/static/src/xml/base.xml:191 +msgid "New database name:" +msgstr "Nume baza date nouă:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:77 +msgid "Load Demonstration data:" +msgstr "Încărcare date demo:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:81 +msgid "Default language:" +msgstr "Limba implicită:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:91 +msgid "Admin password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:95 +msgid "Confirm password:" +msgstr "Confirmați parola:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:109 +msgid "DROP DATABASE" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:116 +#: addons/web/static/src/xml/base.xml:150 +#: addons/web/static/src/xml/base.xml:301 +msgid "Database:" +msgstr "Bază de date:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:128 +#: addons/web/static/src/xml/base.xml:162 +#: addons/web/static/src/xml/base.xml:187 +msgid "Master Password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:132 +#: addons/web/static/src/xml/base.xml:328 +msgid "Drop" +msgstr "Aruncă" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:143 +msgid "BACKUP DATABASE" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:166 +#: addons/web/static/src/xml/base.xml:329 +msgid "Backup" +msgstr "Copie de siguranță" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:175 +msgid "RESTORE DATABASE" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:182 +msgid "File:" +msgstr "Fișier:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:195 +#: addons/web/static/src/xml/base.xml:330 +msgid "Restore" +msgstr "Restaurare" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:204 +msgid "CHANGE MASTER PASSWORD" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:216 +msgid "New master password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:221 +msgid "Confirm new master password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:251 +msgid "" +"Your version of OpenERP is unsupported. Support & maintenance services are " +"available here:" +msgstr "" +"Versiunea OpenERP vă este fără suport. Serviciul de suport & întreținere " +"este disponibil aici:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:251 +msgid "OpenERP Entreprise" +msgstr "OpenERP Entreprise" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:256 +msgid "OpenERP Enterprise Contract." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:257 +msgid "Your report will be sent to the OpenERP Enterprise team." +msgstr "Raportul va fi trimis echipei OpenERP Enterprise" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:259 +msgid "Summary:" +msgstr "Rezumat:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:263 +msgid "Description:" +msgstr "Descriere:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:267 +msgid "What you did:" +msgstr "Ce ați făcut:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:297 +msgid "Invalid username or password" +msgstr "Nume de utilizator sau parolă incorecte." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:306 +msgid "Username" +msgstr "Nume utilizator" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:308 +#: addons/web/static/src/xml/base.xml:331 +msgid "Password" +msgstr "Parolă" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:310 +msgid "Log in" +msgstr "Autentificare" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:314 +msgid "Manage Databases" +msgstr "Administrează baza de date" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:332 +msgid "Back to Login" +msgstr "Înapoi la autentificare" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:353 +msgid "Home" +msgstr "Acasă" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:363 +msgid "LOGOUT" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:388 +msgid "Fold menu" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:389 +msgid "Unfold menu" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:454 +msgid "Hide this tip" +msgstr "Ascunde acest sfat" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:455 +msgid "Disable all tips" +msgstr "Dezactivarea tuturor sugestiilor" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:463 +msgid "Add / Remove Shortcut..." +msgstr "Adăugare / Ștergere shortcut ..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:471 +msgid "More…" +msgstr "Mai mult..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:477 +msgid "Debug View#" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:478 +msgid "View Log (perm_read)" +msgstr "Arată jurnal (perm_read)" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:479 +msgid "View Fields" +msgstr "Arată câmpurile" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:483 +msgid "View" +msgstr "Vizualizare" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:484 +msgid "Edit SearchView" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:485 +msgid "Edit Action" +msgstr "Editează acțiunea" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:486 +msgid "Edit Workflow" +msgstr "Editare workflow" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:491 +msgid "ID:" +msgstr "ID:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:494 +msgid "XML ID:" +msgstr "XML ID:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:497 +msgid "Creation User:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:500 +msgid "Creation Date:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:503 +msgid "Latest Modification by:" +msgstr "Ultimele modificări de:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:506 +msgid "Latest Modification Date:" +msgstr "Data ultimelor modificări" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:542 +msgid "Field" +msgstr "Câmp" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:632 +#: addons/web/static/src/xml/base.xml:758 +#: addons/web/static/src/xml/base.xml:1708 +msgid "Delete" +msgstr "Șterge" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:757 +msgid "Duplicate" +msgstr "Duplicată" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:775 +msgid "Add attachment" +msgstr "Adaugă atașament" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:801 +msgid "Default:" +msgstr "Implicit:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:818 +msgid "Condition:" +msgstr "Condiție:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:837 +msgid "Only you" +msgstr "Numai tu" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:844 +msgid "All users" +msgstr "Toți utilizatorii" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:851 +msgid "Unhandled widget" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:900 +msgid "Notebook Page \"" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:905 +#: addons/web/static/src/xml/base.xml:964 +msgid "Modifiers:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:931 +msgid "(nolabel)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:936 +msgid "Field:" +msgstr "Câmp:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:940 +msgid "Object:" +msgstr "Obiect:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:944 +msgid "Type:" +msgstr "Tip:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:948 +msgid "Widget:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:952 +msgid "Size:" +msgstr "Dimensiune:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:956 +msgid "Context:" +msgstr "Context:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:960 +msgid "Domain:" +msgstr "Domeniu:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:968 +msgid "Change default:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:972 +msgid "On change:" +msgstr "La modificare" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:976 +msgid "Relation:" +msgstr "Relații:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:980 +msgid "Selection:" +msgstr "Selecţie:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1020 +msgid "Send an e-mail with your default e-mail client" +msgstr "Trimiteți un e-mail cu clientul de e-mail implicit" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1034 +msgid "Open this resource" +msgstr "Deschide acestă resursă" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1056 +msgid "Select date" +msgstr "Selectați data" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1090 +msgid "Open..." +msgstr "Deschide..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1091 +msgid "Create..." +msgstr "Crează..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1092 +msgid "Search..." +msgstr "Caută..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1095 +msgid "..." +msgstr "..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1155 +#: addons/web/static/src/xml/base.xml:1198 +msgid "Set Image" +msgstr "Setează imagine" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1163 +#: addons/web/static/src/xml/base.xml:1213 +#: addons/web/static/src/xml/base.xml:1215 +#: addons/web/static/src/xml/base.xml:1272 +msgid "Clear" +msgstr "Curăță" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1172 +#: addons/web/static/src/xml/base.xml:1223 +msgid "Uploading ..." +msgstr "Se încarcă..." + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1200 +#: addons/web/static/src/xml/base.xml:1495 +msgid "Select" +msgstr "Selectați" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1207 +#: addons/web/static/src/xml/base.xml:1209 +msgid "Save As" +msgstr "Salvează ca" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1238 +msgid "Button" +msgstr "Buton" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1241 +msgid "(no string)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1248 +msgid "Special:" +msgstr "Special:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1253 +msgid "Button Type:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1257 +msgid "Method:" +msgstr "Metodă:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1261 +msgid "Action ID:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1271 +msgid "Search" +msgstr "Caută" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1279 +msgid "Filters" +msgstr "Filtre" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1280 +msgid "-- Filters --" +msgstr "-- Filtre --" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1289 +msgid "-- Actions --" +msgstr "-- Acțiuni --" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1290 +msgid "Add Advanced Filter" +msgstr "Adaugă filtrul avansat" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1291 +msgid "Save Filter" +msgstr "Salvează filtru" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1293 +msgid "Manage Filters" +msgstr "Administrare filtre" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1298 +msgid "Filter Name:" +msgstr "Nume filtru:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1300 +msgid "(Any existing filter with the same name will be replaced)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1305 +msgid "Select Dashboard to add this filter to:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1309 +msgid "Title of new Dashboard item:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1416 +msgid "Advanced Filters" +msgstr "Filtre avansate" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1426 +msgid "Any of the following conditions must match" +msgstr "Oricare dintre următoarele condiţii trebuie să se potrivească" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1427 +msgid "All the following conditions must match" +msgstr "Toate condițiile următoare trebuie să se potrivească" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1428 +msgid "None of the following conditions must match" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1435 +msgid "Add condition" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1436 +msgid "and" +msgstr "și" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1503 +msgid "Save & New" +msgstr "Salvează & Crează înregistrare nouă" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1504 +msgid "Save & Close" +msgstr "Salvează & Închide" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1611 +msgid "" +"This wizard will export all data that matches the current search criteria to " +"a CSV file.\n" +" You can export all data or only the fields that can be " +"reimported after modification." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1618 +msgid "Export Type:" +msgstr "Tipul exportului :" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1620 +msgid "Import Compatible Export" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1621 +msgid "Export all Data" +msgstr "Exportă toate datele" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1624 +msgid "Export Formats" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1630 +msgid "Available fields" +msgstr "Câmpuri disponibile" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1632 +msgid "Fields to export" +msgstr "Câmpurile de exportat" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1634 +msgid "Save fields list" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1648 +msgid "Remove All" +msgstr "Eliminați toate" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1660 +msgid "Name" +msgstr "Nume" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1693 +msgid "Save as:" +msgstr "Salvează ca:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1700 +msgid "Saved exports:" +msgstr "Exporturi salvate :" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1714 +msgid "Old Password:" +msgstr "Parola veche:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1719 +msgid "New Password:" +msgstr "Parola nouă:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1724 +msgid "Confirm Password:" +msgstr "Confirmați parola:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1742 +msgid "1. Import a .CSV file" +msgstr "1. Importarea unui fișier .CSV" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1743 +msgid "" +"Select a .CSV file to import. If you need a sample of file to import,\n" +" you should use the export tool with the \"Import Compatible\" option." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1747 +msgid "CSV File:" +msgstr "Fișier CSV:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1750 +msgid "2. Check your file format" +msgstr "2. Verificarea formatului de fișier" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1753 +msgid "Import Options" +msgstr "Opțiuni de import" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1757 +msgid "Does your file have titles?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1763 +msgid "Separator:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1765 +msgid "Delimiter:" +msgstr "Delimitator:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1769 +msgid "Encoding:" +msgstr "Codificare:" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1772 +msgid "UTF-8" +msgstr "UTF-8" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1773 +msgid "Latin 1" +msgstr "Latin 1" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1776 +msgid "Lines to skip" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1776 +msgid "" +"For use if CSV files have titles on multiple lines, skips more than a single " +"line during import" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1803 +msgid "The import failed due to:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1805 +msgid "Here is a preview of the file we could not import:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1812 +msgid "Activate the developper mode" +msgstr "Activează modul de dezvoltare" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1814 +msgid "Version" +msgstr "Versiune" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1815 +msgid "Copyright © 2004-TODAY OpenERP SA. All Rights Reserved." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1816 +msgid "OpenERP is a trademark of the" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1817 +msgid "OpenERP SA Company" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1819 +msgid "Licenced under the terms of" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1820 +msgid "GNU Affero General Public License" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1822 +msgid "For more information visit" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1823 +msgid "OpenERP.com" +msgstr "" diff --git a/addons/web/i18n/ru.po b/addons/web/i18n/ru.po index 93ea3a568b1..ab25cd47295 100644 --- a/addons/web/i18n/ru.po +++ b/addons/web/i18n/ru.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-14 15:27+0100\n" -"PO-Revision-Date: 2012-02-08 07:26+0000\n" +"PO-Revision-Date: 2012-02-20 07:27+0000\n" "Last-Translator: Aleksei Motsik \n" "Language-Team: Russian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-15 05:43+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-21 06:10+0000\n" +"X-Generator: Launchpad (build 14838)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:172 @@ -150,12 +150,12 @@ msgstr "Экспортировать в файл" #. openerp-web #: addons/web/static/src/js/data_export.js:125 msgid "Please enter save field list name" -msgstr "" +msgstr "Введите имя для сохраняемого списка полей" #. openerp-web #: addons/web/static/src/js/data_export.js:360 msgid "Please select fields to save export list..." -msgstr "" +msgstr "Выберите поля для сохранения в списке экспорта..." #. openerp-web #: addons/web/static/src/js/data_export.js:373 @@ -192,7 +192,7 @@ msgstr "Загрузка \"%s\"" #. openerp-web #: addons/web/static/src/js/search.js:191 msgid "Filter disabled due to invalid syntax" -msgstr "" +msgstr "Фильтр отключен так-как имеет неверный синтаксис" #. openerp-web #: addons/web/static/src/js/search.js:237 @@ -219,7 +219,7 @@ msgstr "Ошибка поиска" #. openerp-web #: addons/web/static/src/js/search.js:415 msgid "triggered from search view" -msgstr "" +msgstr "вызвано из поиска" #. openerp-web #: addons/web/static/src/js/search.js:503 @@ -382,12 +382,12 @@ msgstr "Редактор Вида %d - %s" #. openerp-web #: addons/web/static/src/js/view_editor.js:367 msgid "Inherited View" -msgstr "" +msgstr "Унаследованный Вид" #. openerp-web #: addons/web/static/src/js/view_editor.js:371 msgid "Do you really wants to create an inherited view here?" -msgstr "" +msgstr "Вы действительно хотите создать наследующий вид?" #. openerp-web #: addons/web/static/src/js/view_editor.js:381 @@ -426,7 +426,7 @@ msgstr "Настроить" #: addons/web/static/src/js/view_form.js:123 #: addons/web/static/src/js/view_form.js:686 msgid "Set Default" -msgstr "" +msgstr "Установить по умолчанию" #. openerp-web #: addons/web/static/src/js/view_form.js:469 @@ -437,7 +437,7 @@ msgstr "Внимание. Эта запись была изменена. Ваш #. openerp-web #: addons/web/static/src/js/view_form.js:693 msgid "Save default" -msgstr "" +msgstr "Сохранить как По Умолчанию" #. openerp-web #: addons/web/static/src/js/view_form.js:754 @@ -551,7 +551,7 @@ msgstr "Не определено" #: addons/web/static/src/js/view_list.js:1327 #, python-format msgid "%(page)d/%(page_count)d" -msgstr "" +msgstr "%(page)d/%(page_count)d" #. openerp-web #: addons/web/static/src/js/view_page.js:8 @@ -571,7 +571,7 @@ msgstr "Дерево" #. openerp-web #: addons/web/static/src/js/views.js:565 addons/web/static/src/xml/base.xml:480 msgid "Fields View Get" -msgstr "" +msgstr "Получить Поля Просмотра" #. openerp-web #: addons/web/static/src/js/views.js:573 @@ -843,7 +843,7 @@ msgstr "Вернутся к Авторизации" #. openerp-web #: addons/web/static/src/xml/base.xml:353 msgid "Home" -msgstr "" +msgstr "Домой" #. openerp-web #: addons/web/static/src/xml/base.xml:363 @@ -853,12 +853,12 @@ msgstr "ВЫЙТИ" #. openerp-web #: addons/web/static/src/xml/base.xml:388 msgid "Fold menu" -msgstr "" +msgstr "Свернуть меню" #. openerp-web #: addons/web/static/src/xml/base.xml:389 msgid "Unfold menu" -msgstr "" +msgstr "Развернуть меню" #. openerp-web #: addons/web/static/src/xml/base.xml:454 @@ -873,7 +873,7 @@ msgstr "Отключить все подсказки" #. openerp-web #: addons/web/static/src/xml/base.xml:463 msgid "Add / Remove Shortcut..." -msgstr "" +msgstr "Добавить / Удалить ярлык..." #. openerp-web #: addons/web/static/src/xml/base.xml:471 @@ -883,32 +883,32 @@ msgstr "Больше..." #. openerp-web #: addons/web/static/src/xml/base.xml:477 msgid "Debug View#" -msgstr "" +msgstr "Debug View#" #. openerp-web #: addons/web/static/src/xml/base.xml:478 msgid "View Log (perm_read)" -msgstr "" +msgstr "Просмотр Лога (доступ на чтение)" #. openerp-web #: addons/web/static/src/xml/base.xml:479 msgid "View Fields" -msgstr "" +msgstr "Просмотр Полей" #. openerp-web #: addons/web/static/src/xml/base.xml:483 msgid "View" -msgstr "" +msgstr "Вид" #. openerp-web #: addons/web/static/src/xml/base.xml:484 msgid "Edit SearchView" -msgstr "" +msgstr "Изменить Вид Поиска" #. openerp-web #: addons/web/static/src/xml/base.xml:485 msgid "Edit Action" -msgstr "" +msgstr "Изменить действие" #. openerp-web #: addons/web/static/src/xml/base.xml:486 @@ -918,191 +918,191 @@ msgstr "Редактировать Процесс" #. openerp-web #: addons/web/static/src/xml/base.xml:491 msgid "ID:" -msgstr "" +msgstr "ID:" #. openerp-web #: addons/web/static/src/xml/base.xml:494 msgid "XML ID:" -msgstr "" +msgstr "XML ID:" #. openerp-web #: addons/web/static/src/xml/base.xml:497 msgid "Creation User:" -msgstr "" +msgstr "Создатель:" #. openerp-web #: addons/web/static/src/xml/base.xml:500 msgid "Creation Date:" -msgstr "" +msgstr "Дата Создания:" #. openerp-web #: addons/web/static/src/xml/base.xml:503 msgid "Latest Modification by:" -msgstr "" +msgstr "Изменялся:" #. openerp-web #: addons/web/static/src/xml/base.xml:506 msgid "Latest Modification Date:" -msgstr "" +msgstr "Дата Изменения:" #. openerp-web #: addons/web/static/src/xml/base.xml:542 msgid "Field" -msgstr "" +msgstr "Поле" #. openerp-web #: addons/web/static/src/xml/base.xml:632 #: addons/web/static/src/xml/base.xml:758 #: addons/web/static/src/xml/base.xml:1708 msgid "Delete" -msgstr "" +msgstr "Удалить" #. openerp-web #: addons/web/static/src/xml/base.xml:757 msgid "Duplicate" -msgstr "" +msgstr "Клонировать" #. openerp-web #: addons/web/static/src/xml/base.xml:775 msgid "Add attachment" -msgstr "" +msgstr "Добавить вложение" #. openerp-web #: addons/web/static/src/xml/base.xml:801 msgid "Default:" -msgstr "" +msgstr "По умолчанию:" #. openerp-web #: addons/web/static/src/xml/base.xml:818 msgid "Condition:" -msgstr "" +msgstr "Условие:" #. openerp-web #: addons/web/static/src/xml/base.xml:837 msgid "Only you" -msgstr "" +msgstr "Только Вы" #. openerp-web #: addons/web/static/src/xml/base.xml:844 msgid "All users" -msgstr "" +msgstr "Все пользователи" #. openerp-web #: addons/web/static/src/xml/base.xml:851 msgid "Unhandled widget" -msgstr "" +msgstr "Неподдерживаемый виджет" #. openerp-web #: addons/web/static/src/xml/base.xml:900 msgid "Notebook Page \"" -msgstr "" +msgstr "Страница Блокнота \"" #. openerp-web #: addons/web/static/src/xml/base.xml:905 #: addons/web/static/src/xml/base.xml:964 msgid "Modifiers:" -msgstr "" +msgstr "Модификаторы:" #. openerp-web #: addons/web/static/src/xml/base.xml:931 msgid "(nolabel)" -msgstr "" +msgstr "(без метки)" #. openerp-web #: addons/web/static/src/xml/base.xml:936 msgid "Field:" -msgstr "" +msgstr "Поле:" #. openerp-web #: addons/web/static/src/xml/base.xml:940 msgid "Object:" -msgstr "" +msgstr "Объект:" #. openerp-web #: addons/web/static/src/xml/base.xml:944 msgid "Type:" -msgstr "" +msgstr "Тип:" #. openerp-web #: addons/web/static/src/xml/base.xml:948 msgid "Widget:" -msgstr "" +msgstr "Виджет:" #. openerp-web #: addons/web/static/src/xml/base.xml:952 msgid "Size:" -msgstr "" +msgstr "Размер:" #. openerp-web #: addons/web/static/src/xml/base.xml:956 msgid "Context:" -msgstr "" +msgstr "Контекст:" #. openerp-web #: addons/web/static/src/xml/base.xml:960 msgid "Domain:" -msgstr "" +msgstr "Домен:" #. openerp-web #: addons/web/static/src/xml/base.xml:968 msgid "Change default:" -msgstr "" +msgstr "Изменить по умолчанию:" #. openerp-web #: addons/web/static/src/xml/base.xml:972 msgid "On change:" -msgstr "" +msgstr "При изменении:" #. openerp-web #: addons/web/static/src/xml/base.xml:976 msgid "Relation:" -msgstr "" +msgstr "Отношение:" #. openerp-web #: addons/web/static/src/xml/base.xml:980 msgid "Selection:" -msgstr "" +msgstr "Выбор:" #. openerp-web #: addons/web/static/src/xml/base.xml:1020 msgid "Send an e-mail with your default e-mail client" -msgstr "" +msgstr "Отправлять имейл вашим почтовым клиентом" #. openerp-web #: addons/web/static/src/xml/base.xml:1034 msgid "Open this resource" -msgstr "" +msgstr "Открыть этот ресурс" #. openerp-web #: addons/web/static/src/xml/base.xml:1056 msgid "Select date" -msgstr "" +msgstr "Выбрать дату" #. openerp-web #: addons/web/static/src/xml/base.xml:1090 msgid "Open..." -msgstr "" +msgstr "Открыть..." #. openerp-web #: addons/web/static/src/xml/base.xml:1091 msgid "Create..." -msgstr "" +msgstr "Создать…" #. openerp-web #: addons/web/static/src/xml/base.xml:1092 msgid "Search..." -msgstr "" +msgstr "Поиск…" #. openerp-web #: addons/web/static/src/xml/base.xml:1095 msgid "..." -msgstr "" +msgstr "..." #. openerp-web #: addons/web/static/src/xml/base.xml:1155 #: addons/web/static/src/xml/base.xml:1198 msgid "Set Image" -msgstr "" +msgstr "Назначить изображение" #. openerp-web #: addons/web/static/src/xml/base.xml:1163 @@ -1110,150 +1110,150 @@ msgstr "" #: addons/web/static/src/xml/base.xml:1215 #: addons/web/static/src/xml/base.xml:1272 msgid "Clear" -msgstr "" +msgstr "Очистить" #. openerp-web #: addons/web/static/src/xml/base.xml:1172 #: addons/web/static/src/xml/base.xml:1223 msgid "Uploading ..." -msgstr "" +msgstr "Загружаю ..." #. openerp-web #: addons/web/static/src/xml/base.xml:1200 #: addons/web/static/src/xml/base.xml:1495 msgid "Select" -msgstr "" +msgstr "Выбор" #. openerp-web #: addons/web/static/src/xml/base.xml:1207 #: addons/web/static/src/xml/base.xml:1209 msgid "Save As" -msgstr "" +msgstr "Сохранить как" #. openerp-web #: addons/web/static/src/xml/base.xml:1238 msgid "Button" -msgstr "" +msgstr "Кнопка" #. openerp-web #: addons/web/static/src/xml/base.xml:1241 msgid "(no string)" -msgstr "" +msgstr "(нет строки)" #. openerp-web #: addons/web/static/src/xml/base.xml:1248 msgid "Special:" -msgstr "" +msgstr "Специальное:" #. openerp-web #: addons/web/static/src/xml/base.xml:1253 msgid "Button Type:" -msgstr "" +msgstr "Тип Кнопки:" #. openerp-web #: addons/web/static/src/xml/base.xml:1257 msgid "Method:" -msgstr "" +msgstr "Метод:" #. openerp-web #: addons/web/static/src/xml/base.xml:1261 msgid "Action ID:" -msgstr "" +msgstr "ID Действия:" #. openerp-web #: addons/web/static/src/xml/base.xml:1271 msgid "Search" -msgstr "" +msgstr "Поиск" #. openerp-web #: addons/web/static/src/xml/base.xml:1279 msgid "Filters" -msgstr "" +msgstr "Фильтры" #. openerp-web #: addons/web/static/src/xml/base.xml:1280 msgid "-- Filters --" -msgstr "" +msgstr "-- Фильтры --" #. openerp-web #: addons/web/static/src/xml/base.xml:1289 msgid "-- Actions --" -msgstr "" +msgstr "-- Действия --" #. openerp-web #: addons/web/static/src/xml/base.xml:1290 msgid "Add Advanced Filter" -msgstr "" +msgstr "Добавить Расширенный Фильтр" #. openerp-web #: addons/web/static/src/xml/base.xml:1291 msgid "Save Filter" -msgstr "" +msgstr "Сохранить фильтр" #. openerp-web #: addons/web/static/src/xml/base.xml:1293 msgid "Manage Filters" -msgstr "" +msgstr "Управление фильтрами" #. openerp-web #: addons/web/static/src/xml/base.xml:1298 msgid "Filter Name:" -msgstr "" +msgstr "Название Фильтра:" #. openerp-web #: addons/web/static/src/xml/base.xml:1300 msgid "(Any existing filter with the same name will be replaced)" -msgstr "" +msgstr "(Существующий фильтр с таким же именени будет замещен)" #. openerp-web #: addons/web/static/src/xml/base.xml:1305 msgid "Select Dashboard to add this filter to:" -msgstr "" +msgstr "Выберите Дашбоард, к которому добавить этот фильтр:" #. openerp-web #: addons/web/static/src/xml/base.xml:1309 msgid "Title of new Dashboard item:" -msgstr "" +msgstr "Заголовок нового Дашбоарда:" #. openerp-web #: addons/web/static/src/xml/base.xml:1416 msgid "Advanced Filters" -msgstr "" +msgstr "Расширенные Фильтры" #. openerp-web #: addons/web/static/src/xml/base.xml:1426 msgid "Any of the following conditions must match" -msgstr "" +msgstr "Одно из следующих условий должно соответствовать" #. openerp-web #: addons/web/static/src/xml/base.xml:1427 msgid "All the following conditions must match" -msgstr "" +msgstr "Все следующие условия должны соответствовать" #. openerp-web #: addons/web/static/src/xml/base.xml:1428 msgid "None of the following conditions must match" -msgstr "" +msgstr "Ни одно из следующих условий не должно соответствовать" #. openerp-web #: addons/web/static/src/xml/base.xml:1435 msgid "Add condition" -msgstr "" +msgstr "Добавить условие" #. openerp-web #: addons/web/static/src/xml/base.xml:1436 msgid "and" -msgstr "" +msgstr "и" #. openerp-web #: addons/web/static/src/xml/base.xml:1503 msgid "Save & New" -msgstr "" +msgstr "Сохранить и Создать" #. openerp-web #: addons/web/static/src/xml/base.xml:1504 msgid "Save & Close" -msgstr "" +msgstr "Сохранить и Закрыть" #. openerp-web #: addons/web/static/src/xml/base.xml:1611 @@ -1263,81 +1263,84 @@ msgid "" " You can export all data or only the fields that can be " "reimported after modification." msgstr "" +"Этот мастер экспортирует все найденные данные в CSV файл.\n" +" Вы можете экспортровать все данные либо только те поля которые " +"могут быть в последствии импортированны." #. openerp-web #: addons/web/static/src/xml/base.xml:1618 msgid "Export Type:" -msgstr "" +msgstr "Тип экспорта:" #. openerp-web #: addons/web/static/src/xml/base.xml:1620 msgid "Import Compatible Export" -msgstr "" +msgstr "Импорт совместимого Экспорта" #. openerp-web #: addons/web/static/src/xml/base.xml:1621 msgid "Export all Data" -msgstr "" +msgstr "Экспортировать все данные" #. openerp-web #: addons/web/static/src/xml/base.xml:1624 msgid "Export Formats" -msgstr "" +msgstr "Форматы Экспорта" #. openerp-web #: addons/web/static/src/xml/base.xml:1630 msgid "Available fields" -msgstr "" +msgstr "Доступные поля" #. openerp-web #: addons/web/static/src/xml/base.xml:1632 msgid "Fields to export" -msgstr "" +msgstr "Поля для экспорта" #. openerp-web #: addons/web/static/src/xml/base.xml:1634 msgid "Save fields list" -msgstr "" +msgstr "Сохранить список полей" #. openerp-web #: addons/web/static/src/xml/base.xml:1648 msgid "Remove All" -msgstr "" +msgstr "Удалить все" #. openerp-web #: addons/web/static/src/xml/base.xml:1660 msgid "Name" -msgstr "" +msgstr "Название" #. openerp-web #: addons/web/static/src/xml/base.xml:1693 msgid "Save as:" -msgstr "" +msgstr "Сохранить как:" #. openerp-web #: addons/web/static/src/xml/base.xml:1700 msgid "Saved exports:" -msgstr "" +msgstr "Сохраненые экспорты:" #. openerp-web #: addons/web/static/src/xml/base.xml:1714 msgid "Old Password:" -msgstr "" +msgstr "Старый пароль:" #. openerp-web #: addons/web/static/src/xml/base.xml:1719 msgid "New Password:" -msgstr "" +msgstr "Новый пароль:" #. openerp-web #: addons/web/static/src/xml/base.xml:1724 msgid "Confirm Password:" -msgstr "" +msgstr "Пароль ещё раз:" #. openerp-web #: addons/web/static/src/xml/base.xml:1742 msgid "1. Import a .CSV file" -msgstr "" +msgstr "1. Импорт из .CSV файла" #. openerp-web #: addons/web/static/src/xml/base.xml:1743 @@ -1345,56 +1348,59 @@ msgid "" "Select a .CSV file to import. If you need a sample of file to import,\n" " you should use the export tool with the \"Import Compatible\" option." msgstr "" +"Укажите .CSV файл для импорта. Если вам нужен пример такого файла,\n" +" воспользуйтесь инструментом экспорта с опцией \"Совместимость для " +"Импорта\"." #. openerp-web #: addons/web/static/src/xml/base.xml:1747 msgid "CSV File:" -msgstr "" +msgstr "Файл CSV:" #. openerp-web #: addons/web/static/src/xml/base.xml:1750 msgid "2. Check your file format" -msgstr "" +msgstr "2. Проверьте формат файла" #. openerp-web #: addons/web/static/src/xml/base.xml:1753 msgid "Import Options" -msgstr "" +msgstr "Параметры импорта" #. openerp-web #: addons/web/static/src/xml/base.xml:1757 msgid "Does your file have titles?" -msgstr "" +msgstr "В файле есть заголовки (строка с названиями колонок)?" #. openerp-web #: addons/web/static/src/xml/base.xml:1763 msgid "Separator:" -msgstr "" +msgstr "Разделитель:" #. openerp-web #: addons/web/static/src/xml/base.xml:1765 msgid "Delimiter:" -msgstr "" +msgstr "Разделитель:" #. openerp-web #: addons/web/static/src/xml/base.xml:1769 msgid "Encoding:" -msgstr "" +msgstr "Кодировка:" #. openerp-web #: addons/web/static/src/xml/base.xml:1772 msgid "UTF-8" -msgstr "" +msgstr "UTF-8" #. openerp-web #: addons/web/static/src/xml/base.xml:1773 msgid "Latin 1" -msgstr "" +msgstr "Latin 1" #. openerp-web #: addons/web/static/src/xml/base.xml:1776 msgid "Lines to skip" -msgstr "" +msgstr "Пропустить строки" #. openerp-web #: addons/web/static/src/xml/base.xml:1776 @@ -1402,58 +1408,60 @@ msgid "" "For use if CSV files have titles on multiple lines, skips more than a single " "line during import" msgstr "" +"Применимо если в CSV файле заголовки расположены в нескольких строках и из " +"необходимо пропустить" #. openerp-web #: addons/web/static/src/xml/base.xml:1803 msgid "The import failed due to:" -msgstr "" +msgstr "Импорт не выполнен по причине:" #. openerp-web #: addons/web/static/src/xml/base.xml:1805 msgid "Here is a preview of the file we could not import:" -msgstr "" +msgstr "Предпросмотр файла, который система не смогла импортировать:" #. openerp-web #: addons/web/static/src/xml/base.xml:1812 msgid "Activate the developper mode" -msgstr "" +msgstr "Активировать режим разработчика" #. openerp-web #: addons/web/static/src/xml/base.xml:1814 msgid "Version" -msgstr "" +msgstr "Версия" #. openerp-web #: addons/web/static/src/xml/base.xml:1815 msgid "Copyright © 2004-TODAY OpenERP SA. All Rights Reserved." -msgstr "" +msgstr "Авторское право © 2004-СЕГОДНЯ OpenERP SA. Все Права Защищены." #. openerp-web #: addons/web/static/src/xml/base.xml:1816 msgid "OpenERP is a trademark of the" -msgstr "" +msgstr "OpenERP является торговым знаком" #. openerp-web #: addons/web/static/src/xml/base.xml:1817 msgid "OpenERP SA Company" -msgstr "" +msgstr "OpenERP SA Company" #. openerp-web #: addons/web/static/src/xml/base.xml:1819 msgid "Licenced under the terms of" -msgstr "" +msgstr "Лицензированно по условиям" #. openerp-web #: addons/web/static/src/xml/base.xml:1820 msgid "GNU Affero General Public License" -msgstr "" +msgstr "GNU Affero General Public License" #. openerp-web #: addons/web/static/src/xml/base.xml:1822 msgid "For more information visit" -msgstr "" +msgstr "Для получения подробной информации посетите" #. openerp-web #: addons/web/static/src/xml/base.xml:1823 msgid "OpenERP.com" -msgstr "" +msgstr "OpenERP.com" diff --git a/addons/web/i18n/tr.po b/addons/web/i18n/tr.po index 58ca46c1fcc..e63d10d4905 100644 --- a/addons/web/i18n/tr.po +++ b/addons/web/i18n/tr.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-14 15:27+0100\n" -"PO-Revision-Date: 2012-02-09 20:50+0000\n" +"PO-Revision-Date: 2012-02-24 11:29+0000\n" "Last-Translator: Ahmet Altınışık \n" "Language-Team: Turkish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-15 05:43+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-25 05:30+0000\n" +"X-Generator: Launchpad (build 14860)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:172 @@ -192,7 +192,7 @@ msgstr "Karşıdan yükle \"%s\"" #. openerp-web #: addons/web/static/src/js/search.js:191 msgid "Filter disabled due to invalid syntax" -msgstr "" +msgstr "Geçersiz sözdizimi nedeniyle filtre engellendi" #. openerp-web #: addons/web/static/src/js/search.js:237 @@ -381,12 +381,12 @@ msgstr "Editörü göster %d - %s" #. openerp-web #: addons/web/static/src/js/view_editor.js:367 msgid "Inherited View" -msgstr "" +msgstr "Devralınan Görünüm" #. openerp-web #: addons/web/static/src/js/view_editor.js:371 msgid "Do you really wants to create an inherited view here?" -msgstr "" +msgstr "Devralınmış görünüm oluşturmak istediğinden emin misin?" #. openerp-web #: addons/web/static/src/js/view_editor.js:381 diff --git a/addons/web/i18n/uk.po b/addons/web/i18n/uk.po new file mode 100644 index 00000000000..67fd1f9a9ff --- /dev/null +++ b/addons/web/i18n/uk.po @@ -0,0 +1,1456 @@ +# Ukrainian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-02-28 19:20+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Ukrainian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-02-29 04:54+0000\n" +"X-Generator: Launchpad (build 14874)\n" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:172 +#: addons/web/static/src/js/chrome.js:198 +#: addons/web/static/src/js/chrome.js:414 +#: addons/web/static/src/js/view_form.js:419 +#: addons/web/static/src/js/view_form.js:1233 +#: addons/web/static/src/xml/base.xml:1695 +msgid "Ok" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:180 +msgid "Send OpenERP Enterprise Report" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:194 +msgid "Dont send" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:256 +#, python-format +msgid "Loading (%d)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:288 +msgid "Invalid database name" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:483 +msgid "Backed" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:484 +msgid "Database backed up successfully" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:527 +msgid "Restored" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:527 +msgid "Database restored successfully" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:708 +#: addons/web/static/src/xml/base.xml:359 +msgid "About" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:787 +#: addons/web/static/src/xml/base.xml:356 +msgid "Preferences" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:790 +#: addons/web/static/src/js/search.js:239 +#: addons/web/static/src/js/search.js:288 +#: addons/web/static/src/js/view_editor.js:95 +#: addons/web/static/src/js/view_editor.js:836 +#: addons/web/static/src/js/view_editor.js:962 +#: addons/web/static/src/js/view_form.js:1228 +#: addons/web/static/src/xml/base.xml:738 +#: addons/web/static/src/xml/base.xml:1496 +#: addons/web/static/src/xml/base.xml:1506 +#: addons/web/static/src/xml/base.xml:1515 +msgid "Cancel" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:791 +msgid "Change password" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:792 +#: addons/web/static/src/js/view_editor.js:73 +#: addons/web/static/src/js/views.js:962 addons/web/static/src/xml/base.xml:737 +#: addons/web/static/src/xml/base.xml:1500 +#: addons/web/static/src/xml/base.xml:1514 +msgid "Save" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:811 +#: addons/web/static/src/xml/base.xml:226 +#: addons/web/static/src/xml/base.xml:1729 +msgid "Change Password" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:1096 +msgid "OpenERP - Unsupported/Community Version" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/chrome.js:1131 +msgid "Client Error" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:6 +msgid "Export Data" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:19 +#: addons/web/static/src/js/data_import.js:69 +#: addons/web/static/src/js/view_editor.js:49 +#: addons/web/static/src/js/view_editor.js:398 +#: addons/web/static/src/js/view_form.js:692 +#: addons/web/static/src/js/view_form.js:3044 +#: addons/web/static/src/js/views.js:963 +msgid "Close" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:20 +msgid "Export To File" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:125 +msgid "Please enter save field list name" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:360 +msgid "Please select fields to save export list..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_export.js:373 +msgid "Please select fields to export..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_import.js:34 +msgid "Import Data" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_import.js:70 +msgid "Import File" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/data_import.js:105 +msgid "External ID" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/formats.js:300 +#: addons/web/static/src/js/view_page.js:245 +msgid "Download" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/formats.js:305 +#, python-format +msgid "Download \"%s\"" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:191 +msgid "Filter disabled due to invalid syntax" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:237 +msgid "Filter Entry" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:242 +#: addons/web/static/src/js/search.js:291 +msgid "OK" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:286 +#: addons/web/static/src/xml/base.xml:1292 +msgid "Add to Dashboard" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:415 +msgid "Invalid Search" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:415 +msgid "triggered from search view" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:503 +#, python-format +msgid "Incorrect value for field %(fieldname)s: [%(value)s] is %(message)s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:839 +msgid "not a valid integer" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:853 +msgid "not a valid number" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:931 +#: addons/web/static/src/xml/base.xml:968 +msgid "Yes" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:932 +msgid "No" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1290 +msgid "contains" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1291 +msgid "doesn't contain" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1292 +#: addons/web/static/src/js/search.js:1306 +#: addons/web/static/src/js/search.js:1325 +#: addons/web/static/src/js/search.js:1344 +#: addons/web/static/src/js/search.js:1365 +msgid "is equal to" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1293 +#: addons/web/static/src/js/search.js:1307 +#: addons/web/static/src/js/search.js:1326 +#: addons/web/static/src/js/search.js:1345 +#: addons/web/static/src/js/search.js:1366 +msgid "is not equal to" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1294 +#: addons/web/static/src/js/search.js:1308 +#: addons/web/static/src/js/search.js:1327 +#: addons/web/static/src/js/search.js:1346 +#: addons/web/static/src/js/search.js:1367 +msgid "greater than" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1295 +#: addons/web/static/src/js/search.js:1309 +#: addons/web/static/src/js/search.js:1328 +#: addons/web/static/src/js/search.js:1347 +#: addons/web/static/src/js/search.js:1368 +msgid "less than" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1296 +#: addons/web/static/src/js/search.js:1310 +#: addons/web/static/src/js/search.js:1329 +#: addons/web/static/src/js/search.js:1348 +#: addons/web/static/src/js/search.js:1369 +msgid "greater or equal than" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1297 +#: addons/web/static/src/js/search.js:1311 +#: addons/web/static/src/js/search.js:1330 +#: addons/web/static/src/js/search.js:1349 +#: addons/web/static/src/js/search.js:1370 +msgid "less or equal than" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1360 +#: addons/web/static/src/js/search.js:1383 +msgid "is" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1384 +msgid "is not" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1396 +msgid "is true" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/search.js:1397 +msgid "is false" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:20 +#, python-format +msgid "Manage Views (%s)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:46 +#: addons/web/static/src/js/view_list.js:17 +#: addons/web/static/src/xml/base.xml:100 +#: addons/web/static/src/xml/base.xml:327 +#: addons/web/static/src/xml/base.xml:756 +msgid "Create" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:47 +#: addons/web/static/src/xml/base.xml:483 +#: addons/web/static/src/xml/base.xml:755 +msgid "Edit" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:48 +#: addons/web/static/src/xml/base.xml:1647 +msgid "Remove" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:71 +#, python-format +msgid "Create a view (%s)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:168 +msgid "Do you really want to remove this view?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:364 +#, python-format +msgid "View Editor %d - %s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:367 +msgid "Inherited View" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:371 +msgid "Do you really wants to create an inherited view here?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:381 +msgid "Preview" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:501 +msgid "Do you really want to remove this node?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:815 +#: addons/web/static/src/js/view_editor.js:939 +msgid "Properties" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_editor.js:818 +#: addons/web/static/src/js/view_editor.js:942 +msgid "Update" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:16 +msgid "Form" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:121 +#: addons/web/static/src/js/views.js:803 +msgid "Customize" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:123 +#: addons/web/static/src/js/view_form.js:686 +msgid "Set Default" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:469 +msgid "" +"Warning, the record has been modified, your changes will be discarded." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:693 +msgid "Save default" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:754 +msgid "Attachments" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:792 +#, python-format +msgid "Do you really want to delete the attachment %s?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:822 +#, python-format +msgid "Unknown operator %s in domain %s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:830 +#, python-format +msgid "Unknown field %s in domain %s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:868 +#, python-format +msgid "Unsupported operator %s in domain %s" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:1225 +msgid "Confirm" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:1921 +#: addons/web/static/src/js/view_form.js:2578 +#: addons/web/static/src/js/view_form.js:2741 +msgid "Open: " +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2049 +msgid "   Search More..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2062 +#, python-format +msgid "   Create \"%s\"" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2068 +msgid "   Create and Edit..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2101 +#: addons/web/static/src/js/views.js:675 +msgid "Search: " +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2101 +#: addons/web/static/src/js/view_form.js:2550 +msgid "Create: " +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2661 +#: addons/web/static/src/xml/base.xml:750 +#: addons/web/static/src/xml/base.xml:772 +#: addons/web/static/src/xml/base.xml:1646 +msgid "Add" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_form.js:2721 +msgid "Add: " +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:8 +msgid "List" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:269 +msgid "Unlimited" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:305 +#, python-format +msgid "[%(first_record)d to %(last_record)d] of %(records_count)d" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:524 +msgid "Do you really want to remove these records?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:1230 +msgid "Undefined" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_list.js:1327 +#, python-format +msgid "%(page)d/%(page_count)d" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_page.js:8 +msgid "Page" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_page.js:52 +msgid "Do you really want to delete this record?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/view_tree.js:11 +msgid "Tree" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:565 addons/web/static/src/xml/base.xml:480 +msgid "Fields View Get" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:573 +#, python-format +msgid "View Log (%s)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:600 +#, python-format +msgid "Model %s fields" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:610 addons/web/static/src/xml/base.xml:482 +msgid "Manage Views" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:611 +msgid "Could not find current view declaration" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:805 +msgid "Translate" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:807 +msgid "Technical translation" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:811 +msgid "Other Options" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:814 +#: addons/web/static/src/xml/base.xml:1736 +msgid "Import" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:817 +#: addons/web/static/src/xml/base.xml:1606 +msgid "Export" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:825 +msgid "Reports" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:825 +msgid "Actions" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:825 +msgid "Links" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:919 +msgid "You must choose at least one record." +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:920 +msgid "Warning" +msgstr "" + +#. openerp-web +#: addons/web/static/src/js/views.js:957 +msgid "Translations" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:44 addons/web/static/src/xml/base.xml:315 +msgid "Powered by" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:44 addons/web/static/src/xml/base.xml:315 +#: addons/web/static/src/xml/base.xml:1813 +msgid "OpenERP" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:52 +msgid "Loading..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:61 +msgid "CREATE DATABASE" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:68 addons/web/static/src/xml/base.xml:211 +msgid "Master password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:72 addons/web/static/src/xml/base.xml:191 +msgid "New database name:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:77 +msgid "Load Demonstration data:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:81 +msgid "Default language:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:91 +msgid "Admin password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:95 +msgid "Confirm password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:109 +msgid "DROP DATABASE" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:116 +#: addons/web/static/src/xml/base.xml:150 +#: addons/web/static/src/xml/base.xml:301 +msgid "Database:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:128 +#: addons/web/static/src/xml/base.xml:162 +#: addons/web/static/src/xml/base.xml:187 +msgid "Master Password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:132 +#: addons/web/static/src/xml/base.xml:328 +msgid "Drop" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:143 +msgid "BACKUP DATABASE" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:166 +#: addons/web/static/src/xml/base.xml:329 +msgid "Backup" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:175 +msgid "RESTORE DATABASE" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:182 +msgid "File:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:195 +#: addons/web/static/src/xml/base.xml:330 +msgid "Restore" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:204 +msgid "CHANGE MASTER PASSWORD" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:216 +msgid "New master password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:221 +msgid "Confirm new master password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:251 +msgid "" +"Your version of OpenERP is unsupported. Support & maintenance services are " +"available here:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:251 +msgid "OpenERP Entreprise" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:256 +msgid "OpenERP Enterprise Contract." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:257 +msgid "Your report will be sent to the OpenERP Enterprise team." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:259 +msgid "Summary:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:263 +msgid "Description:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:267 +msgid "What you did:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:297 +msgid "Invalid username or password" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:306 +msgid "Username" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:308 +#: addons/web/static/src/xml/base.xml:331 +msgid "Password" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:310 +msgid "Log in" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:314 +msgid "Manage Databases" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:332 +msgid "Back to Login" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:353 +msgid "Home" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:363 +msgid "LOGOUT" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:388 +msgid "Fold menu" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:389 +msgid "Unfold menu" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:454 +msgid "Hide this tip" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:455 +msgid "Disable all tips" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:463 +msgid "Add / Remove Shortcut..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:471 +msgid "More…" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:477 +msgid "Debug View#" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:478 +msgid "View Log (perm_read)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:479 +msgid "View Fields" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:483 +msgid "View" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:484 +msgid "Edit SearchView" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:485 +msgid "Edit Action" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:486 +msgid "Edit Workflow" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:491 +msgid "ID:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:494 +msgid "XML ID:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:497 +msgid "Creation User:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:500 +msgid "Creation Date:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:503 +msgid "Latest Modification by:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:506 +msgid "Latest Modification Date:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:542 +msgid "Field" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:632 +#: addons/web/static/src/xml/base.xml:758 +#: addons/web/static/src/xml/base.xml:1708 +msgid "Delete" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:757 +msgid "Duplicate" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:775 +msgid "Add attachment" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:801 +msgid "Default:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:818 +msgid "Condition:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:837 +msgid "Only you" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:844 +msgid "All users" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:851 +msgid "Unhandled widget" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:900 +msgid "Notebook Page \"" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:905 +#: addons/web/static/src/xml/base.xml:964 +msgid "Modifiers:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:931 +msgid "(nolabel)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:936 +msgid "Field:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:940 +msgid "Object:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:944 +msgid "Type:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:948 +msgid "Widget:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:952 +msgid "Size:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:956 +msgid "Context:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:960 +msgid "Domain:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:968 +msgid "Change default:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:972 +msgid "On change:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:976 +msgid "Relation:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:980 +msgid "Selection:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1020 +msgid "Send an e-mail with your default e-mail client" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1034 +msgid "Open this resource" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1056 +msgid "Select date" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1090 +msgid "Open..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1091 +msgid "Create..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1092 +msgid "Search..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1095 +msgid "..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1155 +#: addons/web/static/src/xml/base.xml:1198 +msgid "Set Image" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1163 +#: addons/web/static/src/xml/base.xml:1213 +#: addons/web/static/src/xml/base.xml:1215 +#: addons/web/static/src/xml/base.xml:1272 +msgid "Clear" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1172 +#: addons/web/static/src/xml/base.xml:1223 +msgid "Uploading ..." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1200 +#: addons/web/static/src/xml/base.xml:1495 +msgid "Select" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1207 +#: addons/web/static/src/xml/base.xml:1209 +msgid "Save As" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1238 +msgid "Button" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1241 +msgid "(no string)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1248 +msgid "Special:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1253 +msgid "Button Type:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1257 +msgid "Method:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1261 +msgid "Action ID:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1271 +msgid "Search" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1279 +msgid "Filters" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1280 +msgid "-- Filters --" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1289 +msgid "-- Actions --" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1290 +msgid "Add Advanced Filter" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1291 +msgid "Save Filter" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1293 +msgid "Manage Filters" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1298 +msgid "Filter Name:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1300 +msgid "(Any existing filter with the same name will be replaced)" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1305 +msgid "Select Dashboard to add this filter to:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1309 +msgid "Title of new Dashboard item:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1416 +msgid "Advanced Filters" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1426 +msgid "Any of the following conditions must match" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1427 +msgid "All the following conditions must match" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1428 +msgid "None of the following conditions must match" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1435 +msgid "Add condition" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1436 +msgid "and" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1503 +msgid "Save & New" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1504 +msgid "Save & Close" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1611 +msgid "" +"This wizard will export all data that matches the current search criteria to " +"a CSV file.\n" +" You can export all data or only the fields that can be " +"reimported after modification." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1618 +msgid "Export Type:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1620 +msgid "Import Compatible Export" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1621 +msgid "Export all Data" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1624 +msgid "Export Formats" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1630 +msgid "Available fields" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1632 +msgid "Fields to export" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1634 +msgid "Save fields list" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1648 +msgid "Remove All" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1660 +msgid "Name" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1693 +msgid "Save as:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1700 +msgid "Saved exports:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1714 +msgid "Old Password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1719 +msgid "New Password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1724 +msgid "Confirm Password:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1742 +msgid "1. Import a .CSV file" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1743 +msgid "" +"Select a .CSV file to import. If you need a sample of file to import,\n" +" you should use the export tool with the \"Import Compatible\" option." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1747 +msgid "CSV File:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1750 +msgid "2. Check your file format" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1753 +msgid "Import Options" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1757 +msgid "Does your file have titles?" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1763 +msgid "Separator:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1765 +msgid "Delimiter:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1769 +msgid "Encoding:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1772 +msgid "UTF-8" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1773 +msgid "Latin 1" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1776 +msgid "Lines to skip" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1776 +msgid "" +"For use if CSV files have titles on multiple lines, skips more than a single " +"line during import" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1803 +msgid "The import failed due to:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1805 +msgid "Here is a preview of the file we could not import:" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1812 +msgid "Activate the developper mode" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1814 +msgid "Version" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1815 +msgid "Copyright © 2004-TODAY OpenERP SA. All Rights Reserved." +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1816 +msgid "OpenERP is a trademark of the" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1817 +msgid "OpenERP SA Company" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1819 +msgid "Licenced under the terms of" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1820 +msgid "GNU Affero General Public License" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1822 +msgid "For more information visit" +msgstr "" + +#. openerp-web +#: addons/web/static/src/xml/base.xml:1823 +msgid "OpenERP.com" +msgstr "" diff --git a/addons/web/i18n/zh_CN.po b/addons/web/i18n/zh_CN.po index f5e37f0442a..eb036a334d9 100644 --- a/addons/web/i18n/zh_CN.po +++ b/addons/web/i18n/zh_CN.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-14 15:27+0100\n" -"PO-Revision-Date: 2012-02-15 13:19+0000\n" -"Last-Translator: Wei \"oldrev\" Li \n" +"PO-Revision-Date: 2012-02-17 07:29+0000\n" +"Last-Translator: Jeff Wang \n" "Language-Team: Chinese (Simplified) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-16 05:21+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-18 05:18+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:172 @@ -654,7 +654,7 @@ msgstr "翻译" #. openerp-web #: addons/web/static/src/xml/base.xml:44 addons/web/static/src/xml/base.xml:315 msgid "Powered by" -msgstr "动力来自" +msgstr "选择自由,选择" #. openerp-web #: addons/web/static/src/xml/base.xml:44 addons/web/static/src/xml/base.xml:315 diff --git a/addons/web/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js b/addons/web/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js index 47f542e5d39..585bc072e56 100644 --- a/addons/web/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js +++ b/addons/web/static/lib/jquery.contextmenu/jquery.contextmenu.r2.packed.js @@ -1,3 +1,7 @@ +/* + Fork of some unlicensed library found somewhere, don't hesitate to + patch it directly. +*/ (function($) { var menu,shadow,trigger,content,hash,currentTarget; var defaults= { @@ -30,7 +34,7 @@ }; $.fn.contextMenu= function(id,options) { if(!menu) { - menu=$('
').hide().css({ + menu=$('
').hide().css({ position:'absolute', zIndex:'2000' }).appendTo('body').bind('click', function(e) { diff --git a/addons/web_mobile/static/openerp/mockup/jquery-1.5.1.js b/addons/web/static/lib/jquery/jquery-1.7.2b1.js old mode 100755 new mode 100644 similarity index 55% rename from addons/web_mobile/static/openerp/mockup/jquery-1.5.1.js rename to addons/web/static/lib/jquery/jquery-1.7.2b1.js index 78fcfa469b3..1797ea9e6ab --- a/addons/web_mobile/static/openerp/mockup/jquery-1.5.1.js +++ b/addons/web/static/lib/jquery/jquery-1.7.2b1.js @@ -1,5 +1,5 @@ /*! - * jQuery JavaScript Library v1.5.1 + * jQuery JavaScript Library v1.7.2b1 * http://jquery.com/ * * Copyright 2011, John Resig @@ -11,12 +11,14 @@ * Copyright 2011, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * - * Date: Wed Feb 23 13:55:29 2011 -0500 + * Date: Tue Jan 31 20:11:27 2012 -0500 */ (function( window, undefined ) { // Use the correct document accordingly with window argument (sandbox) -var document = window.document; +var document = window.document, + navigator = window.navigator, + location = window.location; var jQuery = (function() { // Define a local copy of jQuery @@ -35,8 +37,8 @@ var jQuery = function( selector, context ) { rootjQuery, // A simple way to check for HTML strings or ID strings - // (both of which we optimize for) - quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/, + // Prioritize #id over to avoid XSS via location.hash (#9521) + quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, // Check if a string has a non-whitespace character in it rnotwhite = /\S/, @@ -45,9 +47,6 @@ var jQuery = function( selector, context ) { trimLeft = /^\s+/, trimRight = /\s+$/, - // Check for digits - rdigit = /\d/, - // Match a standalone tag rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, @@ -63,21 +62,24 @@ var jQuery = function( selector, context ) { rmsie = /(msie) ([\w.]+)/, rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + // Matches dashed string for camelizing + rdashAlpha = /-([a-z]|[0-9])/ig, + rmsPrefix = /^-ms-/, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return ( letter + "" ).toUpperCase(); + }, + // Keep a UserAgent string for use with jQuery.browser userAgent = navigator.userAgent, // For matching the engine and version of the browser browserMatch, - // Has the ready events already been bound? - readyBound = false, - // The deferred used on DOM ready readyList, - // Promise methods - promiseMethods = "then done fail isResolved isRejected promise".split( " " ), - // The ready event handler DOMContentLoaded, @@ -113,7 +115,7 @@ jQuery.fn = jQuery.prototype = { if ( selector === "body" && !context && document.body ) { this.context = document; this[0] = document.body; - this.selector = "body"; + this.selector = selector; this.length = 1; return this; } @@ -121,7 +123,13 @@ jQuery.fn = jQuery.prototype = { // Handle HTML strings if ( typeof selector === "string" ) { // Are we dealing with HTML string or an ID? - match = quickExpr.exec( selector ); + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = quickExpr.exec( selector ); + } // Verify a match, and that no context was specified for #id if ( match && (match[1] || !context) ) { @@ -129,7 +137,7 @@ jQuery.fn = jQuery.prototype = { // HANDLE: $(html) -> $(array) if ( match[1] ) { context = context instanceof jQuery ? context[0] : context; - doc = (context ? context.ownerDocument || context : document); + doc = ( context ? context.ownerDocument || context : document ); // If a single string is passed in and it's a single tag // just do a createElement and skip the rest @@ -146,7 +154,7 @@ jQuery.fn = jQuery.prototype = { } else { ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); - selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes; + selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; } return jQuery.merge( this, selector ); @@ -176,7 +184,7 @@ jQuery.fn = jQuery.prototype = { // HANDLE: $(expr, $(...)) } else if ( !context || context.jquery ) { - return (context || rootjQuery).find( selector ); + return ( context || rootjQuery ).find( selector ); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) @@ -190,7 +198,7 @@ jQuery.fn = jQuery.prototype = { return rootjQuery.ready( selector ); } - if (selector.selector !== undefined) { + if ( selector.selector !== undefined ) { this.selector = selector.selector; this.context = selector.context; } @@ -202,7 +210,7 @@ jQuery.fn = jQuery.prototype = { selector: "", // The current version of jQuery being used - jquery: "1.5.1", + jquery: "1.7.2b1", // The default length of a jQuery object is 0 length: 0, @@ -247,7 +255,7 @@ jQuery.fn = jQuery.prototype = { ret.context = this.context; if ( name === "find" ) { - ret.selector = this.selector + (this.selector ? " " : "") + selector; + ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; } else if ( name ) { ret.selector = this.selector + "." + name + "(" + selector + ")"; } @@ -268,15 +276,16 @@ jQuery.fn = jQuery.prototype = { jQuery.bindReady(); // Add the callback - readyList.done( fn ); + readyList.add( fn ); return this; }, eq: function( i ) { + i = +i; return i === -1 ? this.slice( i ) : - this.slice( i, +i + 1 ); + this.slice( i, i + 1 ); }, first: function() { @@ -378,9 +387,11 @@ jQuery.extend = jQuery.fn.extend = function() { jQuery.extend({ noConflict: function( deep ) { - window.$ = _$; + if ( window.$ === jQuery ) { + window.$ = _$; + } - if ( deep ) { + if ( deep && window.jQuery === jQuery ) { window.jQuery = _jQuery; } @@ -394,15 +405,19 @@ jQuery.extend({ // the ready event fires. See #6781 readyWait: 1, + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + // Handle when the DOM is ready ready: function( wait ) { - // A third-party is pushing the ready event forwards - if ( wait === true ) { - jQuery.readyWait--; - } - - // Make sure that the DOM is not already loaded - if ( !jQuery.readyWait || (wait !== true && !jQuery.isReady) ) { + // Either a released hold or an DOMready/load event and not yet ready + if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( !document.body ) { return setTimeout( jQuery.ready, 1 ); @@ -417,21 +432,21 @@ jQuery.extend({ } // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); + readyList.fireWith( document, [ jQuery ] ); // Trigger any bound ready events if ( jQuery.fn.trigger ) { - jQuery( document ).trigger( "ready" ).unbind( "ready" ); + jQuery( document ).trigger( "ready" ).off( "ready" ); } } }, bindReady: function() { - if ( readyBound ) { + if ( readyList ) { return; } - readyBound = true; + readyList = jQuery.Callbacks( "once memory" ); // Catch cases where $(document).ready() is called after the // browser event has already occurred. @@ -452,7 +467,7 @@ jQuery.extend({ } else if ( document.attachEvent ) { // ensure firing before onload, // maybe late but safe also for iframes - document.attachEvent("onreadystatechange", DOMContentLoaded); + document.attachEvent( "onreadystatechange", DOMContentLoaded ); // A fallback to window.onload, that will always work window.attachEvent( "onload", jQuery.ready ); @@ -482,13 +497,12 @@ jQuery.extend({ return jQuery.type(obj) === "array"; }, - // A crude way of determining if an object is a window isWindow: function( obj ) { - return obj && typeof obj === "object" && "setInterval" in obj; + return obj != null && obj == obj.window; }, - isNaN: function( obj ) { - return obj == null || !rdigit.test( obj ) || isNaN( obj ); + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); }, type: function( obj ) { @@ -505,10 +519,15 @@ jQuery.extend({ return false; } - // Not own constructor property must be Object - if ( obj.constructor && - !hasOwn.call(obj, "constructor") && - !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + try { + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 return false; } @@ -529,7 +548,7 @@ jQuery.extend({ }, error: function( msg ) { - throw msg; + throw new Error( msg ); }, parseJSON: function( data ) { @@ -540,67 +559,66 @@ jQuery.extend({ // Make sure leading/trailing whitespace is removed (IE can't handle it) data = jQuery.trim( data ); + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + // Make sure the incoming data is actual JSON // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test(data.replace(rvalidescape, "@") - .replace(rvalidtokens, "]") - .replace(rvalidbraces, "")) ) { + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { - // Try to use the native JSON parser first - return window.JSON && window.JSON.parse ? - window.JSON.parse( data ) : - (new Function("return " + data))(); + return ( new Function( "return " + data ) )(); - } else { - jQuery.error( "Invalid JSON: " + data ); } + jQuery.error( "Invalid JSON: " + data ); }, // Cross-browser xml parsing - // (xml & tmp used internally) - parseXML: function( data , xml , tmp ) { - - if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); - xml.async = "false"; - xml.loadXML( data ); + parseXML: function( data ) { + var xml, tmp; + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; } - - tmp = xml.documentElement; - - if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) { + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { jQuery.error( "Invalid XML: " + data ); } - return xml; }, noop: function() {}, - // Evalulates a script in a global context + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context globalEval: function( data ) { - if ( data && rnotwhite.test(data) ) { - // Inspired by code by Andrea Giammarchi - // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html - var head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement, - script = document.createElement( "script" ); - - if ( jQuery.support.scriptEval() ) { - script.appendChild( document.createTextNode( data ) ); - } else { - script.text = data; - } - - // Use insertBefore instead of appendChild to circumvent an IE6 bug. - // This arises when a base node is used (#2709). - head.insertBefore( script, head.firstChild ); - head.removeChild( script ); + if ( data && rnotwhite.test( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); } }, + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + nodeName: function( elem, name ) { return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); }, @@ -609,7 +627,7 @@ jQuery.extend({ each: function( object, callback, args ) { var name, i = 0, length = object.length, - isObj = length === undefined || jQuery.isFunction(object); + isObj = length === undefined || jQuery.isFunction( object ); if ( args ) { if ( isObj ) { @@ -635,8 +653,11 @@ jQuery.extend({ } } } else { - for ( var value = object[0]; - i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} + for ( ; i < length; ) { + if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { + break; + } + } } } @@ -664,10 +685,8 @@ jQuery.extend({ if ( array != null ) { // The window, strings (and functions) also have 'length' - // The extra typeof function check is to prevent crashes - // in Safari 2 (See: #3039) // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 - var type = jQuery.type(array); + var type = jQuery.type( array ); if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { push.call( ret, array ); @@ -679,14 +698,22 @@ jQuery.extend({ return ret; }, - inArray: function( elem, array ) { - if ( array.indexOf ) { - return array.indexOf( elem ); - } + inArray: function( elem, array, i ) { + var len; - for ( var i = 0, length = array.length; i < length; i++ ) { - if ( array[ i ] === elem ) { - return i; + if ( array ) { + if ( indexOf ) { + return indexOf.call( array, elem, i ); + } + + len = array.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in array && array[ i ] === elem ) { + return i; + } } } @@ -731,15 +758,30 @@ jQuery.extend({ // arg is for internal usage only map: function( elems, callback, arg ) { - var ret = [], value; + var value, key, ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; // Go through the array, translating each of the items to their - // new value (or values). - for ( var i = 0, length = elems.length; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); - if ( value != null ) { - ret[ ret.length ] = value; + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } } } @@ -750,230 +792,88 @@ jQuery.extend({ // A global GUID counter for objects guid: 1, - proxy: function( fn, proxy, thisObject ) { - if ( arguments.length === 2 ) { - if ( typeof proxy === "string" ) { - thisObject = fn; - fn = thisObject[ proxy ]; - proxy = undefined; - - } else if ( proxy && !jQuery.isFunction( proxy ) ) { - thisObject = proxy; - proxy = undefined; - } + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + if ( typeof context === "string" ) { + var tmp = fn[ context ]; + context = fn; + fn = tmp; } - if ( !proxy && fn ) { + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + var args = slice.call( arguments, 2 ), proxy = function() { - return fn.apply( thisObject || this, arguments ); + return fn.apply( context, args.concat( slice.call( arguments ) ) ); }; - } // Set the guid of unique handler to the same of original handler, so it can be removed - if ( fn ) { - proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - } + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - // So proxy can be declared as an argument return proxy; }, // Mutifunctional method to get and set values to a collection - // The value/s can be optionally by executed if its a function - access: function( elems, key, value, exec, fn, pass ) { - var length = elems.length; + // The value/s can optionally be executed if it's a function + access: function( elems, fn, key, value, chainable, emptyGet, pass ) { + var exec, + bulk = key == null, + i = 0, + length = elems.length; - // Setting many attributes - if ( typeof key === "object" ) { - for ( var k in key ) { - jQuery.access( elems, k, key[k], exec, fn, value ); + // Sets many values + if ( key && typeof key === "object" ) { + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); } - return elems; - } + chainable = 1; - // Setting one attribute - if ( value !== undefined ) { + // Sets one value + } else if ( value !== undefined ) { // Optionally, function values get executed if exec is true - exec = !pass && exec && jQuery.isFunction(value); + exec = pass === undefined && jQuery.isFunction( value ); - for ( var i = 0; i < length; i++ ) { - fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + if ( bulk ) { + // Bulk operations only iterate when executing function values + if ( exec ) { + exec = fn; + fn = function( elem, key, value ) { + return exec.call( jQuery( elem ), value ); + }; + + // Otherwise they run against the entire set + } else { + fn.call( elems, value ); + fn = null; + } } - return elems; + if ( fn ) { + for (; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + } + + chainable = 1; } - // Getting an attribute - return length ? fn( elems[0], key ) : undefined; + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; }, now: function() { - return (new Date()).getTime(); - }, - - // Create a simple deferred (one callbacks list) - _Deferred: function() { - var // callbacks list - callbacks = [], - // stored [ context , args ] - fired, - // to avoid firing when already doing so - firing, - // flag to know if the deferred has been cancelled - cancelled, - // the deferred itself - deferred = { - - // done( f1, f2, ...) - done: function() { - if ( !cancelled ) { - var args = arguments, - i, - length, - elem, - type, - _fired; - if ( fired ) { - _fired = fired; - fired = 0; - } - for ( i = 0, length = args.length; i < length; i++ ) { - elem = args[ i ]; - type = jQuery.type( elem ); - if ( type === "array" ) { - deferred.done.apply( deferred, elem ); - } else if ( type === "function" ) { - callbacks.push( elem ); - } - } - if ( _fired ) { - deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] ); - } - } - return this; - }, - - // resolve with given context and args - resolveWith: function( context, args ) { - if ( !cancelled && !fired && !firing ) { - firing = 1; - try { - while( callbacks[ 0 ] ) { - callbacks.shift().apply( context, args ); - } - } - // We have to add a catch block for - // IE prior to 8 or else the finally - // block will never get executed - catch (e) { - throw e; - } - finally { - fired = [ context, args ]; - firing = 0; - } - } - return this; - }, - - // resolve with this as context and given arguments - resolve: function() { - deferred.resolveWith( jQuery.isFunction( this.promise ) ? this.promise() : this, arguments ); - return this; - }, - - // Has this deferred been resolved? - isResolved: function() { - return !!( firing || fired ); - }, - - // Cancel - cancel: function() { - cancelled = 1; - callbacks = []; - return this; - } - }; - - return deferred; - }, - - // Full fledged deferred (two callbacks list) - Deferred: function( func ) { - var deferred = jQuery._Deferred(), - failDeferred = jQuery._Deferred(), - promise; - // Add errorDeferred methods, then and promise - jQuery.extend( deferred, { - then: function( doneCallbacks, failCallbacks ) { - deferred.done( doneCallbacks ).fail( failCallbacks ); - return this; - }, - fail: failDeferred.done, - rejectWith: failDeferred.resolveWith, - reject: failDeferred.resolve, - isRejected: failDeferred.isResolved, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - if ( obj == null ) { - if ( promise ) { - return promise; - } - promise = obj = {}; - } - var i = promiseMethods.length; - while( i-- ) { - obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ]; - } - return obj; - } - } ); - // Make sure only one callback list will be used - deferred.done( failDeferred.cancel ).fail( deferred.cancel ); - // Unexpose cancel - delete deferred.cancel; - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - return deferred; - }, - - // Deferred helper - when: function( object ) { - var lastIndex = arguments.length, - deferred = lastIndex <= 1 && object && jQuery.isFunction( object.promise ) ? - object : - jQuery.Deferred(), - promise = deferred.promise(); - - if ( lastIndex > 1 ) { - var array = slice.call( arguments, 0 ), - count = lastIndex, - iCallback = function( index ) { - return function( value ) { - array[ index ] = arguments.length > 1 ? slice.call( arguments, 0 ) : value; - if ( !( --count ) ) { - deferred.resolveWith( promise, array ); - } - }; - }; - while( ( lastIndex-- ) ) { - object = array[ lastIndex ]; - if ( object && jQuery.isFunction( object.promise ) ) { - object.promise().then( iCallback(lastIndex), deferred.reject ); - } else { - --count; - } - } - if ( !count ) { - deferred.resolveWith( promise, array ); - } - } else if ( deferred !== object ) { - deferred.resolve( object ); - } - return promise; + return ( new Date() ).getTime(); }, // Use of jQuery.browser is frowned upon. @@ -991,32 +891,29 @@ jQuery.extend({ }, sub: function() { - function jQuerySubclass( selector, context ) { - return new jQuerySubclass.fn.init( selector, context ); + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); } - jQuery.extend( true, jQuerySubclass, this ); - jQuerySubclass.superclass = this; - jQuerySubclass.fn = jQuerySubclass.prototype = this(); - jQuerySubclass.fn.constructor = jQuerySubclass; - jQuerySubclass.subclass = this.subclass; - jQuerySubclass.fn.init = function init( selector, context ) { - if ( context && context instanceof jQuery && !(context instanceof jQuerySubclass) ) { - context = jQuerySubclass(context); + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); } - return jQuery.fn.init.call( this, selector, context, rootjQuerySubclass ); + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); }; - jQuerySubclass.fn.init.prototype = jQuerySubclass.fn; - var rootjQuerySubclass = jQuerySubclass(document); - return jQuerySubclass; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; }, browser: {} }); -// Create readyList deferred -readyList = jQuery._Deferred(); - // Populate the class2type map jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); @@ -1033,12 +930,6 @@ if ( jQuery.browser.webkit ) { jQuery.browser.safari = true; } -if ( indexOf ) { - jQuery.inArray = function( elem, array ) { - return indexOf.call( array, elem ); - }; -} - // IE doesn't match non-breaking spaces with \s if ( rnotwhite.test( "\xA0" ) ) { trimLeft = /^[\s\xA0]+/; @@ -1084,35 +975,423 @@ function doScrollCheck() { jQuery.ready(); } -// Expose jQuery to the global object return jQuery; })(); -(function() { +// String to Object flags format cache +var flagsCache = {}; - jQuery.support = {}; +// Convert String-formatted flags into Object-formatted ones and store in cache +function createFlags( flags ) { + var object = flagsCache[ flags ] = {}, + i, length; + flags = flags.split( /\s+/ ); + for ( i = 0, length = flags.length; i < length; i++ ) { + object[ flags[i] ] = true; + } + return object; +} - var div = document.createElement("div"); +/* + * Create a callback list using the following parameters: + * + * flags: an optional list of space-separated flags that will change how + * the callback list behaves + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible flags: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( flags ) { - div.style.display = "none"; - div.innerHTML = "
a"; + // Convert flags from String-formatted to Object-formatted + // (we check in cache first) + flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; - var all = div.getElementsByTagName("*"), - a = div.getElementsByTagName("a")[0], - select = document.createElement("select"), - opt = select.appendChild( document.createElement("option") ), - input = div.getElementsByTagName("input")[0]; + var // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = [], + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // Flag to know if list is currently firing + firing, + // First callback to fire (used internally by add and fireWith) + firingStart, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // Add one or several callbacks to the list + add = function( args ) { + var i, + length, + elem, + type, + actual; + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + // Inspect recursively + add( elem ); + } else if ( type === "function" ) { + // Add if not in unique mode and callback is not in + if ( !flags.unique || !self.has( elem ) ) { + list.push( elem ); + } + } + } + }, + // Fire callbacks + fire = function( context, args ) { + args = args || []; + memory = !flags.memory || [ context, args ]; + fired = true; + firing = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { + memory = true; // Mark as halted + break; + } + } + firing = false; + if ( list ) { + if ( !flags.once ) { + if ( stack && stack.length ) { + memory = stack.shift(); + self.fireWith( memory[ 0 ], memory[ 1 ] ); + } + } else if ( memory === true ) { + self.disable(); + } else { + list = []; + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + var length = list.length; + add( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away, unless previous + // firing was halted (stopOnFalse) + } else if ( memory && memory !== true ) { + firingStart = length; + fire( memory[ 0 ], memory[ 1 ] ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + var args = arguments, + argIndex = 0, + argLength = args.length; + for ( ; argIndex < argLength ; argIndex++ ) { + for ( var i = 0; i < list.length; i++ ) { + if ( args[ argIndex ] === list[ i ] ) { + // Handle firingIndex and firingLength + if ( firing ) { + if ( i <= firingLength ) { + firingLength--; + if ( i <= firingIndex ) { + firingIndex--; + } + } + } + // Remove the element + list.splice( i--, 1 ); + // If we have some unicity property then + // we only need to do this once + if ( flags.unique ) { + break; + } + } + } + } + } + return this; + }, + // Control if a given callback is in the list + has: function( fn ) { + if ( list ) { + var i = 0, + length = list.length; + for ( ; i < length; i++ ) { + if ( fn === list[ i ] ) { + return true; + } + } + } + return false; + }, + // Remove all callbacks from the list + empty: function() { + list = []; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory || memory === true ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( stack ) { + if ( firing ) { + if ( !flags.once ) { + stack.push( [ context, args ] ); + } + } else if ( !( flags.once && memory ) ) { + fire( context, args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + + + +var // Static reference to slice + sliceDeferred = [].slice; + +jQuery.extend({ + + Deferred: function( func ) { + var doneList = jQuery.Callbacks( "once memory" ), + failList = jQuery.Callbacks( "once memory" ), + progressList = jQuery.Callbacks( "memory" ), + state = "pending", + lists = { + resolve: doneList, + reject: failList, + notify: progressList + }, + promise = { + done: doneList.add, + fail: failList.add, + progress: progressList.add, + + state: function() { + return state; + }, + + // Deprecated + isResolved: doneList.fired, + isRejected: failList.fired, + + then: function( doneCallbacks, failCallbacks, progressCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); + return this; + }, + always: function() { + deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); + return this; + }, + pipe: function( fnDone, fnFail, fnProgress ) { + return jQuery.Deferred(function( newDefer ) { + jQuery.each( { + done: [ fnDone, "resolve" ], + fail: [ fnFail, "reject" ], + progress: [ fnProgress, "notify" ] + }, function( handler, data ) { + var fn = data[ 0 ], + action = data[ 1 ], + returned; + if ( jQuery.isFunction( fn ) ) { + deferred[ handler ](function() { + returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); + } + }); + } else { + deferred[ handler ]( newDefer[ action ] ); + } + }); + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + obj = promise; + } else { + for ( var key in promise ) { + obj[ key ] = promise[ key ]; + } + } + return obj; + } + }, + deferred = promise.promise({}), + key; + + for ( key in lists ) { + deferred[ key ] = lists[ key ].fire; + deferred[ key + "With" ] = lists[ key ].fireWith; + } + + // Handle state + deferred.done( function() { + state = "resolved"; + }, failList.disable, progressList.lock ).fail( function() { + state = "rejected"; + }, doneList.disable, progressList.lock ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( firstParam ) { + var args = sliceDeferred.call( arguments, 0 ), + i = 0, + length = args.length, + pValues = new Array( length ), + count = length, + pCount = length, + deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? + firstParam : + jQuery.Deferred(), + promise = deferred.promise(); + function resolveFunc( i ) { + return function( value ) { + args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + if ( !( --count ) ) { + deferred.resolveWith( deferred, args ); + } + }; + } + function progressFunc( i ) { + return function( value ) { + pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + deferred.notifyWith( promise, pValues ); + }; + } + if ( length > 1 ) { + for ( ; i < length; i++ ) { + if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { + args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( deferred, args ); + } + } else if ( deferred !== firstParam ) { + deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); + } + return promise; + } +}); + + + + +jQuery.support = (function() { + + var support, + all, + a, + select, + opt, + input, + marginDiv, + fragment, + tds, + events, + eventName, + i, + isSupported, + div = document.createElement( "div" ), + documentElement = document.documentElement; + + // Preliminary tests + div.setAttribute("className", "t"); + div.innerHTML = "
a"; + + all = div.getElementsByTagName( "*" ); + a = div.getElementsByTagName( "a" )[ 0 ]; // Can't get basic test support if ( !all || !all.length || !a ) { - return; + return {}; } - jQuery.support = { + // First batch of supports tests + select = document.createElement( "select" ); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName( "input" )[ 0 ]; + + support = { // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: div.firstChild.nodeType === 3, + leadingWhitespace: ( div.firstChild.nodeType === 3 ), // Make sure that tbody elements aren't automatically inserted // IE will insert them into empty tables @@ -1123,17 +1402,17 @@ return jQuery; htmlSerialize: !!div.getElementsByTagName("link").length, // Get the style information from getAttribute - // (IE uses .cssText insted) - style: /red/.test( a.getAttribute("style") ), + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), // Make sure that URLs aren't manipulated // (IE normalizes it by default) - hrefNormalized: a.getAttribute("href") === "/a", + hrefNormalized: ( a.getAttribute("href") === "/a" ), // Make sure that element opacity exists // (IE uses filter instead) // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.55$/.test( a.style.opacity ), + opacity: /^0.55/.test( a.style.opacity ), // Verify style float existence // (IE uses styleFloat instead of cssFloat) @@ -1142,124 +1421,152 @@ return jQuery; // Make sure that if no value is specified for a checkbox // that it defaults to "on". // (WebKit defaults to "" instead) - checkOn: input.value === "on", + checkOn: ( input.value === "on" ), // Make sure that a selected-by-default option has a working selected property. // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) optSelected: opt.selected, + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Tests for enctype support on a form(#6743) + enctype: !!document.createElement("form").enctype, + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, deleteExpando: true, - optDisabled: false, - checkClone: false, noCloneEvent: true, - noCloneChecked: true, - boxModel: null, inlineBlockNeedsLayout: false, shrinkWrapBlocks: false, - reliableHiddenOffsets: true + reliableMarginRight: true, + pixelMargin: true }; + // Make sure checked status is properly cloned input.checked = true; - jQuery.support.noCloneChecked = input.cloneNode( true ).checked; + support.noCloneChecked = input.cloneNode( true ).checked; // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as diabled) + // (WebKit marks them as disabled) select.disabled = true; - jQuery.support.optDisabled = !opt.disabled; - - var _scriptEval = null; - jQuery.support.scriptEval = function() { - if ( _scriptEval === null ) { - var root = document.documentElement, - script = document.createElement("script"), - id = "script" + jQuery.now(); - - try { - script.appendChild( document.createTextNode( "window." + id + "=1;" ) ); - } catch(e) {} - - root.insertBefore( script, root.firstChild ); - - // Make sure that the execution of code works by injecting a script - // tag with appendChild/createTextNode - // (IE doesn't support this, fails, and uses .text instead) - if ( window[ id ] ) { - _scriptEval = true; - delete window[ id ]; - } else { - _scriptEval = false; - } - - root.removeChild( script ); - // release memory in IE - root = script = id = null; - } - - return _scriptEval; - }; + support.optDisabled = !opt.disabled; // Test to see if it's possible to delete an expando from an element // Fails in Internet Explorer try { delete div.test; - - } catch(e) { - jQuery.support.deleteExpando = false; + } catch( e ) { + support.deleteExpando = false; } if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { - div.attachEvent("onclick", function click() { + div.attachEvent( "onclick", function() { // Cloning a node shouldn't copy over any // bound event handlers (IE does this) - jQuery.support.noCloneEvent = false; - div.detachEvent("onclick", click); + support.noCloneEvent = false; }); - div.cloneNode(true).fireEvent("onclick"); + div.cloneNode( true ).fireEvent( "onclick" ); } - div = document.createElement("div"); - div.innerHTML = ""; + // Check if a radio maintains its value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute("type", "radio"); + support.radioValue = input.value === "t"; - var fragment = document.createDocumentFragment(); - fragment.appendChild( div.firstChild ); + input.setAttribute("checked", "checked"); + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.lastChild ); // WebKit doesn't clone checked state correctly in fragments - jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked; + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; - // Figure out if the W3C box model works as expected - // document.body must exist before we can do this + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + fragment.removeChild( input ); + fragment.appendChild( div ); + + div.innerHTML = ""; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + if ( window.getComputedStyle ) { + marginDiv = document.createElement( "div" ); + marginDiv.style.width = "0"; + marginDiv.style.marginRight = "0"; + div.style.width = "2px"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; + } + + // Technique from Juriy Zaytsev + // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for ( i in { + submit: 1, + change: 1, + focusin: 1 + }) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } + + fragment.removeChild( div ); + + // Null elements to avoid leaks in IE + fragment = select = opt = marginDiv = div = input = null; + + // Run tests that need a body at doc ready jQuery(function() { - var div = document.createElement("div"), + var container, outer, inner, table, td, offsetSupport, + conMarginTop, ptlm, vb, style, html, body = document.getElementsByTagName("body")[0]; - // Frameset documents with no body should not run this code if ( !body ) { + // Return for frameset docs that don't have a body return; } - div.style.width = div.style.paddingLeft = "1px"; - body.appendChild( div ); - jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2; + conMarginTop = 1; + ptlm = "position:absolute;top:0;left:0;width:1px;height:1px;margin:0;"; + vb = "visibility:hidden;border:0;"; + style = "style='" + ptlm + "border:5px solid #000;padding:0;'"; + html = "
" + + "" + + "
"; - if ( "zoom" in div.style ) { - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - // (IE < 8 does this) - div.style.display = "inline"; - div.style.zoom = 1; - jQuery.support.inlineBlockNeedsLayout = div.offsetWidth === 2; + container = document.createElement("div"); + container.style.cssText = vb + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px"; + body.insertBefore( container, body.firstChild ); - // Check if elements with layout shrink-wrap their children - // (IE 6 does this) - div.style.display = ""; - div.innerHTML = "
"; - jQuery.support.shrinkWrapBlocks = div.offsetWidth !== 2; - } - - div.innerHTML = "
t
"; - var tds = div.getElementsByTagName("td"); + // Construct the test element + div = document.createElement("div"); + container.appendChild( div ); // Check if table cells still have offsetWidth/Height when they are set // to display:none and there are still other visible table cells in a @@ -1268,54 +1575,87 @@ return jQuery; // display:none (it is still safe to use offsets if a parent element is // hidden; don safety goggles and see bug #4512 for more information). // (only IE 8 fails this test) - jQuery.support.reliableHiddenOffsets = tds[0].offsetHeight === 0; + div.innerHTML = "
t
"; - tds[0].style.display = ""; - tds[1].style.display = "none"; + tds = div.getElementsByTagName( "td" ); + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; // Check if empty table cells still have offsetWidth/Height - // (IE < 8 fail this test) - jQuery.support.reliableHiddenOffsets = jQuery.support.reliableHiddenOffsets && tds[0].offsetHeight === 0; - div.innerHTML = ""; + // (IE <= 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); - body.removeChild( div ).style.display = "none"; - div = tds = null; + // Figure out if the W3C box model works as expected + div.innerHTML = ""; + div.style.width = div.style.paddingLeft = "1px"; + jQuery.boxModel = support.boxModel = div.offsetWidth === 2; + + if ( typeof div.style.zoom !== "undefined" ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.style.display = "inline"; + div.style.zoom = 1; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = ""; + div.innerHTML = "
"; + support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); + } + + div.style.cssText = ptlm + vb; + div.innerHTML = html; + + outer = div.firstChild; + inner = outer.firstChild; + td = outer.nextSibling.firstChild.firstChild; + + offsetSupport = { + doesNotAddBorder: ( inner.offsetTop !== 5 ), + doesAddBorderForTableAndCells: ( td.offsetTop === 5 ) + }; + + inner.style.position = "fixed"; + inner.style.top = "20px"; + + // safari subtracts parent border width here which is 5px + offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 ); + inner.style.position = inner.style.top = ""; + + outer.style.overflow = "hidden"; + outer.style.position = "relative"; + + offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 ); + offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop ); + + if ( window.getComputedStyle ) { + div.style.marginTop = "1%"; + support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%"; + } + + if ( typeof container.style.zoom !== "undefined" ) { + container.style.zoom = 1; + } + + body.removeChild( container ); + div = container = null; + + jQuery.extend( support, offsetSupport ); }); - // Technique from Juriy Zaytsev - // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ - var eventSupported = function( eventName ) { - var el = document.createElement("div"); - eventName = "on" + eventName; - - // We only care about the case where non-standard event systems - // are used, namely in IE. Short-circuiting here helps us to - // avoid an eval call (in setAttribute) which can cause CSP - // to go haywire. See: https://developer.mozilla.org/en/Security/CSP - if ( !el.attachEvent ) { - return true; - } - - var isSupported = (eventName in el); - if ( !isSupported ) { - el.setAttribute(eventName, "return;"); - isSupported = typeof el[eventName] === "function"; - } - el = null; - - return isSupported; - }; - - jQuery.support.submitBubbles = eventSupported("submit"); - jQuery.support.changeBubbles = eventSupported("change"); - - // release memory in IE - div = all = a = null; + return support; })(); -var rbrace = /^(?:\{.*\}|\[.*\])$/; + +var rbrace = /^(?:\{.*\}|\[.*\])$/, + rmultiDash = /([A-Z])/g; jQuery.extend({ cache: {}, @@ -1338,7 +1678,6 @@ jQuery.extend({ hasData: function( elem ) { elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); }, @@ -1347,7 +1686,9 @@ jQuery.extend({ return; } - var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache, + var privateCache, thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", // We have to handle DOM nodes and JS objects differently because IE6-7 // can't GC object references properly across the DOM-JS boundary @@ -1359,11 +1700,12 @@ jQuery.extend({ // Only defining an ID for JS objects if its cache already exists allows // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando; + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey, + isEvents = name === "events"; // Avoid doing any more work than we need to when trying to get data on an // object that has no data at all - if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) { + if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { return; } @@ -1371,18 +1713,17 @@ jQuery.extend({ // Only DOM nodes need a new unique ID for each element since their data // ends up in the global cache if ( isNode ) { - elem[ jQuery.expando ] = id = ++jQuery.uuid; + elem[ internalKey ] = id = ++jQuery.uuid; } else { - id = jQuery.expando; + id = internalKey; } } if ( !cache[ id ] ) { cache[ id ] = {}; - // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery - // metadata on plain JS objects when the object is serialized using - // JSON.stringify + // Avoids exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify if ( !isNode ) { cache[ id ].toJSON = jQuery.noop; } @@ -1392,37 +1733,53 @@ jQuery.extend({ // shallow copied over onto the existing cache if ( typeof name === "object" || typeof name === "function" ) { if ( pvt ) { - cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name); + cache[ id ] = jQuery.extend( cache[ id ], name ); } else { - cache[ id ] = jQuery.extend(cache[ id ], name); + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); } } - thisCache = cache[ id ]; + privateCache = thisCache = cache[ id ]; - // Internal jQuery data is stored in a separate object inside the object's data + // jQuery data() is stored in a separate object inside the object's internal data // cache in order to avoid key collisions between internal data and user-defined - // data - if ( pvt ) { - if ( !thisCache[ internalKey ] ) { - thisCache[ internalKey ] = {}; + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; } - thisCache = thisCache[ internalKey ]; + thisCache = thisCache.data; } if ( data !== undefined ) { - thisCache[ name ] = data; + thisCache[ jQuery.camelCase( name ) ] = data; } - // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should - // not attempt to inspect the internal events object using jQuery.data, as this - // internal data object is undocumented and subject to change. - if ( name === "events" && !thisCache[name] ) { - return thisCache[ internalKey ] && thisCache[ internalKey ].events; + // Users should not attempt to inspect the internal events object using jQuery.data, + // it is undocumented and subject to change. But does anyone listen? No. + if ( isEvents && !thisCache[ name ] ) { + return privateCache.events; } - return getByName ? thisCache[ name ] : thisCache; + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; }, removeData: function( elem, name, pvt /* Internal Use Only */ ) { @@ -1430,13 +1787,18 @@ jQuery.extend({ return; } - var internalKey = jQuery.expando, isNode = elem.nodeType, + var thisCache, i, l, + + // Reference to internal data cache key + internalKey = jQuery.expando, + + isNode = elem.nodeType, // See jQuery.data for more information cache = isNode ? jQuery.cache : elem, // See jQuery.data for more information - id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + id = isNode ? elem[ internalKey ] : internalKey; // If there is already no cache entry for this object, there is no // purpose in continuing @@ -1445,22 +1807,44 @@ jQuery.extend({ } if ( name ) { - var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ]; + + thisCache = pvt ? cache[ id ] : cache[ id ].data; if ( thisCache ) { - delete thisCache[ name ]; + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split( " " ); + } + } + } + + for ( i = 0, l = name.length; i < l; i++ ) { + delete thisCache[ name[i] ]; + } // If there is no data left in the cache, we want to continue // and let the cache object itself get destroyed - if ( !isEmptyDataObject(thisCache) ) { + if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { return; } } } // See jQuery.data for more information - if ( pvt ) { - delete cache[ id ][ internalKey ]; + if ( !pvt ) { + delete cache[ id ].data; // Don't destroy the parent cache unless the internal data object // had been the only thing left in it @@ -1469,43 +1853,28 @@ jQuery.extend({ } } - var internalCache = cache[ id ][ internalKey ]; - // Browsers that fail expando deletion also refuse to delete expandos on // the window, but it will allow it on all other JS objects; other browsers // don't care - if ( jQuery.support.deleteExpando || cache != window ) { + // Ensure that `cache` is not a window object #10080 + if ( jQuery.support.deleteExpando || !cache.setInterval ) { delete cache[ id ]; } else { cache[ id ] = null; } - // We destroyed the entire user cache at once because it's faster than - // iterating through each key, but we need to continue to persist internal - // data if it existed - if ( internalCache ) { - cache[ id ] = {}; - // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery - // metadata on plain JS objects when the object is serialized using - // JSON.stringify - if ( !isNode ) { - cache[ id ].toJSON = jQuery.noop; - } - - cache[ id ][ internalKey ] = internalCache; - - // Otherwise, we need to eliminate the expando on the node to avoid + // We destroyed the cache and need to eliminate the expando on the node to avoid // false lookups in the cache for entries that no longer exist - } else if ( isNode ) { + if ( isNode ) { // IE does not allow us to delete expando properties from nodes, // nor does it have a removeAttribute function on Document nodes; // we must handle all of these cases if ( jQuery.support.deleteExpando ) { - delete elem[ jQuery.expando ]; + delete elem[ internalKey ]; } else if ( elem.removeAttribute ) { - elem.removeAttribute( jQuery.expando ); + elem.removeAttribute( internalKey ); } else { - elem[ jQuery.expando ] = null; + elem[ internalKey ] = null; } } }, @@ -1531,59 +1900,70 @@ jQuery.extend({ jQuery.fn.extend({ data: function( key, value ) { - var data = null; + var parts, part, attr, name, l, + elem = this[0], + i = 0, + data = null; - if ( typeof key === "undefined" ) { + // Gets all values + if ( key === undefined ) { if ( this.length ) { - data = jQuery.data( this[0] ); + data = jQuery.data( elem ); - if ( this[0].nodeType === 1 ) { - var attr = this[0].attributes, name; - for ( var i = 0, l = attr.length; i < l; i++ ) { + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + attr = elem.attributes; + for ( l = attr.length; i < l; i++ ) { name = attr[i].name; if ( name.indexOf( "data-" ) === 0 ) { - name = name.substr( 5 ); - dataAttr( this[0], name, data[ name ] ); + name = jQuery.camelCase( name.substring(5) ); + + dataAttr( elem, name, data[ name ] ); } } + jQuery._data( elem, "parsedAttrs", true ); } } return data; + } - } else if ( typeof key === "object" ) { + // Sets multiple values + if ( typeof key === "object" ) { return this.each(function() { jQuery.data( this, key ); }); } - var parts = key.split("."); + parts = key.split( ".", 2 ); parts[1] = parts[1] ? "." + parts[1] : ""; + part = parts[1] + "!"; - if ( value === undefined ) { - data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + return jQuery.access( this, function( value ) { - // Try to fetch any internally stored data first - if ( data === undefined && this.length ) { - data = jQuery.data( this[0], key ); - data = dataAttr( this[0], key, data ); + if ( value === undefined ) { + data = this.triggerHandler( "getData" + part, [ parts[0] ] ); + + // Try to fetch any internally stored data first + if ( data === undefined && elem ) { + data = jQuery.data( elem, key ); + data = dataAttr( elem, key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; } - return data === undefined && parts[1] ? - this.data( parts[0] ) : - data; + parts[1] = value; + this.each(function() { + var self = jQuery( this ); - } else { - return this.each(function() { - var $this = jQuery( this ), - args = [ parts[0], value ]; - - $this.triggerHandler( "setData" + parts[1] + "!", args ); + self.triggerHandler( "setData" + part, parts ); jQuery.data( this, key, value ); - $this.triggerHandler( "changeData" + parts[1] + "!", args ); + self.triggerHandler( "changeData" + part, parts ); }); - } + }, null, value, arguments.length > 1, null, false ); }, removeData: function( key ) { @@ -1597,14 +1977,17 @@ function dataAttr( elem, key, data ) { // If nothing was found internally, try to fetch any // data from the HTML5 data-* attribute if ( data === undefined && elem.nodeType === 1 ) { - data = elem.getAttribute( "data-" + key ); + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); if ( typeof data === "string" ) { try { data = data === "true" ? true : data === "false" ? false : data === "null" ? null : - !jQuery.isNaN( data ) ? parseFloat( data ) : + jQuery.isNumeric( data ) ? parseFloat( data ) : rbrace.test( data ) ? jQuery.parseJSON( data ) : data; } catch( e ) {} @@ -1620,11 +2003,14 @@ function dataAttr( elem, key, data ) { return data; } -// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON -// property to be considered empty objects; this property always exists in -// order to make sure JSON.stringify does not expose internal metadata +// checks a cache object for emptiness function isEmptyDataObject( obj ) { for ( var name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } if ( name !== "toJSON" ) { return false; } @@ -1636,35 +2022,78 @@ function isEmptyDataObject( obj ) { +function handleQueueMarkDefer( elem, type, src ) { + var deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + defer = jQuery._data( elem, deferDataKey ); + if ( defer && + ( src === "queue" || !jQuery._data(elem, queueDataKey) ) && + ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) { + // Give room for hard-coded callbacks to fire first + // and eventually mark/queue something else on the element + setTimeout( function() { + if ( !jQuery._data( elem, queueDataKey ) && + !jQuery._data( elem, markDataKey ) ) { + jQuery.removeData( elem, deferDataKey, true ); + defer.fire(); + } + }, 0 ); + } +} + jQuery.extend({ - queue: function( elem, type, data ) { - if ( !elem ) { - return; + + _mark: function( elem, type ) { + if ( elem ) { + type = ( type || "fx" ) + "mark"; + jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 ); } + }, - type = (type || "fx") + "queue"; - var q = jQuery._data( elem, type ); + _unmark: function( force, elem, type ) { + if ( force !== true ) { + type = elem; + elem = force; + force = false; + } + if ( elem ) { + type = type || "fx"; + var key = type + "mark", + count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 ); + if ( count ) { + jQuery._data( elem, key, count ); + } else { + jQuery.removeData( elem, key, true ); + handleQueueMarkDefer( elem, type, "mark" ); + } + } + }, - // Speed up dequeue by getting out quickly if this is just a lookup - if ( !data ) { + queue: function( elem, type, data ) { + var q; + if ( elem ) { + type = ( type || "fx" ) + "queue"; + q = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !q || jQuery.isArray(data) ) { + q = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + q.push( data ); + } + } return q || []; } - - if ( !q || jQuery.isArray(data) ) { - q = jQuery._data( elem, type, jQuery.makeArray(data) ); - - } else { - q.push( data ); - } - - return q; }, dequeue: function( elem, type ) { type = type || "fx"; var queue = jQuery.queue( elem, type ), - fn = queue.shift(); + fn = queue.shift(), + hooks = {}; // If the fx queue is dequeued, always remove the progress sentinel if ( fn === "inprogress" ) { @@ -1675,60 +2104,99 @@ jQuery.extend({ // Add a progress sentinel to prevent the fx queue from being // automatically dequeued if ( type === "fx" ) { - queue.unshift("inprogress"); + queue.unshift( "inprogress" ); } - fn.call(elem, function() { - jQuery.dequeue(elem, type); - }); + jQuery._data( elem, type + ".run", hooks ); + fn.call( elem, function() { + jQuery.dequeue( elem, type ); + }, hooks ); } if ( !queue.length ) { - jQuery.removeData( elem, type + "queue", true ); + jQuery.removeData( elem, type + "queue " + type + ".run", true ); + handleQueueMarkDefer( elem, type, "queue" ); } } }); jQuery.fn.extend({ queue: function( type, data ) { + var setter = 2; + if ( typeof type !== "string" ) { data = type; type = "fx"; + setter--; } - if ( data === undefined ) { + if ( arguments.length < setter ) { return jQuery.queue( this[0], type ); } - return this.each(function( i ) { - var queue = jQuery.queue( this, type, data ); - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); }, dequeue: function( type ) { return this.each(function() { jQuery.dequeue( this, type ); }); }, - // Based off of the plugin by Clint Helfers, with permission. // http://blindsignals.com/index.php/2009/07/jquery-delay/ delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; type = type || "fx"; - return this.queue( type, function() { - var elem = this; - setTimeout(function() { - jQuery.dequeue( elem, type ); - }, time ); + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; }); }, - clearQueue: function( type ) { return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, object ) { + if ( typeof type !== "string" ) { + object = type; + type = undefined; + } + type = type || "fx"; + var defer = jQuery.Deferred(), + elements = this, + i = elements.length, + count = 1, + deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + tmp; + function resolve() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + } + while( i-- ) { + if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || + ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || + jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && + jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) { + count++; + tmp.add( resolve ); + } + } + resolve(); + return defer.promise(); } }); @@ -1736,66 +2204,67 @@ jQuery.fn.extend({ var rclass = /[\n\t\r]/g, - rspaces = /\s+/, + rspace = /\s+/, rreturn = /\r/g, - rspecialurl = /^(?:href|src|style)$/, rtype = /^(?:button|input)$/i, rfocusable = /^(?:button|input|object|select|textarea)$/i, rclickable = /^a(?:rea)?$/i, - rradiocheck = /^(?:radio|checkbox)$/i; - -jQuery.props = { - "for": "htmlFor", - "class": "className", - readonly: "readOnly", - maxlength: "maxLength", - cellspacing: "cellSpacing", - rowspan: "rowSpan", - colspan: "colSpan", - tabindex: "tabIndex", - usemap: "useMap", - frameborder: "frameBorder" -}; + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute, + nodeHook, boolHook, fixSpecified; jQuery.fn.extend({ attr: function( name, value ) { - return jQuery.access( this, name, value, true, jQuery.attr ); + return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); }, - removeAttr: function( name, fn ) { - return this.each(function(){ - jQuery.attr( this, name, "" ); - if ( this.nodeType === 1 ) { - this.removeAttribute( name ); - } + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} }); }, addClass: function( value ) { - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - self.addClass( value.call(this, i, self.attr("class")) ); + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); }); } if ( value && typeof value === "string" ) { - var classNames = (value || "").split( rspaces ); + classNames = value.split( rspace ); - for ( var i = 0, l = this.length; i < l; i++ ) { - var elem = this[i]; + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; if ( elem.nodeType === 1 ) { - if ( !elem.className ) { + if ( !elem.className && classNames.length === 1 ) { elem.className = value; } else { - var className = " " + elem.className + " ", - setClass = elem.className; + setClass = " " + elem.className + " "; - for ( var c = 0, cl = classNames.length; c < cl; c++ ) { - if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) { - setClass += " " + classNames[c]; + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { + setClass += classNames[ c ] + " "; } } elem.className = jQuery.trim( setClass ); @@ -1808,24 +2277,25 @@ jQuery.fn.extend({ }, removeClass: function( value ) { - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - self.removeClass( value.call(this, i, self.attr("class")) ); + var classNames, i, l, elem, className, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); }); } if ( (value && typeof value === "string") || value === undefined ) { - var classNames = (value || "").split( rspaces ); + classNames = ( value || "" ).split( rspace ); - for ( var i = 0, l = this.length; i < l; i++ ) { - var elem = this[i]; + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; if ( elem.nodeType === 1 && elem.className ) { if ( value ) { - var className = (" " + elem.className + " ").replace(rclass, " "); - for ( var c = 0, cl = classNames.length; c < cl; c++ ) { - className = className.replace(" " + classNames[c] + " ", " "); + className = (" " + elem.className + " ").replace( rclass, " " ); + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[ c ] + " ", " "); } elem.className = jQuery.trim( className ); @@ -1844,9 +2314,8 @@ jQuery.fn.extend({ isBool = typeof stateVal === "boolean"; if ( jQuery.isFunction( value ) ) { - return this.each(function(i) { - var self = jQuery(this); - self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal ); + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); }); } @@ -1857,7 +2326,7 @@ jQuery.fn.extend({ i = 0, self = jQuery( this ), state = stateVal, - classNames = value.split( rspaces ); + classNames = value.split( rspace ); while ( (className = classNames[ i++ ]) ) { // check each className given, space seperated list @@ -1878,9 +2347,11 @@ jQuery.fn.extend({ }, hasClass: function( selector ) { - var className = " " + selector + " "; - for ( var i = 0, l = this.length; i < l; i++ ) { - if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { return true; } } @@ -1889,82 +2360,42 @@ jQuery.fn.extend({ }, val: function( value ) { + var hooks, ret, isFunction, + elem = this[0]; + if ( !arguments.length ) { - var elem = this[0]; - if ( elem ) { - if ( jQuery.nodeName( elem, "option" ) ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; + hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; } - // We need to handle select boxes special - if ( jQuery.nodeName( elem, "select" ) ) { - var index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { - var option = options[ i ]; - - // Don't return options that are disabled or in a disabled optgroup - if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && - (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { - - // Get the specific value for the option - value = jQuery(option).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - // Fixes Bug #2551 -- select.val() broken in IE after form.reset() - if ( one && !values.length && options.length ) { - return jQuery( options[ index ] ).val(); - } - - return values; - } - - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) { - return elem.getAttribute("value") === null ? "on" : elem.value; - } - - // Everything else, we just grab the value - return (elem.value || "").replace(rreturn, ""); + ret = elem.value; + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; } - return undefined; + return; } - var isFunction = jQuery.isFunction(value); + isFunction = jQuery.isFunction( value ); - return this.each(function(i) { - var self = jQuery(this), val = value; + return this.each(function( i ) { + var self = jQuery(this), val; if ( this.nodeType !== 1 ) { return; } if ( isFunction ) { - val = value.call(this, i, self.val()); + val = value.call( this, i, self.val() ); + } else { + val = value; } // Treat null/undefined as ""; convert numbers to string @@ -1972,27 +2403,16 @@ jQuery.fn.extend({ val = ""; } else if ( typeof val === "number" ) { val += ""; - } else if ( jQuery.isArray(val) ) { - val = jQuery.map(val, function (value) { + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { return value == null ? "" : value + ""; }); } - if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) { - this.checked = jQuery.inArray( self.val(), val ) >= 0; + hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; - } else if ( jQuery.nodeName( this, "select" ) ) { - var values = jQuery.makeArray(val); - - jQuery( "option", this ).each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - this.selectedIndex = -1; - } - - } else { + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { this.value = val; } }); @@ -2000,6 +2420,74 @@ jQuery.fn.extend({ }); jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, i, max, option, + index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + i = one ? index : 0; + max = one ? index + 1 : options.length; + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + attrFn: { val: true, css: true, @@ -2012,239 +2500,474 @@ jQuery.extend({ }, attr: function( elem, name, value, pass ) { + var ret, hooks, notxml, + nType = elem.nodeType; + // don't get/set attributes on text, comment and attribute nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || elem.nodeType === 2 ) { - return undefined; + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; } if ( pass && name in jQuery.attrFn ) { - return jQuery(elem)[name](value); + return jQuery( elem )[ name ]( value ); } - var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), - // Whether we are setting (or getting) - set = value !== undefined; + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } - // Try to normalize/fix the name - name = notxml && jQuery.props[ name ] || name; + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - // Only do all the following if this is a node (faster for style) - if ( elem.nodeType === 1 ) { - // These attributes require special treatment - var special = rspecialurl.test( name ); + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( notxml ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); + } - // Safari mis-reports the default selected property of an option - // Accessing the parent's selectedIndex property fixes it - if ( name === "selected" && !jQuery.support.optSelected ) { - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; + if ( value !== undefined ) { - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; - // If applicable, access the attribute via the DOM 0 way - // 'in' checks fail in Blackberry 4.7 #6931 - if ( (name in elem || elem[ name ] !== undefined) && notxml && !special ) { - if ( set ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; - if ( value === null ) { - if ( elem.nodeType === 1 ) { - elem.removeAttribute( name ); - } - - } else { - elem[ name ] = value; - } - } - - // browsers index elements by id/name on forms, give priority to attributes. - if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { - return elem.getAttributeNode( name ).nodeValue; - } - - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - if ( name === "tabIndex" ) { - var attributeNode = elem.getAttributeNode( "tabIndex" ); - - return attributeNode && attributeNode.specified ? - attributeNode.value : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - - return elem[ name ]; - } - - if ( !jQuery.support.style && notxml && name === "style" ) { - if ( set ) { - elem.style.cssText = "" + value; - } - - return elem.style.cssText; - } - - if ( set ) { - // convert the value to a string (all browsers do this but IE) see #1070 + } else { elem.setAttribute( name, "" + value ); + return value; } - // Ensure that missing attributes return undefined - // Blackberry 4.7 returns "" from getAttribute #6938 - if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) { - return undefined; - } + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; - var attr = !jQuery.support.hrefNormalized && notxml && special ? - // Some attributes require a special call on IE - elem.getAttribute( name, 2 ) : - elem.getAttribute( name ); + } else { + + ret = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined - return attr === null ? undefined : attr; + return ret === null ? + undefined : + ret; } - // Handle everything which isn't a DOM element node - if ( set ) { - elem[ name ] = value; + }, + + removeAttr: function( elem, value ) { + var propName, attrNames, name, l, + i = 0; + + if ( value && elem.nodeType === 1 ) { + attrNames = value.toLowerCase().split( rspace ); + l = attrNames.length; + + for ( ; i < l; i++ ) { + name = attrNames[ i ]; + + if ( name ) { + propName = jQuery.propFix[ name ] || name; + + // See #9699 for explanation of this approach (setting first, then removal) + jQuery.attr( elem, name, "" ); + elem.removeAttribute( getSetAttribute ? name : propName ); + + // Set corresponding property to false for boolean attributes + if ( rboolean.test( name ) && propName in elem ) { + elem[ propName ] = false; + } + } + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + // Use the value property for back compat + // Use the nodeHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return ( elem[ name ] = value ); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } } - return elem[ name ]; } }); +// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional) +jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex; + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + // Fall back to attribute presence where some booleans are not supported + var attrNode, + property = jQuery.prop( elem, name ); + return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + fixSpecified = { + name: true, + id: true + }; + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ? + ret.nodeValue : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + ret = document.createAttribute( name ); + elem.setAttributeNode( ret ); + } + return ( ret.nodeValue = value + "" ); + } + }; + + // Apply the nodeHook to tabindex + jQuery.attrHooks.tabindex.set = nodeHook.set; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + get: nodeHook.get, + set: function( elem, value, name ) { + if ( value === "" ) { + value = "false"; + } + nodeHook.set( elem, value, name ); + } + }; +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = "" + value ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }); +}); + -var rnamespaces = /\.(.*)$/, - rformElems = /^(?:textarea|input|select)$/i, - rperiod = /\./g, - rspace = / /g, - rescape = /[^\w\s.|`]/g, - fcleanup = function( nm ) { - return nm.replace(rescape, "\\$&"); +var rformElems = /^(?:textarea|input|select)$/i, + rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, + rhoverHack = /(?:^|\s)hover(\.\S+)?\b/, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/, + quickParse = function( selector ) { + var quick = rquickIs.exec( selector ); + if ( quick ) { + // 0 1 2 3 + // [ _, tag, id, class ] + quick[1] = ( quick[1] || "" ).toLowerCase(); + quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" ); + } + return quick; + }, + quickIs = function( elem, m ) { + var attrs = elem.attributes || {}; + return ( + (!m[1] || elem.nodeName.toLowerCase() === m[1]) && + (!m[2] || (attrs.id || {}).value === m[2]) && + (!m[3] || m[3].test( (attrs[ "class" ] || {}).value )) + ); + }, + hoverHack = function( events ) { + return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); }; /* - * A number of helper functions used for managing events. - * Many of the ideas behind this code originated from - * Dean Edwards' addEvent library. + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. */ jQuery.event = { - // Bind an event to an element - // Original by Dean Edwards - add: function( elem, types, handler, data ) { - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + add: function( elem, types, handler, data, selector ) { + + var elemData, eventHandle, events, + t, tns, type, namespaces, handleObj, + handleObjIn, quick, handlers, special; + + // Don't attach events to noData or text/comment nodes (allow plain objects tho) + if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { return; } - // TODO :: Use a try/catch until it's safe to pull this out (likely 1.6) - // Minor release fix for bug #8018 - try { - // For whatever reason, IE has trouble passing the window object - // around, causing it to be cloned in the process - if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) { - elem = window; - } - } - catch ( e ) {} - - if ( handler === false ) { - handler = returnFalse; - } else if ( !handler ) { - // Fixes bug #7229. Fix recommended by jdalton - return; - } - - var handleObjIn, handleObj; - + // Caller can pass in an object of custom data in lieu of the handler if ( handler.handler ) { handleObjIn = handler; handler = handleObjIn.handler; + selector = handleObjIn.selector; } - // Make sure that the function being executed has a unique ID + // Make sure that the handler has a unique ID, used to find/remove it later if ( !handler.guid ) { handler.guid = jQuery.guid++; } - // Init the element's event structure - var elemData = jQuery._data( elem ); - - // If no elemData is found then we must be trying to bind to one of the - // banned noData elements - if ( !elemData ) { - return; - } - - var events = elemData.events, - eventHandle = elemData.handle; - + // Init the element's event structure and main handler, if this is the first + events = elemData.events; if ( !events ) { elemData.events = events = {}; } - + eventHandle = elemData.handle; if ( !eventHandle ) { - elemData.handle = eventHandle = function() { - // Handle the second event of a trigger and when - // an event is called after a page has unloaded - return typeof jQuery !== "undefined" && !jQuery.event.triggered ? - jQuery.event.handle.apply( eventHandle.elem, arguments ) : + elemData.handle = eventHandle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : undefined; }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; } - // Add elem as a property of the handle function - // This is to prevent a memory leak with non-native events in IE. - eventHandle.elem = elem; - // Handle multiple events separated by a space // jQuery(...).bind("mouseover mouseout", fn); - types = types.split(" "); + types = jQuery.trim( hoverHack(types) ).split( " " ); + for ( t = 0; t < types.length; t++ ) { - var type, i = 0, namespaces; + tns = rtypenamespace.exec( types[t] ) || []; + type = tns[1]; + namespaces = ( tns[2] || "" ).split( "." ).sort(); - while ( (type = types[ i++ ]) ) { - handleObj = handleObjIn ? - jQuery.extend({}, handleObjIn) : - { handler: handler, data: data }; + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; - // Namespaced event handlers - if ( type.indexOf(".") > -1 ) { - namespaces = type.split("."); - type = namespaces.shift(); - handleObj.namespace = namespaces.slice(0).sort().join("."); + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; - } else { - namespaces = []; - handleObj.namespace = ""; - } + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; - handleObj.type = type; - if ( !handleObj.guid ) { - handleObj.guid = handler.guid; - } + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: tns[1], + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + quick: selector && quickParse( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); - // Get the current list of functions bound to this event - var handlers = events[ type ], - special = jQuery.event.special[ type ] || {}; - - // Init the event handler queue + // Init the event handler queue if we're the first + handlers = events[ type ]; if ( !handlers ) { handlers = events[ type ] = []; + handlers.delegateCount = 0; - // Check for a special event handler - // Only use addEventListener/attachEvent if the special - // events handler returns false + // Only use addEventListener/attachEvent if the special events handler returns false if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { // Bind the global event handler to the element if ( elem.addEventListener ) { @@ -2264,10 +2987,14 @@ jQuery.event = { } } - // Add the function to the element's handler list - handlers.push( handleObj ); + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } - // Keep track of which events have been used, for global triggering + // Keep track of which events have ever been used, for event optimization jQuery.event.global[ type ] = true; } @@ -2278,299 +3005,230 @@ jQuery.event = { global: {}, // Detach an event or set of events from an element - remove: function( elem, types, handler, pos ) { - // don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + remove: function( elem, types, handler, selector, mappedTypes ) { + + var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + t, tns, type, origType, namespaces, origCount, + j, events, special, handle, eventType, handleObj; + + if ( !elemData || !(events = elemData.events) ) { return; } - if ( handler === false ) { - handler = returnFalse; - } + // Once for each type.namespace in types; type may be omitted + types = jQuery.trim( hoverHack( types || "" ) ).split(" "); + for ( t = 0; t < types.length; t++ ) { + tns = rtypenamespace.exec( types[t] ) || []; + type = origType = tns[1]; + namespaces = tns[2]; - var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, - elemData = jQuery.hasData( elem ) && jQuery._data( elem ), - events = elemData && elemData.events; - - if ( !elemData || !events ) { - return; - } - - // types is actually an event object here - if ( types && types.type ) { - handler = types.handler; - types = types.type; - } - - // Unbind all events for the element - if ( !types || typeof types === "string" && types.charAt(0) === "." ) { - types = types || ""; - - for ( type in events ) { - jQuery.event.remove( elem, type + types ); - } - - return; - } - - // Handle multiple events separated by a space - // jQuery(...).unbind("mouseover mouseout", fn); - types = types.split(" "); - - while ( (type = types[ i++ ]) ) { - origType = type; - handleObj = null; - all = type.indexOf(".") < 0; - namespaces = []; - - if ( !all ) { - // Namespaced event handlers - namespaces = type.split("."); - type = namespaces.shift(); - - namespace = new RegExp("(^|\\.)" + - jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)"); - } - - eventType = events[ type ]; - - if ( !eventType ) { - continue; - } - - if ( !handler ) { - for ( j = 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( all || namespace.test( handleObj.namespace ) ) { - jQuery.event.remove( elem, origType, handleObj.handler, j ); - eventType.splice( j--, 1 ); - } + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); } - continue; } special = jQuery.event.special[ type ] || {}; + type = ( selector? special.delegateType : special.bindType ) || type; + eventType = events[ type ] || []; + origCount = eventType.length; + namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null; - for ( j = pos || 0; j < eventType.length; j++ ) { + // Remove matching events + for ( j = 0; j < eventType.length; j++ ) { handleObj = eventType[ j ]; - if ( handler.guid === handleObj.guid ) { - // remove the given handler for the given type - if ( all || namespace.test( handleObj.namespace ) ) { - if ( pos == null ) { - eventType.splice( j--, 1 ); - } + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !namespaces || namespaces.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + eventType.splice( j--, 1 ); - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } + if ( handleObj.selector ) { + eventType.delegateCount--; } - - if ( pos != null ) { - break; + if ( special.remove ) { + special.remove.call( elem, handleObj ); } } } - // remove generic event handler if no more handlers exist - if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( eventType.length === 0 && origCount !== eventType.length ) { if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { jQuery.removeEvent( elem, type, elemData.handle ); } - ret = null; delete events[ type ]; } } // Remove the expando if it's no longer used if ( jQuery.isEmptyObject( events ) ) { - var handle = elemData.handle; + handle = elemData.handle; if ( handle ) { handle.elem = null; } - delete elemData.events; - delete elemData.handle; - - if ( jQuery.isEmptyObject( elemData ) ) { - jQuery.removeData( elem, undefined, true ); - } + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery.removeData( elem, [ "events", "handle" ], true ); } }, - // bubbling is internal - trigger: function( event, data, elem /*, bubbling */ ) { + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Don't do events on text and comment nodes + if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { + return; + } + // Event object or event type var type = event.type || event, - bubbling = arguments[3]; + namespaces = [], + cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType; - if ( !bubbling ) { - event = typeof event === "object" ? - // jQuery.Event object - event[ jQuery.expando ] ? event : - // Object literal - jQuery.extend( jQuery.Event(type), event ) : - // Just the event type (string) - jQuery.Event(type); + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } - if ( type.indexOf("!") >= 0 ) { - event.type = type = type.slice(0, -1); - event.exclusive = true; - } + if ( type.indexOf( "!" ) >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } - // Handle a global trigger - if ( !elem ) { - // Don't bubble custom events when global (to avoid too much overhead) - event.stopPropagation(); + if ( type.indexOf( "." ) >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } - // Only trigger if we've ever bound an event for it - if ( jQuery.event.global[ type ] ) { - // XXX This code smells terrible. event.js should not be directly - // inspecting the data cache - jQuery.each( jQuery.cache, function() { - // internalKey variable is just used to make it easier to find - // and potentially change this stuff later; currently it just - // points to jQuery.expando - var internalKey = jQuery.expando, - internalCache = this[ internalKey ]; - if ( internalCache && internalCache.events && internalCache.events[ type ] ) { - jQuery.event.trigger( event, data, internalCache.handle.elem ); - } - }); + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.isTrigger = true; + event.exclusive = exclusive; + event.namespace = namespaces.join( "." ); + event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null; + ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; + + // Handle a global trigger + if ( !elem ) { + + // TODO: Stop taunting the data cache; remove global events and always attach to document + cache = jQuery.cache; + for ( i in cache ) { + if ( cache[ i ].events && cache[ i ].events[ type ] ) { + jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); } } + return; + } - // Handle triggering a single element - - // don't do events on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { - return undefined; - } - - // Clean up in case it is reused - event.result = undefined; + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { event.target = elem; - - // Clone the incoming data, if any - data = jQuery.makeArray( data ); - data.unshift( event ); } - event.currentTarget = elem; + // Clone any incoming data and prepend the event, creating the handler arg list + data = data != null ? jQuery.makeArray( data ) : []; + data.unshift( event ); - // Trigger the event, it is assumed that "handle" is a function - var handle = jQuery._data( elem, "handle" ); - - if ( handle ) { - handle.apply( elem, data ); + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( special.trigger && special.trigger.apply( elem, data ) === false ) { + return; } - var parent = elem.parentNode || elem.ownerDocument; + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + eventPath = [[ elem, special.bindType || type ]]; + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - // Trigger an inline bound script - try { - if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) { - if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) { - event.result = false; - event.preventDefault(); - } + bubbleType = special.delegateType || type; + cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; + old = null; + for ( ; cur; cur = cur.parentNode ) { + eventPath.push([ cur, bubbleType ]); + old = cur; } - // prevent IE from throwing an error for some elements with some event types, see #3533 - } catch (inlineError) {} - - if ( !event.isPropagationStopped() && parent ) { - jQuery.event.trigger( event, data, parent, true ); - - } else if ( !event.isDefaultPrevented() ) { - var old, - target = event.target, - targetType = type.replace( rnamespaces, "" ), - isClick = jQuery.nodeName( target, "a" ) && targetType === "click", - special = jQuery.event.special[ targetType ] || {}; - - if ( (!special._default || special._default.call( elem, event ) === false) && - !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) { - - try { - if ( target[ targetType ] ) { - // Make sure that we don't accidentally re-trigger the onFOO events - old = target[ "on" + targetType ]; - - if ( old ) { - target[ "on" + targetType ] = null; - } - - jQuery.event.triggered = true; - target[ targetType ](); - } - - // prevent IE from throwing an error for some elements with some event types, see #3533 - } catch (triggerError) {} - - if ( old ) { - target[ "on" + targetType ] = old; - } - - jQuery.event.triggered = false; + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( old && old === elem.ownerDocument ) { + eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); } } - }, - handle: function( event ) { - var all, handlers, namespaces, namespace_re, events, - namespace_sort = [], - args = jQuery.makeArray( arguments ); + // Fire handlers on the event path + for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { - event = args[0] = jQuery.event.fix( event || window.event ); - event.currentTarget = this; + cur = eventPath[i][0]; + event.type = eventPath[i][1]; - // Namespaced event handlers - all = event.type.indexOf(".") < 0 && !event.exclusive; - - if ( !all ) { - namespaces = event.type.split("."); - event.type = namespaces.shift(); - namespace_sort = namespaces.slice(0).sort(); - namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)"); + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + // Note that this is a bare JS function and not a jQuery handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { + event.preventDefault(); + } } + event.type = type; - event.namespace = event.namespace || namespace_sort.join("."); + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { - events = jQuery._data(this, "events"); + if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { - handlers = (events || {})[ event.type ]; + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + // IE<9 dies on focus/blur to hidden element (#1486) + if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { - if ( events && handlers ) { - // Clone the handlers to prevent manipulation - handlers = handlers.slice(0); + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; - for ( var j = 0, l = handlers.length; j < l; j++ ) { - var handleObj = handlers[ j ]; - - // Filter the functions by class - if ( all || namespace_re.test( handleObj.namespace ) ) { - // Pass in a reference to the handler function itself - // So that we can later remove it - event.handler = handleObj.handler; - event.data = handleObj.data; - event.handleObj = handleObj; - - var ret = handleObj.handler.apply( this, args ); - - if ( ret !== undefined ) { - event.result = ret; - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); - } + if ( old ) { + elem[ ontype ] = null; } - if ( event.isImmediatePropagationStopped() ) { - break; + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( old ) { + elem[ ontype ] = old; } } } @@ -2579,90 +3237,197 @@ jQuery.event = { return event.result; }, - props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event || window.event ); + + var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), + delegateCount = handlers.delegateCount, + args = [].slice.call( arguments, 0 ), + run_all = !event.exclusive && !event.namespace, + handlerQueue = [], + i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Determine handlers that should run if there are delegated events + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && !(event.button && event.type === "click") ) { + + // Pregenerate a single jQuery object for reuse with .is() + jqcur = jQuery(this); + jqcur.context = this.ownerDocument || this; + + for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { + + // Don't process events on disabled elements (#6911, #8165) + if ( cur.disabled !== true ) { + selMatch = {}; + matches = []; + jqcur[0] = cur; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + sel = handleObj.selector; + + if ( selMatch[ sel ] === undefined ) { + selMatch[ sel ] = ( + handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel ) + ); + } + if ( selMatch[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, matches: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( handlers.length > delegateCount ) { + handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); + } + + // Run delegates first; they may want to stop propagation beneath us + for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { + matched = handlerQueue[ i ]; + event.currentTarget = matched.elem; + + for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { + handleObj = matched.matches[ j ]; + + // Triggered event must either 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { + + event.data = handleObj.data; + event.handleObj = handleObj; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + return event.result; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** + props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var eventDoc, doc, body, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, fix: function( event ) { if ( event[ jQuery.expando ] ) { return event; } - // store a copy of the original event object - // and "clone" to set read-only properties - var originalEvent = event; + // Create a writable copy of the event object and normalize some properties + var i, prop, + originalEvent = event, + fixHook = jQuery.event.fixHooks[ event.type ] || {}, + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + event = jQuery.Event( originalEvent ); - for ( var i = this.props.length, prop; i; ) { - prop = this.props[ --i ]; + for ( i = copy.length; i; ) { + prop = copy[ --i ]; event[ prop ] = originalEvent[ prop ]; } - // Fix target property, if necessary + // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) if ( !event.target ) { - // Fixes #1925 where srcElement might not be defined either - event.target = event.srcElement || document; + event.target = originalEvent.srcElement || document; } - // check if target is a textnode (safari) + // Target should not be a text node (#504, Safari) if ( event.target.nodeType === 3 ) { event.target = event.target.parentNode; } - // Add relatedTarget, if necessary - if ( !event.relatedTarget && event.fromElement ) { - event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; - } - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && event.clientX != null ) { - var doc = document.documentElement, - body = document.body; - - event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); - event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); - } - - // Add which for key events - if ( event.which == null && (event.charCode != null || event.keyCode != null) ) { - event.which = event.charCode != null ? event.charCode : event.keyCode; - } - - // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) - if ( !event.metaKey && event.ctrlKey ) { + // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8) + if ( event.metaKey === undefined ) { event.metaKey = event.ctrlKey; } - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && event.button !== undefined ) { - event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); - } - - return event; + return fixHook.filter? fixHook.filter( event, originalEvent ) : event; }, - // Deprecated, use jQuery.guid instead - guid: 1E8, - - // Deprecated, use jQuery.proxy instead - proxy: jQuery.proxy, - special: { ready: { // Make sure the ready event is setup - setup: jQuery.bindReady, - teardown: jQuery.noop + setup: jQuery.bindReady }, - live: { - add: function( handleObj ) { - jQuery.event.add( this, - liveConvert( handleObj.origType, handleObj.selector ), - jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) ); - }, + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, - remove: function( handleObj ) { - jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj ); - } + focus: { + delegateType: "focusin" + }, + blur: { + delegateType: "focusout" }, beforeunload: { @@ -2679,9 +3444,35 @@ jQuery.event = { } } } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } } }; +// Some plugins are using, but it's undocumented/deprecated and will be removed. +// The 1.7 special event interface should provide all the hooks needed now. +jQuery.event.handle = jQuery.event.dispatch; + jQuery.removeEvent = document.removeEventListener ? function( elem, type, handle ) { if ( elem.removeEventListener ) { @@ -2694,10 +3485,10 @@ jQuery.removeEvent = document.removeEventListener ? } }; -jQuery.Event = function( src ) { +jQuery.Event = function( src, props ) { // Allow instantiation without the 'new' keyword - if ( !this.preventDefault ) { - return new jQuery.Event( src ); + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); } // Event object @@ -2707,17 +3498,21 @@ jQuery.Event = function( src ) { // Events bubbling up the document may have been marked as prevented // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false || - src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse; + this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; // Event type } else { this.type = src; } - // timeStamp is buggy for some events on Firefox(#3843) - // So we won't rely on the native value - this.timeStamp = jQuery.now(); + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); // Mark it as fixed this[ jQuery.expando ] = true; @@ -2773,303 +3568,268 @@ jQuery.Event.prototype = { isImmediatePropagationStopped: returnFalse }; -// Checks if an event happened on an element within another element -// Used in jQuery.event.special.mouseenter and mouseleave handlers -var withinElement = function( event ) { - // Check if mouse(over|out) are still within the same parent element - var parent = event.relatedTarget; - - // Firefox sometimes assigns relatedTarget a XUL element - // which we cannot access the parentNode property of - try { - - // Chrome does something similar, the parentNode property - // can be accessed but is null. - if ( parent !== document && !parent.parentNode ) { - return; - } - // Traverse up the tree - while ( parent && parent !== this ) { - parent = parent.parentNode; - } - - if ( parent !== this ) { - // set the correct event type - event.type = event.data; - - // handle event if we actually just moused on to a non sub-element - jQuery.event.handle.apply( this, arguments ); - } - - // assuming we've left the element since we most likely mousedover a xul element - } catch(e) { } -}, - -// In case of event delegation, we only need to rename the event.type, -// liveHandler will take care of the rest. -delegate = function( event ) { - event.type = event.data; - jQuery.event.handle.apply( this, arguments ); -}; - -// Create mouseenter and mouseleave events +// Create mouseenter/leave events using mouseover/out and event-time checks jQuery.each({ mouseenter: "mouseover", mouseleave: "mouseout" }, function( orig, fix ) { jQuery.event.special[ orig ] = { - setup: function( data ) { - jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); - }, - teardown: function( data ) { - jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var target = this, + related = event.relatedTarget, + handleObj = event.handleObj, + selector = handleObj.selector, + ret; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; } }; }); -// submit delegation +// IE submit delegation if ( !jQuery.support.submitBubbles ) { jQuery.event.special.submit = { - setup: function( data, namespaces ) { - if ( this.nodeName && this.nodeName.toLowerCase() !== "form" ) { - jQuery.event.add(this, "click.specialSubmit", function( e ) { - var elem = e.target, - type = elem.type; - - if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { - trigger( "submit", this, arguments ); - } - }); - - jQuery.event.add(this, "keypress.specialSubmit", function( e ) { - var elem = e.target, - type = elem.type; - - if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { - trigger( "submit", this, arguments ); - } - }); - - } else { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { return false; } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !form._submit_attached ) { + jQuery.event.add( form, "submit._submit", function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + }); + form._submit_attached = true; + } + }); + // return undefined since we don't need an event listener }, - teardown: function( namespaces ) { - jQuery.event.remove( this, ".specialSubmit" ); + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); } }; - } -// change delegation, happens here so we have bind. +// IE change delegation and checkbox/radio fix if ( !jQuery.support.changeBubbles ) { - var changeFilters, - - getVal = function( elem ) { - var type = elem.type, val = elem.value; - - if ( type === "radio" || type === "checkbox" ) { - val = elem.checked; - - } else if ( type === "select-multiple" ) { - val = elem.selectedIndex > -1 ? - jQuery.map( elem.options, function( elem ) { - return elem.selected; - }).join("-") : - ""; - - } else if ( elem.nodeName.toLowerCase() === "select" ) { - val = elem.selectedIndex; - } - - return val; - }, - - testChange = function testChange( e ) { - var elem = e.target, data, val; - - if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) { - return; - } - - data = jQuery._data( elem, "_change_data" ); - val = getVal(elem); - - // the current data will be also retrieved by beforeactivate - if ( e.type !== "focusout" || elem.type !== "radio" ) { - jQuery._data( elem, "_change_data", val ); - } - - if ( data === undefined || val === data ) { - return; - } - - if ( data != null || val ) { - e.type = "change"; - e.liveFired = undefined; - jQuery.event.trigger( e, arguments[1], elem ); - } - }; - jQuery.event.special.change = { - filters: { - focusout: testChange, - beforedeactivate: testChange, + setup: function() { - click: function( e ) { - var elem = e.target, type = elem.type; - - if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) { - testChange.call( this, e ); + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + jQuery.event.simulate( "change", this, event, true ); + } + }); } - }, - - // Change has to be called before submit - // Keydown will be called before keypress, which is used in submit-event delegation - keydown: function( e ) { - var elem = e.target, type = elem.type; - - if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") || - (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || - type === "select-multiple" ) { - testChange.call( this, e ); - } - }, - - // Beforeactivate happens also before the previous element is blurred - // with this event you can't trigger a change event, but you can store - // information - beforeactivate: function( e ) { - var elem = e.target; - jQuery._data( elem, "_change_data", getVal(elem) ); - } - }, - - setup: function( data, namespaces ) { - if ( this.type === "file" ) { return false; } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; - for ( var type in changeFilters ) { - jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); - } - - return rformElems.test( this.nodeName ); + if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + elem._change_attached = true; + } + }); }, - teardown: function( namespaces ) { - jQuery.event.remove( this, ".specialChange" ); + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); return rformElems.test( this.nodeName ); } }; - - changeFilters = jQuery.event.special.change.filters; - - // Handle when the input is .focus()'d - changeFilters.focus = changeFilters.beforeactivate; -} - -function trigger( type, elem, args ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - // Don't pass args or remember liveFired; they apply to the donor event. - var event = jQuery.extend( {}, args[ 0 ] ); - event.type = type; - event.originalEvent = {}; - event.liveFired = undefined; - jQuery.event.handle.call( elem, event ); - if ( event.isDefaultPrevented() ) { - args[ 0 ].preventDefault(); - } } // Create "bubbling" focus and blur events -if ( document.addEventListener ) { +if ( !jQuery.support.focusinBubbles ) { jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + jQuery.event.special[ fix ] = { setup: function() { - this.addEventListener( orig, handler, true ); + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } }, teardown: function() { - this.removeEventListener( orig, handler, true ); + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } } }; - - function handler( e ) { - e = jQuery.event.fix( e ); - e.type = fix; - return jQuery.event.handle.call( this, e ); - } }); } -jQuery.each(["bind", "one"], function( i, name ) { - jQuery.fn[ name ] = function( type, data, fn ) { - // Handle object literals - if ( typeof type === "object" ) { - for ( var key in type ) { - this[ name ](key, data, type[key], fn); +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { // && selector != null + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); } return this; } - if ( jQuery.isFunction( data ) || data === false ) { - fn = data; - data = undefined; - } - - var handler = name === "one" ? jQuery.proxy( fn, function( event ) { - jQuery( this ).unbind( event, handler ); - return fn.apply( this, arguments ); - }) : fn; - - if ( type === "unload" && name !== "one" ) { - this.one( type, data, fn ); - - } else { - for ( var i = 0, l = this.length; i < l; i++ ) { - jQuery.event.add( this[i], type, handler, data ); + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; } } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + var handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( var type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + live: function( types, data, fn ) { + jQuery( this.context ).on( types, this.selector, data, fn ); return this; - }; -}); - -jQuery.fn.extend({ - unbind: function( type, fn ) { - // Handle object literals - if ( typeof type === "object" && !type.preventDefault ) { - for ( var key in type ) { - this.unbind(key, type[key]); - } - - } else { - for ( var i = 0, l = this.length; i < l; i++ ) { - jQuery.event.remove( this[i], type, fn ); - } - } - + }, + die: function( types, fn ) { + jQuery( this.context ).off( types, this.selector || "**", fn ); return this; }, delegate: function( selector, types, data, fn ) { - return this.live( types, data, fn, selector ); + return this.on( types, selector, data, fn ); }, - undelegate: function( selector, types, fn ) { - if ( arguments.length === 0 ) { - return this.unbind( "live" ); - - } else { - return this.die( types, null, fn, selector ); - } + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn ); }, trigger: function( type, data ) { @@ -3077,38 +3837,36 @@ jQuery.fn.extend({ jQuery.event.trigger( type, data, this ); }); }, - triggerHandler: function( type, data ) { if ( this[0] ) { - var event = jQuery.Event( type ); - event.preventDefault(); - event.stopPropagation(); - jQuery.event.trigger( event, data, this[0] ); - return event.result; + return jQuery.event.trigger( type, data, this[0], true ); } }, toggle: function( fn ) { // Save reference to arguments for access in closure var args = arguments, - i = 1; + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; while ( i < args.length ) { - jQuery.proxy( fn, args[ i++ ] ); + args[ i++ ].guid = guid; } - return this.click( jQuery.proxy( fn, function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - })); + return this.click( toggler ); }, hover: function( fnOver, fnOut ) { @@ -3116,165 +3874,9 @@ jQuery.fn.extend({ } }); -var liveMap = { - focus: "focusin", - blur: "focusout", - mouseenter: "mouseover", - mouseleave: "mouseout" -}; - -jQuery.each(["live", "die"], function( i, name ) { - jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { - var type, i = 0, match, namespaces, preType, - selector = origSelector || this.selector, - context = origSelector ? this : jQuery( this.context ); - - if ( typeof types === "object" && !types.preventDefault ) { - for ( var key in types ) { - context[ name ]( key, data, types[key], selector ); - } - - return this; - } - - if ( jQuery.isFunction( data ) ) { - fn = data; - data = undefined; - } - - types = (types || "").split(" "); - - while ( (type = types[ i++ ]) != null ) { - match = rnamespaces.exec( type ); - namespaces = ""; - - if ( match ) { - namespaces = match[0]; - type = type.replace( rnamespaces, "" ); - } - - if ( type === "hover" ) { - types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); - continue; - } - - preType = type; - - if ( type === "focus" || type === "blur" ) { - types.push( liveMap[ type ] + namespaces ); - type = type + namespaces; - - } else { - type = (liveMap[ type ] || type) + namespaces; - } - - if ( name === "live" ) { - // bind live handler - for ( var j = 0, l = context.length; j < l; j++ ) { - jQuery.event.add( context[j], "live." + liveConvert( type, selector ), - { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); - } - - } else { - // unbind live handler - context.unbind( "live." + liveConvert( type, selector ), fn ); - } - } - - return this; - }; -}); - -function liveHandler( event ) { - var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret, - elems = [], - selectors = [], - events = jQuery._data( this, "events" ); - - // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911) - if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) { - return; - } - - if ( event.namespace ) { - namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)"); - } - - event.liveFired = this; - - var live = events.live.slice(0); - - for ( j = 0; j < live.length; j++ ) { - handleObj = live[j]; - - if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { - selectors.push( handleObj.selector ); - - } else { - live.splice( j--, 1 ); - } - } - - match = jQuery( event.target ).closest( selectors, event.currentTarget ); - - for ( i = 0, l = match.length; i < l; i++ ) { - close = match[i]; - - for ( j = 0; j < live.length; j++ ) { - handleObj = live[j]; - - if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) { - elem = close.elem; - related = null; - - // Those two events require additional checking - if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { - event.type = handleObj.preType; - related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; - } - - if ( !related || related !== elem ) { - elems.push({ elem: elem, handleObj: handleObj, level: close.level }); - } - } - } - } - - for ( i = 0, l = elems.length; i < l; i++ ) { - match = elems[i]; - - if ( maxLevel && match.level > maxLevel ) { - break; - } - - event.currentTarget = match.elem; - event.data = match.handleObj.data; - event.handleObj = match.handleObj; - - ret = match.handleObj.origHandler.apply( match.elem, arguments ); - - if ( ret === false || event.isPropagationStopped() ) { - maxLevel = match.level; - - if ( ret === false ) { - stop = false; - } - if ( event.isImmediatePropagationStopped() ) { - break; - } - } - } - - return stop; -} - -function liveConvert( type, selector ) { - return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&"); -} - jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup error").split(" "), function( i, name ) { + "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { // Handle event binding jQuery.fn[ name ] = function( data, fn ) { @@ -3284,16 +3886,25 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl } return arguments.length > 0 ? - this.bind( name, data, fn ) : + this.on( name, null, data, fn ) : this.trigger( name ); }; if ( jQuery.attrFn ) { jQuery.attrFn[ name ] = true; } + + if ( rkeyEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; + } + + if ( rmouseEvent.test( name ) ) { + jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; + } }); + /*! * Sizzle CSS Selector Engine * Copyright 2011, The Dojo Foundation @@ -3303,11 +3914,13 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl (function(){ var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + expando = "sizcache" + (Math.random() + '').replace('.', ''), done = 0, toString = Object.prototype.toString, hasDuplicate = false, baseHasDuplicate = true, rBackslash = /\\/g, + rReturn = /\r\n/g, rNonWord = /\W/; // Here we check if the JavaScript engine is using some sort of @@ -3328,7 +3941,7 @@ var Sizzle = function( selector, context, results, seed ) { if ( context.nodeType !== 1 && context.nodeType !== 9 ) { return []; } - + if ( !selector || typeof selector !== "string" ) { return results; } @@ -3338,7 +3951,7 @@ var Sizzle = function( selector, context, results, seed ) { contextXML = Sizzle.isXML( context ), parts = [], soFar = selector; - + // Reset the position of the chunker regexp (start from head) do { chunker.exec( "" ); @@ -3346,9 +3959,9 @@ var Sizzle = function( selector, context, results, seed ) { if ( m ) { soFar = m[3]; - + parts.push( m[1] ); - + if ( m[2] ) { extra = m[3]; break; @@ -3359,7 +3972,7 @@ var Sizzle = function( selector, context, results, seed ) { if ( parts.length > 1 && origPOS.exec( selector ) ) { if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { - set = posProcess( parts[0] + parts[1], context ); + set = posProcess( parts[0] + parts[1], context, seed ); } else { set = Expr.relative[ parts[0] ] ? @@ -3372,8 +3985,8 @@ var Sizzle = function( selector, context, results, seed ) { if ( Expr.relative[ selector ] ) { selector += parts.shift(); } - - set = posProcess( selector, set ); + + set = posProcess( selector, set, seed ); } } @@ -3492,18 +4105,17 @@ Sizzle.matchesSelector = function( node, expr ) { }; Sizzle.find = function( expr, context, isXML ) { - var set; + var set, i, len, match, type, left; if ( !expr ) { return []; } - for ( var i = 0, l = Expr.order.length; i < l; i++ ) { - var match, - type = Expr.order[i]; - + for ( i = 0, len = Expr.order.length; i < len; i++ ) { + type = Expr.order[i]; + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { - var left = match[1]; + left = match[1]; match.splice( 1, 1 ); if ( left.substr( left.length - 1 ) !== "\\" ) { @@ -3529,17 +4141,18 @@ Sizzle.find = function( expr, context, isXML ) { Sizzle.filter = function( expr, set, inplace, not ) { var match, anyFound, + type, found, item, filter, left, + i, pass, old = expr, result = [], curLoop = set, isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); while ( expr && set.length ) { - for ( var type in Expr.filter ) { + for ( type in Expr.filter ) { if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { - var found, item, - filter = Expr.filter[ type ], - left = match[1]; + filter = Expr.filter[ type ]; + left = match[1]; anyFound = false; @@ -3565,10 +4178,10 @@ Sizzle.filter = function( expr, set, inplace, not ) { } if ( match ) { - for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + for ( i = 0; (item = curLoop[i]) != null; i++ ) { if ( item ) { found = filter( item, match, i, curLoop ); - var pass = not ^ !!found; + pass = not ^ found; if ( inplace && found != null ) { if ( pass ) { @@ -3619,7 +4232,46 @@ Sizzle.filter = function( expr, set, inplace, not ) { }; Sizzle.error = function( msg ) { - throw "Syntax error, unrecognized expression: " + msg; + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Utility function for retreiving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +var getText = Sizzle.getText = function( elem ) { + var i, node, + nodeType = elem.nodeType, + ret = ""; + + if ( nodeType ) { + if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent || innerText for elements + if ( typeof elem.textContent === 'string' ) { + return elem.textContent; + } else if ( typeof elem.innerText === 'string' ) { + // Replace IE's carriage returns + return elem.innerText.replace( rReturn, '' ); + } else { + // Traverse it's children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + } else { + + // If no nodeType, this is expected to be an array + for ( i = 0; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + if ( node.nodeType !== 8 ) { + ret += getText( node ); + } + } + } + return ret; }; var Expr = Sizzle.selectors = { @@ -3833,7 +4485,7 @@ var Expr = Sizzle.selectors = { ATTR: function( match, curLoop, inplace, result, not, isXML ) { var name = match[1] = match[1].replace( rBackslash, "" ); - + if ( !isXML && Expr.attrMap[name] ) { match[1] = Expr.attrMap[name]; } @@ -3867,7 +4519,7 @@ var Expr = Sizzle.selectors = { } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { return true; } - + return match; }, @@ -3877,7 +4529,7 @@ var Expr = Sizzle.selectors = { return match; } }, - + filters: { enabled: function( elem ) { return elem.disabled === false && elem.type !== "hidden"; @@ -3890,14 +4542,14 @@ var Expr = Sizzle.selectors = { checked: function( elem ) { return elem.checked === true; }, - + selected: function( elem ) { // Accessing this property makes selected-by-default // options in Safari work properly if ( elem.parentNode ) { elem.parentNode.selectedIndex; } - + return elem.selected === true; }, @@ -3918,43 +4570,53 @@ var Expr = Sizzle.selectors = { }, text: function( elem ) { - // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + var attr = elem.getAttribute( "type" ), type = elem.type; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) // use getAttribute instead to test this case - return "text" === elem.getAttribute( 'type' ); + return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); }, + radio: function( elem ) { - return "radio" === elem.type; + return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; }, checkbox: function( elem ) { - return "checkbox" === elem.type; + return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; }, file: function( elem ) { - return "file" === elem.type; + return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; }, + password: function( elem ) { - return "password" === elem.type; + return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; }, submit: function( elem ) { - return "submit" === elem.type; + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "submit" === elem.type; }, image: function( elem ) { - return "image" === elem.type; + return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; }, reset: function( elem ) { - return "reset" === elem.type; + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "reset" === elem.type; }, button: function( elem ) { - return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; + var name = elem.nodeName.toLowerCase(); + return name === "input" && "button" === elem.type || name === "button"; }, input: function( elem ) { return (/input|select|textarea|button/i).test( elem.nodeName ); + }, + + focus: function( elem ) { + return elem === elem.ownerDocument.activeElement; } }, setFilters: { @@ -3999,7 +4661,7 @@ var Expr = Sizzle.selectors = { return filter( elem, i, match, array ); } else if ( name === "contains" ) { - return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0; + return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; } else if ( name === "not" ) { var not = match[3]; @@ -4018,57 +4680,61 @@ var Expr = Sizzle.selectors = { }, CHILD: function( elem, match ) { - var type = match[1], + var first, last, + doneName, parent, cache, + count, diff, + type = match[1], node = elem; switch ( type ) { case "only": case "first": - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) { - return false; + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; } } - if ( type === "first" ) { - return true; + if ( type === "first" ) { + return true; } node = elem; + /* falls through */ case "last": - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) { - return false; + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; } } return true; case "nth": - var first = match[2], - last = match[3]; + first = match[2]; + last = match[3]; if ( first === 1 && last === 0 ) { return true; } - - var doneName = match[0], - parent = elem.parentNode; - - if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { - var count = 0; - + + doneName = match[0]; + parent = elem.parentNode; + + if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { + count = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { if ( node.nodeType === 1 ) { node.nodeIndex = ++count; } - } + } - parent.sizcache = doneName; + parent[ expando ] = doneName; } - - var diff = elem.nodeIndex - last; + + diff = elem.nodeIndex - last; if ( first === 0 ) { return diff === 0; @@ -4084,9 +4750,9 @@ var Expr = Sizzle.selectors = { }, TAG: function( elem, match ) { - return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; + return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; }, - + CLASS: function( elem, match ) { return (" " + (elem.className || elem.getAttribute("class")) + " ") .indexOf( match ) > -1; @@ -4094,7 +4760,9 @@ var Expr = Sizzle.selectors = { ATTR: function( elem, match ) { var name = match[1], - result = Expr.attrHandle[ name ] ? + result = Sizzle.attr ? + Sizzle.attr( elem, name ) : + Expr.attrHandle[ name ] ? Expr.attrHandle[ name ]( elem ) : elem[ name ] != null ? elem[ name ] : @@ -4105,6 +4773,8 @@ var Expr = Sizzle.selectors = { return result == null ? type === "!=" : + !type && Sizzle.attr ? + result != null : type === "=" ? value === check : type === "*=" ? @@ -4144,6 +4814,9 @@ for ( var type in Expr.match ) { Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); } +// Expose origPOS +// "global" as in regardless of relation to brackets/parens +Expr.match.globalPOS = origPOS; var makeArray = function( array, results ) { array = Array.prototype.slice.call( array, 0 ); @@ -4152,7 +4825,7 @@ var makeArray = function( array, results ) { results.push.apply( results, array ); return results; } - + return array; }; @@ -4207,6 +4880,16 @@ if ( document.documentElement.compareDocumentPosition ) { } else { sortOrder = function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + var al, bl, ap = [], bp = [], @@ -4214,13 +4897,8 @@ if ( document.documentElement.compareDocumentPosition ) { bup = b.parentNode, cur = aup; - // The nodes are identical, we can exit early - if ( a === b ) { - hasDuplicate = true; - return 0; - // If the nodes are siblings (or identical) we can do a quick check - } else if ( aup === bup ) { + if ( aup === bup ) { return siblingCheck( a, b ); // If no parents were found then the nodes are disconnected @@ -4280,26 +4958,6 @@ if ( document.documentElement.compareDocumentPosition ) { }; } -// Utility function for retreiving the text value of an array of DOM nodes -Sizzle.getText = function( elems ) { - var ret = "", elem; - - for ( var i = 0; elems[i]; i++ ) { - elem = elems[i]; - - // Get the text from text nodes and CDATA nodes - if ( elem.nodeType === 3 || elem.nodeType === 4 ) { - ret += elem.nodeValue; - - // Traverse everything else, except comment nodes - } else if ( elem.nodeType !== 8 ) { - ret += Sizzle.getText( elem.childNodes ); - } - } - - return ret; -}; - // Check to see if the browser returns elements by name when // querying by getElementById (and provide a workaround) (function(){ @@ -4399,7 +5057,7 @@ if ( document.querySelectorAll ) { if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { return; } - + Sizzle = function( query, context, extra, seed ) { context = context || document; @@ -4408,24 +5066,24 @@ if ( document.querySelectorAll ) { if ( !seed && !Sizzle.isXML(context) ) { // See if we find a selector to speed up var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); - + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { // Speed-up: Sizzle("TAG") if ( match[1] ) { return makeArray( context.getElementsByTagName( query ), extra ); - + // Speed-up: Sizzle(".CLASS") } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { return makeArray( context.getElementsByClassName( match[2] ), extra ); } } - + if ( context.nodeType === 9 ) { // Speed-up: Sizzle("body") // The body element only exists once, optimize finding it if ( query === "body" && context.body ) { return makeArray( [ context.body ], extra ); - + // Speed-up: Sizzle("#ID") } else if ( match && match[3] ) { var elem = context.getElementById( match[3] ); @@ -4438,12 +5096,12 @@ if ( document.querySelectorAll ) { if ( elem.id === match[3] ) { return makeArray( [ elem ], extra ); } - + } else { return makeArray( [], extra ); } } - + try { return makeArray( context.querySelectorAll(query), extra ); } catch(qsaError) {} @@ -4481,7 +5139,7 @@ if ( document.querySelectorAll ) { } } } - + return oldSizzle(query, context, extra, seed); }; @@ -4496,27 +5154,39 @@ if ( document.querySelectorAll ) { (function(){ var html = document.documentElement, - matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector, - pseudoWorks = false; - - try { - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( document.documentElement, "[test!='']:sizzle" ); - - } catch( pseudoError ) { - pseudoWorks = true; - } + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; if ( matches ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9 fails this) + var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + Sizzle.matchesSelector = function( node, expr ) { // Make sure that attribute selectors are quoted expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); if ( !Sizzle.isXML( node ) ) { - try { + try { if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { - return matches.call( node, expr ); + var ret = matches.call( node, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || !disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9, so check for that + node.document && node.document.nodeType !== 11 ) { + return ret; + } } } catch(e) {} } @@ -4543,7 +5213,7 @@ if ( document.querySelectorAll ) { if ( div.getElementsByClassName("e").length === 1 ) { return; } - + Expr.order.splice(1, 0, "CLASS"); Expr.find.CLASS = function( match, context, isXML ) { if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { @@ -4565,13 +5235,13 @@ function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { elem = elem[dir]; while ( elem ) { - if ( elem.sizcache === doneName ) { + if ( elem[ expando ] === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 && !isXML ){ - elem.sizcache = doneName; + elem[ expando ] = doneName; elem.sizset = i; } @@ -4594,18 +5264,18 @@ function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { if ( elem ) { var match = false; - + elem = elem[dir]; while ( elem ) { - if ( elem.sizcache === doneName ) { + if ( elem[ expando ] === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 ) { if ( !isXML ) { - elem.sizcache = doneName; + elem[ expando ] = doneName; elem.sizset = i; } @@ -4647,13 +5317,13 @@ if ( document.documentElement.contains ) { Sizzle.isXML = function( elem ) { // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) + // (such as loading iframes in IE - #4833) var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; return documentElement ? documentElement.nodeName !== "HTML" : false; }; -var posProcess = function( selector, context ) { +var posProcess = function( selector, context, seed ) { var match, tmpSet = [], later = "", @@ -4669,13 +5339,16 @@ var posProcess = function( selector, context ) { selector = Expr.relative[selector] ? selector + "*" : selector; for ( var i = 0, l = root.length; i < l; i++ ) { - Sizzle( selector, root[i], tmpSet ); + Sizzle( selector, root[i], tmpSet, seed ); } return Sizzle.filter( later, tmpSet ); }; // EXPOSE +// Override sizzle attribute retrieval +Sizzle.attr = jQuery.attr; +Sizzle.selectors.attrMap = {}; jQuery.find = Sizzle; jQuery.expr = Sizzle.selectors; jQuery.expr[":"] = jQuery.expr.filters; @@ -4694,7 +5367,7 @@ var runtil = /Until$/, rmultiselector = /,/, isSimple = /^.[^:#\[\.,]*$/, slice = Array.prototype.slice, - POS = jQuery.expr.match.POS, + POS = jQuery.expr.match.globalPOS, // methods guaranteed to produce a unique set when starting from a unique set guaranteedUnique = { children: true, @@ -4705,17 +5378,30 @@ var runtil = /Until$/, jQuery.fn.extend({ find: function( selector ) { - var ret = this.pushStack( "", "find", selector ), - length = 0; + var self = this, + i, l; - for ( var i = 0, l = this.length; i < l; i++ ) { + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + var ret = this.pushStack( "", "find", selector ), + length, n, r; + + for ( i = 0, l = this.length; i < l; i++ ) { length = ret.length; jQuery.find( selector, this[i], ret ); if ( i > 0 ) { // Make sure that the results are unique - for ( var n = length; n < ret.length; n++ ) { - for ( var r = 0; r < length; r++ ) { + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { if ( ret[r] === ret[n] ) { ret.splice(n--, 1); break; @@ -4748,47 +5434,42 @@ jQuery.fn.extend({ }, is: function( selector ) { - return !!selector && jQuery.filter( selector, this ).length > 0; + return !!selector && ( + typeof selector === "string" ? + // If this is a positional selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + POS.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); }, closest: function( selectors, context ) { var ret = [], i, l, cur = this[0]; + // Array (deprecated as of jQuery 1.7) if ( jQuery.isArray( selectors ) ) { - var match, selector, - matches = {}, - level = 1; + var level = 1; - if ( cur && selectors.length ) { - for ( i = 0, l = selectors.length; i < l; i++ ) { - selector = selectors[i]; + while ( cur && cur.ownerDocument && cur !== context ) { + for ( i = 0; i < selectors.length; i++ ) { - if ( !matches[selector] ) { - matches[selector] = jQuery.expr.match.POS.test( selector ) ? - jQuery( selector, context || this.context ) : - selector; + if ( jQuery( cur ).is( selectors[ i ] ) ) { + ret.push({ selector: selectors[ i ], elem: cur, level: level }); } } - while ( cur && cur.ownerDocument && cur !== context ) { - for ( selector in matches ) { - match = matches[selector]; - - if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) { - ret.push({ selector: selector, elem: cur, level: level }); - } - } - - cur = cur.parentNode; - level++; - } + cur = cur.parentNode; + level++; } return ret; } - var pos = POS.test( selectors ) ? - jQuery( selectors, context || this.context ) : null; + // String + var pos = POS.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; for ( i = 0, l = this.length; i < l; i++ ) { cur = this[i]; @@ -4800,14 +5481,14 @@ jQuery.fn.extend({ } else { cur = cur.parentNode; - if ( !cur || !cur.ownerDocument || cur === context ) { + if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { break; } } } } - ret = ret.length > 1 ? jQuery.unique(ret) : ret; + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; return this.pushStack( ret, "closest", selectors ); }, @@ -4815,12 +5496,17 @@ jQuery.fn.extend({ // Determine the position of an element within // the matched set of elements index: function( elem ) { - if ( !elem || typeof elem === "string" ) { - return jQuery.inArray( this[0], - // If it receives a string, the selector is used - // If it receives nothing, the siblings are used - elem ? jQuery( elem ) : this.parent().children() ); + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + // Locate the position of the desired element return jQuery.inArray( // If it receives a jQuery object, the first element is used @@ -4830,7 +5516,7 @@ jQuery.fn.extend({ add: function( selector, context ) { var set = typeof selector === "string" ? jQuery( selector, context ) : - jQuery.makeArray( selector ), + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), all = jQuery.merge( this.get(), set ); return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? @@ -4891,12 +5577,7 @@ jQuery.each({ } }, function( name, fn ) { jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ), - // The variable 'args' was introduced in - // https://github.com/jquery/jquery/commit/52a0238 - // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed. - // http://code.google.com/p/v8/issues/detail?id=1050 - args = slice.call(arguments); + var ret = jQuery.map( this, fn, until ); if ( !runtil.test( name ) ) { selector = until; @@ -4912,7 +5593,7 @@ jQuery.each({ ret = ret.reverse(); } - return this.pushStack( ret, name, args.join(",") ); + return this.pushStack( ret, name, slice.call( arguments ).join(",") ); }; }); @@ -4968,6 +5649,11 @@ jQuery.extend({ // Implement the identical functionality for filter and not function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + if ( jQuery.isFunction( qualifier ) ) { return jQuery.grep(elements, function( elem, i ) { var retVal = !!qualifier.call( elem, i, elem ); @@ -4976,7 +5662,7 @@ function winnow( elements, qualifier, keep ) { } else if ( qualifier.nodeType ) { return jQuery.grep(elements, function( elem, i ) { - return (elem === qualifier) === keep; + return ( elem === qualifier ) === keep; }); } else if ( typeof qualifier === "string" ) { @@ -4992,22 +5678,42 @@ function winnow( elements, qualifier, keep ) { } return jQuery.grep(elements, function( elem, i ) { - return (jQuery.inArray( elem, qualifier ) >= 0) === keep; + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; }); } -var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, rleadingWhitespace = /^\s+/, rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, rtagName = /<([\w:]+)/, rtbody = /", "" ], legend: [ 1, "
", "
" ], @@ -5017,7 +5723,8 @@ var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, col: [ 2, "", "
" ], area: [ 1, "", "" ], _default: [ 0, "", "" ] - }; + }, + safeFragment = createSafeFragment( document ); wrapMap.optgroup = wrapMap.option; wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; @@ -5029,20 +5736,12 @@ if ( !jQuery.support.htmlSerialize ) { } jQuery.fn.extend({ - text: function( text ) { - if ( jQuery.isFunction(text) ) { - return this.each(function(i) { - var self = jQuery( this ); - - self.text( text.call(this, i, self.text()) ); - }); - } - - if ( typeof text !== "object" && text !== undefined ) { - return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) ); - } - - return jQuery.text( this ); + text: function( value ) { + return jQuery.access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); + }, null, value, arguments.length ); }, wrapAll: function( html ) { @@ -5068,7 +5767,7 @@ jQuery.fn.extend({ } return elem; - }).append(this); + }).append( this ); } return this; @@ -5095,8 +5794,10 @@ jQuery.fn.extend({ }, wrap: function( html ) { - return this.each(function() { - jQuery( this ).wrapAll( html ); + var isFunction = jQuery.isFunction( html ); + + return this.each(function(i) { + jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); }); }, @@ -5130,7 +5831,7 @@ jQuery.fn.extend({ this.parentNode.insertBefore( elem, this ); }); } else if ( arguments.length ) { - var set = jQuery(arguments[0]); + var set = jQuery.clean( arguments ); set.push.apply( set, this.toArray() ); return this.pushStack( set, "before", arguments ); } @@ -5143,7 +5844,7 @@ jQuery.fn.extend({ }); } else if ( arguments.length ) { var set = this.pushStack( this, "after", arguments ); - set.push.apply( set, jQuery(arguments[0]).toArray() ); + set.push.apply( set, jQuery.clean(arguments) ); return set; } }, @@ -5192,44 +5893,44 @@ jQuery.fn.extend({ }, html: function( value ) { - if ( value === undefined ) { - return this[0] && this[0].nodeType === 1 ? - this[0].innerHTML.replace(rinlinejQuery, "") : - null; + return jQuery.access( this, function( value ) { + var elem = this[0] || {}, + i = 0, + l = this.length; - // See if we can take a shortcut and just use innerHTML - } else if ( typeof value === "string" && !rnocache.test( value ) && - (jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) && - !wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) { - - value = value.replace(rxhtmlTag, "<$1>"); - - try { - for ( var i = 0, l = this.length; i < l; i++ ) { - // Remove element nodes and prevent memory leaks - if ( this[i].nodeType === 1 ) { - jQuery.cleanData( this[i].getElementsByTagName("*") ); - this[i].innerHTML = value; - } - } - - // If using innerHTML throws an exception, use the fallback method - } catch(e) { - this.empty().append( value ); + if ( value === undefined ) { + return elem.nodeType === 1 ? + elem.innerHTML.replace( rinlinejQuery, "" ) : + null; } - } else if ( jQuery.isFunction( value ) ) { - this.each(function(i){ - var self = jQuery( this ); - self.html( value.call(this, i, self.html()) ); - }); + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && + !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { - } else { - this.empty().append( value ); - } + value = value.replace( rxhtmlTag, "<$1>" ); - return this; + try { + for (; i < l; i++ ) { + // Remove element nodes and prevent memory leaks + elem = this[i] || {}; + if ( elem.nodeType === 1 ) { + jQuery.cleanData( elem.getElementsByTagName( "*" ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch(e) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); }, replaceWith: function( value ) { @@ -5260,7 +5961,9 @@ jQuery.fn.extend({ } }); } else { - return this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ); + return this.length ? + this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) : + this; } }, @@ -5322,7 +6025,7 @@ jQuery.fn.extend({ // in certain situations (Bug #8070). // Fragments from the fragment cache must always be cloned and never used // in place. - results.cacheable || (l > 1 && i < lastIndex) ? + results.cacheable || ( l > 1 && i < lastIndex ) ? jQuery.clone( fragment, true, true ) : fragment ); @@ -5330,7 +6033,21 @@ jQuery.fn.extend({ } if ( scripts.length ) { - jQuery.each( scripts, evalScript ); + jQuery.each( scripts, function( i, elem ) { + if ( elem.src ) { + jQuery.ajax({ + url: elem.src, + async: false, + dataType: "script" + }); + } else { + jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) ); + } + + if ( elem.parentNode ) { + elem.parentNode.removeChild( elem ); + } + }); } } @@ -5351,44 +6068,49 @@ function cloneCopyEvent( src, dest ) { return; } - var internalKey = jQuery.expando, - oldData = jQuery.data( src ), - curData = jQuery.data( dest, oldData ); + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; - // Switch to use the internal data object, if it exists, for the next - // stage of data copying - if ( (oldData = oldData[ internalKey ]) ) { - var events = oldData.events; - curData = curData[ internalKey ] = jQuery.extend({}, oldData); + if ( events ) { + delete curData.handle; + curData.events = {}; - if ( events ) { - delete curData.handle; - curData.events = {}; - - for ( var type in events ) { - for ( var i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data ); - } + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); } } } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } } -function cloneFixAttributes(src, dest) { +function cloneFixAttributes( src, dest ) { + var nodeName; + // We do not need to do anything for non-Elements if ( dest.nodeType !== 1 ) { return; } - var nodeName = dest.nodeName.toLowerCase(); - // clearAttributes removes the attributes, which we don't want, // but also removes the attachEvent events, which we *do* want - dest.clearAttributes(); + if ( dest.clearAttributes ) { + dest.clearAttributes(); + } // mergeAttributes, in contrast, only merges back on the // original attributes, not the events - dest.mergeAttributes(src); + if ( dest.mergeAttributes ) { + dest.mergeAttributes( src ); + } + + nodeName = dest.nodeName.toLowerCase(); // IE6-8 fail to clone children inside object elements that use // the proprietary classid attribute value (rather than the type @@ -5424,25 +6146,46 @@ function cloneFixAttributes(src, dest) { // Event data gets referenced instead of copied if the expando // gets copied too dest.removeAttribute( jQuery.expando ); + + // Clear flags for bubbling special change/submit events, they must + // be reattached when the newly cloned events are first activated + dest.removeAttribute( "_submit_attached" ); + dest.removeAttribute( "_change_attached" ); } jQuery.buildFragment = function( args, nodes, scripts ) { - var fragment, cacheable, cacheresults, - doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document); + var fragment, cacheable, cacheresults, doc, + first = args[ 0 ]; + + // nodes may contain either an explicit document object, + // a jQuery collection or context object. + // If nodes[0] contains a valid object to assign to doc + if ( nodes && nodes[0] ) { + doc = nodes[0].ownerDocument || nodes[0]; + } + + // Ensure that an attr object doesn't incorrectly stand in as a document object + // Chrome and Firefox seem to allow this to occur and will throw exception + // Fixes #8950 + if ( !doc.createDocumentFragment ) { + doc = document; + } // Only cache "small" (1/2 KB) HTML strings that are associated with the main document // Cloning options loses the selected state, so don't cache them // IE 6 doesn't like it when you put or elements in a fragment // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache - if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && doc === document && - args[0].charAt(0) === "<" && !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) { + // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501 + if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document && + first.charAt(0) === "<" && !rnocache.test( first ) && + (jQuery.support.checkClone || !rchecked.test( first )) && + (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) { cacheable = true; - cacheresults = jQuery.fragments[ args[0] ]; - if ( cacheresults ) { - if ( cacheresults !== 1 ) { - fragment = cacheresults; - } + + cacheresults = jQuery.fragments[ first ]; + if ( cacheresults && cacheresults !== 1 ) { + fragment = cacheresults; } } @@ -5452,7 +6195,7 @@ jQuery.buildFragment = function( args, nodes, scripts ) { } if ( cacheable ) { - jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1; + jQuery.fragments[ first ] = cacheresults ? fragment : 1; } return { fragment: fragment, cacheable: cacheable }; @@ -5478,7 +6221,7 @@ jQuery.each({ } else { for ( var i = 0, l = insert.length; i < l; i++ ) { - var elems = (i > 0 ? this.clone(true) : this).get(); + var elems = ( i > 0 ? this.clone(true) : this ).get(); jQuery( insert[i] )[ original ]( elems ); ret = ret.concat( elems ); } @@ -5489,10 +6232,10 @@ jQuery.each({ }); function getAll( elem ) { - if ( "getElementsByTagName" in elem ) { + if ( typeof elem.getElementsByTagName !== "undefined" ) { return elem.getElementsByTagName( "*" ); - - } else if ( "querySelectorAll" in elem ) { + + } else if ( typeof elem.querySelectorAll !== "undefined" ) { return elem.querySelectorAll( "*" ); } else { @@ -5500,12 +6243,41 @@ function getAll( elem ) { } } +// Used in clean, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( elem.type === "checkbox" || elem.type === "radio" ) { + elem.defaultChecked = elem.checked; + } +} +// Finds all inputs and passes them to fixDefaultChecked +function findInputs( elem ) { + var nodeName = ( elem.nodeName || "" ).toLowerCase(); + if ( nodeName === "input" ) { + fixDefaultChecked( elem ); + // Skip scripts, get other children + } else if ( nodeName !== "script" && typeof elem.getElementsByTagName !== "undefined" ) { + jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); + } +} + +// Derived From: http://www.iecss.com/shimprove/javascript/shimprove.1-0-1.js +function shimCloneNode( elem ) { + var div = document.createElement( "div" ); + safeFragment.appendChild( div ); + + div.innerHTML = elem.outerHTML; + return div.firstChild; +} + jQuery.extend({ clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var clone = elem.cloneNode(true), - srcElements, - destElements, - i; + var srcElements, + destElements, + i, + // IE<=8 does not properly clone detached, unknown element nodes + clone = jQuery.support.html5Clone || !rnoshimcache.test( "<" + elem.nodeName ) ? + elem.cloneNode( true ) : + shimCloneNode( elem ); if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { @@ -5517,8 +6289,7 @@ jQuery.extend({ cloneFixAttributes( elem, clone ); - // Using Sizzle here is crazy slow, so we use getElementsByTagName - // instead + // Using Sizzle here is crazy slow, so we use getElementsByTagName instead srcElements = getAll( elem ); destElements = getAll( clone ); @@ -5526,7 +6297,10 @@ jQuery.extend({ // with an element if you are cloning the body and one of the // elements on the page has a name or id of "length" for ( i = 0; srcElements[i]; ++i ) { - cloneFixAttributes( srcElements[i], destElements[i] ); + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[i] ) { + cloneFixAttributes( srcElements[i], destElements[i] ); + } } } @@ -5544,10 +6318,15 @@ jQuery.extend({ } } + srcElements = destElements = null; + // Return the cloned set return clone; -}, + }, + clean: function( elems, context, fragment, scripts ) { + var checkScriptType; + context = context || document; // !context.createElement fails in IE with an error but returns typeof 'object' @@ -5555,7 +6334,7 @@ jQuery.extend({ context = context.ownerDocument || context[0] && context[0].ownerDocument || document; } - var ret = []; + var ret = [], j; for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { if ( typeof elem === "number" ) { @@ -5567,54 +6346,76 @@ jQuery.extend({ } // Convert html string into DOM nodes - if ( typeof elem === "string" && !rhtml.test( elem ) ) { - elem = context.createTextNode( elem ); + if ( typeof elem === "string" ) { + if ( !rhtml.test( elem ) ) { + elem = context.createTextNode( elem ); + } else { + // Fix "XHTML"-style tags in all browsers + elem = elem.replace(rxhtmlTag, "<$1>"); - } else if ( typeof elem === "string" ) { - // Fix "XHTML"-style tags in all browsers - elem = elem.replace(rxhtmlTag, "<$1>"); + // Trim whitespace, otherwise indexOf won't work as expected + var tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(), + wrap = wrapMap[ tag ] || wrapMap._default, + depth = wrap[0], + div = context.createElement("div"); - // Trim whitespace, otherwise indexOf won't work as expected - var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(), - wrap = wrapMap[ tag ] || wrapMap._default, - depth = wrap[0], - div = context.createElement("div"); + // Append wrapper element to unknown element safe doc fragment + if ( context === document ) { + // Use the fragment we've already created for this document + safeFragment.appendChild( div ); + } else { + // Use a fragment created with the owner document + createSafeFragment( context ).appendChild( div ); + } - // Go to html and back, then peel off extra wrappers - div.innerHTML = wrap[1] + elem + wrap[2]; + // Go to html and back, then peel off extra wrappers + div.innerHTML = wrap[1] + elem + wrap[2]; - // Move to the right depth - while ( depth-- ) { - div = div.lastChild; - } + // Move to the right depth + while ( depth-- ) { + div = div.lastChild; + } - // Remove IE's autoinserted from table fragments - if ( !jQuery.support.tbody ) { + // Remove IE's autoinserted from table fragments + if ( !jQuery.support.tbody ) { - // String was a , *may* have spurious - var hasBody = rtbody.test(elem), - tbody = tag === "table" && !hasBody ? - div.firstChild && div.firstChild.childNodes : + // String was a
, *may* have spurious + var hasBody = rtbody.test(elem), + tbody = tag === "table" && !hasBody ? + div.firstChild && div.firstChild.childNodes : - // String was a bare or - wrap[1] === "
" && !hasBody ? - div.childNodes : - []; + // String was a bare or + wrap[1] === "
" && !hasBody ? + div.childNodes : + []; - for ( var j = tbody.length - 1; j >= 0 ; --j ) { - if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { - tbody[ j ].parentNode.removeChild( tbody[ j ] ); + for ( j = tbody.length - 1; j >= 0 ; --j ) { + if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { + tbody[ j ].parentNode.removeChild( tbody[ j ] ); + } } } - } + // IE completely kills leading whitespace when innerHTML is used + if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); + } - // IE completely kills leading whitespace when innerHTML is used - if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { - div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); + elem = div.childNodes; } + } - elem = div.childNodes; + // Resets defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + var len; + if ( !jQuery.support.appendChecked ) { + if ( elem[0] && typeof (len = elem.length) === "number" ) { + for ( j = 0; j < len; j++ ) { + findInputs( elem[j] ); + } + } else { + findInputs( elem ); + } } if ( elem.nodeType ) { @@ -5625,13 +6426,18 @@ jQuery.extend({ } if ( fragment ) { + checkScriptType = function( elem ) { + return !elem.type || rscriptType.test( elem.type ); + }; for ( i = 0; ret[i]; i++ ) { if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) { scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] ); } else { if ( ret[i].nodeType === 1 ) { - ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) ); + var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType ); + + ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); } fragment.appendChild( ret[i] ); } @@ -5642,7 +6448,9 @@ jQuery.extend({ }, cleanData: function( elems ) { - var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special, + var data, id, + cache = jQuery.cache, + special = jQuery.event.special, deleteExpando = jQuery.support.deleteExpando; for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { @@ -5653,7 +6461,7 @@ jQuery.extend({ id = elem[ jQuery.expando ]; if ( id ) { - data = cache[ id ] && cache[ id ][ internalKey ]; + data = cache[ id ]; if ( data && data.events ) { for ( var type in data.events ) { @@ -5685,55 +6493,34 @@ jQuery.extend({ } }); -function evalScript( i, elem ) { - if ( elem.src ) { - jQuery.ajax({ - url: elem.src, - async: false, - dataType: "script" - }); - } else { - jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); - } - - if ( elem.parentNode ) { - elem.parentNode.removeChild( elem ); - } -} - var ralpha = /alpha\([^)]*\)/i, ropacity = /opacity=([^)]*)/, - rdashAlpha = /-([a-z])/ig, - rupper = /([A-Z])/g, - rnumpx = /^-?\d+(?:px)?$/i, - rnum = /^-?\d/, + // fixed for IE9, see #8346 + rupper = /([A-Z]|^ms)/g, + rnum = /^[\-+]?(?:\d*\.)?\d+$/i, + rnumnonpx = /^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i, + rrelNum = /^([\-+])=([\-+.\de]+)/, + rmargin = /^margin/, cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssWidth = [ "Left", "Right" ], - cssHeight = [ "Top", "Bottom" ], + + // order is important! + cssExpand = [ "Top", "Right", "Bottom", "Left" ], + curCSS, getComputedStyle, - currentStyle, - - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }; + currentStyle; jQuery.fn.css = function( name, value ) { - // Setting 'undefined' is a no-op - if ( arguments.length === 2 && value === undefined ) { - return this; - } - - return jQuery.access( this, name, value, true, function( elem, name, value ) { + return jQuery.access( this, function( elem, name, value ) { return value !== undefined ? jQuery.style( elem, name, value ) : jQuery.css( elem, name ); - }); + }, name, value, arguments.length > 1 ); }; jQuery.extend({ @@ -5744,7 +6531,7 @@ jQuery.extend({ get: function( elem, computed ) { if ( computed ) { // We should always get a number back from opacity - var ret = curCSS( elem, "opacity", "opacity" ); + var ret = curCSS( elem, "opacity" ); return ret === "" ? "1" : ret; } else { @@ -5756,11 +6543,14 @@ jQuery.extend({ // Exclude the following css properties to add px cssNumber: { - "zIndex": true, + "fillOpacity": true, "fontWeight": true, + "lineHeight": true, "opacity": true, - "zoom": true, - "lineHeight": true + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true }, // Add in properties whose names you wish to fix before @@ -5778,20 +6568,29 @@ jQuery.extend({ } // Make sure that we're working with the right name - var ret, origName = jQuery.camelCase( name ), + var ret, type, origName = jQuery.camelCase( name ), style = elem.style, hooks = jQuery.cssHooks[ origName ]; name = jQuery.cssProps[ origName ] || origName; // Check if we're setting a value if ( value !== undefined ) { + type = typeof value; + + // convert relative number strings (+= or -=) to relative numbers. #7345 + if ( type === "string" && (ret = rrelNum.exec( value )) ) { + value = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) ); + // Fixes bug #9237 + type = "number"; + } + // Make sure that NaN and null values aren't set. See: #7116 - if ( typeof value === "number" && isNaN( value ) || value == null ) { + if ( value == null || type === "number" && isNaN( value ) ) { return; } // If a number was passed in, add 'px' to the (except for certain CSS properties) - if ( typeof value === "number" && !jQuery.cssNumber[ origName ] ) { + if ( type === "number" && !jQuery.cssNumber[ origName ] ) { value += "px"; } @@ -5816,11 +6615,17 @@ jQuery.extend({ }, css: function( elem, name, extra ) { - // Make sure that we're working with the right name - var ret, origName = jQuery.camelCase( name ), - hooks = jQuery.cssHooks[ origName ]; + var ret, hooks; - name = jQuery.cssProps[ origName ] || origName; + // Make sure that we're working with the right name + name = jQuery.camelCase( name ); + hooks = jQuery.cssHooks[ name ]; + name = jQuery.cssProps[ name ] || name; + + // cssFloat needs a special treatment + if ( name === "cssFloat" ) { + name = "float"; + } // If a hook was provided get the computed value from there if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) { @@ -5828,164 +6633,93 @@ jQuery.extend({ // Otherwise, if a way to get the computed value exists, use that } else if ( curCSS ) { - return curCSS( elem, name, origName ); + return curCSS( elem, name ); } }, // A method for quickly swapping in/out CSS properties to get correct calculations swap: function( elem, options, callback ) { - var old = {}; + var old = {}, + ret, name; // Remember the old values, and insert the new ones - for ( var name in options ) { + for ( name in options ) { old[ name ] = elem.style[ name ]; elem.style[ name ] = options[ name ]; } - callback.call( elem ); + ret = callback.call( elem ); // Revert the old values for ( name in options ) { elem.style[ name ] = old[ name ]; } - }, - camelCase: function( string ) { - return string.replace( rdashAlpha, fcamelCase ); + return ret; } }); // DEPRECATED, Use jQuery.css() instead jQuery.curCSS = jQuery.css; -jQuery.each(["height", "width"], function( i, name ) { - jQuery.cssHooks[ name ] = { - get: function( elem, computed, extra ) { - var val; - - if ( computed ) { - if ( elem.offsetWidth !== 0 ) { - val = getWH( elem, name, extra ); - - } else { - jQuery.swap( elem, cssShow, function() { - val = getWH( elem, name, extra ); - }); - } - - if ( val <= 0 ) { - val = curCSS( elem, name, name ); - - if ( val === "0px" && currentStyle ) { - val = currentStyle( elem, name, name ); - } - - if ( val != null ) { - // Should return "auto" instead of 0, use 0 for - // temporary backwards-compat - return val === "" || val === "auto" ? "0px" : val; - } - } - - if ( val < 0 || val == null ) { - val = elem.style[ name ]; - - // Should return "auto" instead of 0, use 0 for - // temporary backwards-compat - return val === "" || val === "auto" ? "0px" : val; - } - - return typeof val === "string" ? val : val + "px"; - } - }, - - set: function( elem, value ) { - if ( rnumpx.test( value ) ) { - // ignore negative width and height values #1599 - value = parseFloat(value); - - if ( value >= 0 ) { - return value + "px"; - } - - } else { - return value; - } - } - }; -}); - -if ( !jQuery.support.opacity ) { - jQuery.cssHooks.opacity = { - get: function( elem, computed ) { - // IE uses filters for opacity - return ropacity.test((computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "") ? - (parseFloat(RegExp.$1) / 100) + "" : - computed ? "1" : ""; - }, - - set: function( elem, value ) { - var style = elem.style; - - // IE has trouble with opacity if it does not have layout - // Force it by setting the zoom level - style.zoom = 1; - - // Set the alpha filter to set the opacity - var opacity = jQuery.isNaN(value) ? - "" : - "alpha(opacity=" + value * 100 + ")", - filter = style.filter || ""; - - style.filter = ralpha.test(filter) ? - filter.replace(ralpha, opacity) : - style.filter + ' ' + opacity; - } - }; -} - if ( document.defaultView && document.defaultView.getComputedStyle ) { - getComputedStyle = function( elem, newName, name ) { - var ret, defaultView, computedStyle; + getComputedStyle = function( elem, name ) { + var ret, defaultView, computedStyle, width, + style = elem.style; name = name.replace( rupper, "-$1" ).toLowerCase(); - if ( !(defaultView = elem.ownerDocument.defaultView) ) { - return undefined; - } + if ( (defaultView = elem.ownerDocument.defaultView) && + (computedStyle = defaultView.getComputedStyle( elem, null )) ) { - if ( (computedStyle = defaultView.getComputedStyle( elem, null )) ) { ret = computedStyle.getPropertyValue( name ); if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) { ret = jQuery.style( elem, name ); } } + // A tribute to the "awesome hack by Dean Edwards" + // WebKit uses "computed value (percentage if specified)" instead of "used value" for margins + // which is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values + if ( !jQuery.support.pixelMargin && computedStyle && rmargin.test( name ) && rnumnonpx.test( ret ) ) { + width = style.width; + style.width = ret; + ret = computedStyle.width; + style.width = width; + } + return ret; }; } if ( document.documentElement.currentStyle ) { currentStyle = function( elem, name ) { - var left, + var left, rsLeft, uncomputed, ret = elem.currentStyle && elem.currentStyle[ name ], - rsLeft = elem.runtimeStyle && elem.runtimeStyle[ name ], style = elem.style; + // Avoid setting ret to empty string here + // so we don't default to auto + if ( ret == null && style && (uncomputed = style[ name ]) ) { + ret = uncomputed; + } + // From the awesome hack by Dean Edwards // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 // If we're not dealing with a regular pixel number // but a number that has a weird ending, we need to convert it to pixels - if ( !rnumpx.test( ret ) && rnum.test( ret ) ) { + if ( rnumnonpx.test( ret ) ) { + // Remember the original values left = style.left; + rsLeft = elem.runtimeStyle && elem.runtimeStyle.left; // Put in the new values to get a computed value out if ( rsLeft ) { elem.runtimeStyle.left = elem.currentStyle.left; } - style.left = name === "fontSize" ? "1em" : (ret || 0); + style.left = name === "fontSize" ? "1em" : ret; ret = style.pixelLeft + "px"; // Revert the changed values @@ -6001,36 +6735,149 @@ if ( document.documentElement.currentStyle ) { curCSS = getComputedStyle || currentStyle; -function getWH( elem, name, extra ) { - var which = name === "width" ? cssWidth : cssHeight, - val = name === "width" ? elem.offsetWidth : elem.offsetHeight; +function getWidthOrHeight( elem, name, extra ) { - if ( extra === "border" ) { + // Start with offset property + var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, + i = name === "width" ? 1 : 0, + len = 4; + + if ( val > 0 ) { + if ( extra !== "border" ) { + for ( ; i < len; i += 2 ) { + if ( !extra ) { + val -= parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0; + } + if ( extra === "margin" ) { + val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ] ) ) || 0; + } else { + val -= parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; + } + } + } + + return val + "px"; + } + + // Fall back to computed then uncomputed css if necessary + val = curCSS( elem, name ); + if ( val < 0 || val == null ) { + val = elem.style[ name ]; + } + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test(val) ) { return val; } - jQuery.each( which, function() { - if ( !extra ) { - val -= parseFloat(jQuery.css( elem, "padding" + this )) || 0; + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + + // Add padding, border, margin + if ( extra ) { + for ( ; i < len; i += 2 ) { + val += parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0; + if ( extra !== "padding" ) { + val += parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; + } + if ( extra === "margin" ) { + val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ]) ) || 0; + } } + } - if ( extra === "margin" ) { - val += parseFloat(jQuery.css( elem, "margin" + this )) || 0; - - } else { - val -= parseFloat(jQuery.css( elem, "border" + this + "Width" )) || 0; - } - }); - - return val; + return val + "px"; } +jQuery.each([ "height", "width" ], function( i, name ) { + jQuery.cssHooks[ name ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + if ( elem.offsetWidth !== 0 ) { + return getWidthOrHeight( elem, name, extra ); + } else { + return jQuery.swap( elem, cssShow, function() { + return getWidthOrHeight( elem, name, extra ); + }); + } + } + }, + + set: function( elem, value ) { + return rnum.test( value ) ? + value + "px" : + value; + } + }; +}); + +if ( !jQuery.support.opacity ) { + jQuery.cssHooks.opacity = { + get: function( elem, computed ) { + // IE uses filters for opacity + return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? + ( parseFloat( RegExp.$1 ) / 100 ) + "" : + computed ? "1" : ""; + }, + + set: function( elem, value ) { + var style = elem.style, + currentStyle = elem.currentStyle, + opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", + filter = currentStyle && currentStyle.filter || style.filter || ""; + + // IE has trouble with opacity if it does not have layout + // Force it by setting the zoom level + style.zoom = 1; + + // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 + if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) { + + // Setting style.filter to null, "" & " " still leave "filter:" in the cssText + // if "filter:" is present at all, clearType is disabled, we want to avoid this + // style.removeAttribute is IE Only, but so apparently is this code path... + style.removeAttribute( "filter" ); + + // if there there is no filter style applied in a css rule, we are done + if ( currentStyle && !currentStyle.filter ) { + return; + } + } + + // otherwise, set new filter values + style.filter = ralpha.test( filter ) ? + filter.replace( ralpha, opacity ) : + filter + " " + opacity; + } + }; +} + +jQuery(function() { + // This hook cannot be added until DOM ready because the support test + // for it is not run until after DOM ready + if ( !jQuery.support.reliableMarginRight ) { + jQuery.cssHooks.marginRight = { + get: function( elem, computed ) { + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + // Work around by temporarily setting element display to inline-block + return jQuery.swap( elem, { "display": "inline-block" }, function() { + if ( computed ) { + return curCSS( elem, "margin-right" ); + } else { + return elem.style.marginRight; + } + }); + } + }; + } +}); + if ( jQuery.expr && jQuery.expr.filters ) { jQuery.expr.filters.hidden = function( elem ) { var width = elem.offsetWidth, height = elem.offsetHeight; - return (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && (elem.style.display || jQuery.css( elem, "display" )) === "none"); + return ( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none"); }; jQuery.expr.filters.visible = function( elem ) { @@ -6038,6 +6885,31 @@ if ( jQuery.expr && jQuery.expr.filters ) { }; } +// These hooks are used by animate to expand properties +jQuery.each({ + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i, + + // assumes a single number if not a string + parts = typeof value === "string" ? value.split(" ") : [ value ], + expanded = {}; + + for ( i = 0; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; +}); + @@ -6046,9 +6918,9 @@ var r20 = /%20/g, rCRLF = /\r?\n/g, rhash = /#.*$/, rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL - rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, + rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /(?:^file|^widget|\-extension):$/, + rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, rnoContent = /^(?:GET|HEAD)$/, rprotocol = /^\/\//, rquery = /\?/, @@ -6056,11 +6928,7 @@ var r20 = /%20/g, rselectTextarea = /^(?:select|textarea)/i, rspacesAjax = /\s+/, rts = /([?&])_=[^&]*/, - rucHeaders = /(^|\-)([a-z])/g, - rucHeadersFunc = function( _, $1, $2 ) { - return $1 + $2.toUpperCase(); - }, - rurl = /^([\w\+\.\-]+:)\/\/([^\/?#:]*)(?::(\d+))?/, + rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/, // Keep a copy of the old load method _load = jQuery.fn.load, @@ -6087,12 +6955,15 @@ var r20 = /%20/g, ajaxLocation, // Document location segments - ajaxLocParts; + ajaxLocParts, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = ["*/"] + ["*"]; // #8138, IE may throw an exception when accessing -// a field from document.location if document.domain has been set +// a field from window.location if document.domain has been set try { - ajaxLocation = document.location.href; + ajaxLocation = location.href; } catch( e ) { // Use the href attribute of an A element // since IE will modify it given document.location @@ -6102,7 +6973,7 @@ try { } // Segment location into parts -ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ); +ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport function addToPrefiltersOrTransports( structure ) { @@ -6124,7 +6995,7 @@ function addToPrefiltersOrTransports( structure ) { placeBefore; // For each dataType in the dataTypeExpression - for(; i < length; i++ ) { + for ( ; i < length; i++ ) { dataType = dataTypes[ i ]; // We control if we're asked to add before // any existing element @@ -6140,7 +7011,7 @@ function addToPrefiltersOrTransports( structure ) { }; } -//Base inspection function for prefilters and transports +// Base inspection function for prefilters and transports function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR, dataType /* internal */, inspected /* internal */ ) { @@ -6155,7 +7026,7 @@ function inspectPrefiltersOrTransports( structure, options, originalOptions, jqX executeOnly = ( structure === prefilters ), selection; - for(; i < length && ( executeOnly || !selection ); i++ ) { + for ( ; i < length && ( executeOnly || !selection ); i++ ) { selection = list[ i ]( options, originalOptions, jqXHR ); // If we got redirected to another dataType // we try there if executing only and not done already @@ -6180,6 +7051,22 @@ function inspectPrefiltersOrTransports( structure, options, originalOptions, jqX return selection; } +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } +} + jQuery.fn.extend({ load: function( url, params, callback ) { if ( typeof url !== "string" && _load ) { @@ -6287,9 +7174,9 @@ jQuery.fn.extend({ // Attach a bunch of functions for handling common AJAX events jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){ jQuery.fn[ o ] = function( f ){ - return this.bind( o, f ); + return this.on( o, f ); }; -} ); +}); jQuery.each( [ "get", "post" ], function( i, method ) { jQuery[ method ] = function( url, data, callback, type ) { @@ -6308,7 +7195,7 @@ jQuery.each( [ "get", "post" ], function( i, method ) { dataType: type }); }; -} ); +}); jQuery.extend({ @@ -6323,23 +7210,16 @@ jQuery.extend({ // Creates a full fledged settings object into target // with both ajaxSettings and settings fields. // If target is omitted, writes into ajaxSettings. - ajaxSetup: function ( target, settings ) { - if ( !settings ) { - // Only one parameter, we extend ajaxSettings - settings = target; - target = jQuery.extend( true, jQuery.ajaxSettings, settings ); + ajaxSetup: function( target, settings ) { + if ( settings ) { + // Building a settings object + ajaxExtend( target, jQuery.ajaxSettings ); } else { - // target was provided, we extend into it - jQuery.extend( true, target, jQuery.ajaxSettings, settings ); - } - // Flatten fields we don't want deep extended - for( var field in { context: 1, url: 1 } ) { - if ( field in settings ) { - target[ field ] = settings[ field ]; - } else if( field in jQuery.ajaxSettings ) { - target[ field ] = jQuery.ajaxSettings[ field ]; - } + // Extending ajaxSettings + settings = target; + target = jQuery.ajaxSettings; } + ajaxExtend( target, settings ); return target; }, @@ -6360,7 +7240,6 @@ jQuery.extend({ cache: null, traditional: false, headers: {}, - crossDomain: null, */ accepts: { @@ -6368,7 +7247,7 @@ jQuery.extend({ html: "text/html", text: "text/plain", json: "application/json, text/javascript", - "*": "*/*" + "*": allTypes }, contents: { @@ -6398,6 +7277,15 @@ jQuery.extend({ // Parse text as xml "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + context: true, + url: true } }, @@ -6428,13 +7316,14 @@ jQuery.extend({ jQuery( callbackContext ) : jQuery.event, // Deferreds deferred = jQuery.Deferred(), - completeDeferred = jQuery._Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), // Status-dependent callbacks statusCode = s.statusCode || {}, // ifModified key ifModifiedKey, // Headers (they are sent all at once) requestHeaders = {}, + requestHeadersNames = {}, // Response headers responseHeadersString, responseHeaders, @@ -6458,7 +7347,9 @@ jQuery.extend({ // Caches the header setRequestHeader: function( name, value ) { if ( !state ) { - requestHeaders[ name.toLowerCase().replace( rucHeaders, rucHeadersFunc ) ] = value; + var lname = name.toLowerCase(); + name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; + requestHeaders[ name ] = value; } return this; }, @@ -6505,7 +7396,7 @@ jQuery.extend({ // Callback for when everything is done // It is defined here because jslint complains if it is declared // at the end of the function (which would be more logical and readable) - function done( status, statusText, responses, headers ) { + function done( status, nativeStatusText, responses, headers ) { // Called once if ( state === 2 ) { @@ -6528,11 +7419,12 @@ jQuery.extend({ responseHeadersString = headers || ""; // Set readyState - jqXHR.readyState = status ? 4 : 0; + jqXHR.readyState = status > 0 ? 4 : 0; var isSuccess, success, error, + statusText = nativeStatusText, response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined, lastModified, etag; @@ -6574,7 +7466,7 @@ jQuery.extend({ // We extract error from statusText // then normalize statusText and status for non-aborts error = statusText; - if( !statusText || status ) { + if ( !statusText || status ) { statusText = "error"; if ( status < 0 ) { status = 0; @@ -6584,7 +7476,7 @@ jQuery.extend({ // Set data for the fake xhr object jqXHR.status = status; - jqXHR.statusText = statusText; + jqXHR.statusText = "" + ( nativeStatusText || statusText ); // Success/Error if ( isSuccess ) { @@ -6603,10 +7495,10 @@ jQuery.extend({ } // Complete - completeDeferred.resolveWith( callbackContext, [ jqXHR, statusText ] ); + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s] ); + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); // Handle the global AJAX counter if ( !( --jQuery.active ) ) { jQuery.event.trigger( "ajaxStop" ); @@ -6618,14 +7510,14 @@ jQuery.extend({ deferred.promise( jqXHR ); jqXHR.success = jqXHR.done; jqXHR.error = jqXHR.fail; - jqXHR.complete = completeDeferred.done; + jqXHR.complete = completeDeferred.add; // Status-dependent callbacks jqXHR.statusCode = function( map ) { if ( map ) { var tmp; if ( state < 2 ) { - for( tmp in map ) { + for ( tmp in map ) { statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ]; } } else { @@ -6645,7 +7537,7 @@ jQuery.extend({ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax ); // Determine if a cross-domain request is in order - if ( !s.crossDomain ) { + if ( s.crossDomain == null ) { parts = rurl.exec( s.url.toLowerCase() ); s.crossDomain = !!( parts && ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] || @@ -6662,7 +7554,7 @@ jQuery.extend({ // Apply prefilters inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - // If request was aborted inside a prefiler, stop there + // If request was aborted inside a prefilter, stop there if ( state === 2 ) { return false; } @@ -6687,6 +7579,8 @@ jQuery.extend({ // If data is available, append data to url if ( s.data ) { s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data; + // #9682: remove data so that it's not used in an eventual retry + delete s.data; } // Get ifModifiedKey before adding the anti-cache parameter @@ -6700,30 +7594,33 @@ jQuery.extend({ ret = s.url.replace( rts, "$1_=" + ts ); // if nothing was replaced, add timestamp to the end - s.url = ret + ( (ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" ); + s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" ); } } // Set the correct header, if data is being sent if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - requestHeaders[ "Content-Type" ] = s.contentType; + jqXHR.setRequestHeader( "Content-Type", s.contentType ); } // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. if ( s.ifModified ) { ifModifiedKey = ifModifiedKey || s.url; if ( jQuery.lastModified[ ifModifiedKey ] ) { - requestHeaders[ "If-Modified-Since" ] = jQuery.lastModified[ ifModifiedKey ]; + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] ); } if ( jQuery.etag[ ifModifiedKey ] ) { - requestHeaders[ "If-None-Match" ] = jQuery.etag[ ifModifiedKey ]; + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] ); } } // Set the Accepts header for the server, depending on the dataType - requestHeaders.Accept = s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? - s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) : - s.accepts[ "*" ]; + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? + s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); // Check for headers option for ( i in s.headers ) { @@ -6767,11 +7664,11 @@ jQuery.extend({ transport.send( requestHeaders, done ); } catch (e) { // Propagate exception as error if not done - if ( status < 2 ) { + if ( state < 2 ) { done( -1, e ); // Simply rethrow otherwise } else { - jQuery.error( e ); + throw e; } } } @@ -6799,7 +7696,7 @@ jQuery.extend({ // Serialize the form elements jQuery.each( a, function() { add( this.name, this.value ); - } ); + }); } else { // If traditional, encode the "old" way (the way 1.3.2 or older @@ -6815,7 +7712,7 @@ jQuery.extend({ }); function buildParams( prefix, obj, traditional, add ) { - if ( jQuery.isArray( obj ) && obj.length ) { + if ( jQuery.isArray( obj ) ) { // Serialize array item. jQuery.each( obj, function( i, v ) { if ( traditional || rbracket.test( prefix ) ) { @@ -6830,21 +7727,14 @@ function buildParams( prefix, obj, traditional, add ) { // a server error. Possible fixes are to modify rack's // deserialization algorithm or to provide an option or flag // to force array serialization to be shallow. - buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v, traditional, add ); + buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); } }); - } else if ( !traditional && obj != null && typeof obj === "object" ) { - // If we see an array here, it is empty and should be treated as an empty - // object - if ( jQuery.isArray( obj ) || jQuery.isEmptyObject( obj ) ) { - add( prefix, "" ); - + } else if ( !traditional && jQuery.type( obj ) === "object" ) { // Serialize object item. - } else { - for ( var name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } + for ( var name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); } } else { @@ -6882,7 +7772,7 @@ function ajaxHandleResponses( s, jqXHR, responses ) { firstDataType; // Fill responseXXX fields - for( type in responseFields ) { + for ( type in responseFields ) { if ( type in responses ) { jqXHR[ responseFields[type] ] = responses[ type ]; } @@ -6961,13 +7851,13 @@ function ajaxConvert( s, response ) { conv2; // For each dataType in the chain - for( i = 1; i < length; i++ ) { + for ( i = 1; i < length; i++ ) { // Create converters map // with lowercased keys if ( i === 1 ) { - for( key in s.converters ) { - if( typeof key === "string" ) { + for ( key in s.converters ) { + if ( typeof key === "string" ) { converters[ key.toLowerCase() ] = s.converters[ key ]; } } @@ -6978,7 +7868,7 @@ function ajaxConvert( s, response ) { current = dataTypes[ i ]; // If current is auto dataType, update it to prev - if( current === "*" ) { + if ( current === "*" ) { current = prev; // If no auto and dataTypes are actually different } else if ( prev !== "*" && prev !== current ) { @@ -6990,7 +7880,7 @@ function ajaxConvert( s, response ) { // If there is no direct converter, search transitively if ( !conv ) { conv2 = undefined; - for( conv1 in converters ) { + for ( conv1 in converters ) { tmp = conv1.split( " " ); if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) { conv2 = converters[ tmp[1] + " " + current ]; @@ -7024,7 +7914,7 @@ function ajaxConvert( s, response ) { var jsc = jQuery.now(), - jsre = /(\=)\?(&|$)|()\?\?()/i; + jsre = /(\=)\?(&|$)|\?\?/i; // Default jsonp settings jQuery.ajaxSetup({ @@ -7037,13 +7927,12 @@ jQuery.ajaxSetup({ // Detect, normalize options and install callbacks for jsonp requests jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { - var dataIsString = ( typeof s.data === "string" ); + var inspectData = s.contentType === "application/x-www-form-urlencoded" && + ( typeof s.data === "string" ); if ( s.dataTypes[ 0 ] === "jsonp" || - originalSettings.jsonpCallback || - originalSettings.jsonp != null || s.jsonp !== false && ( jsre.test( s.url ) || - dataIsString && jsre.test( s.data ) ) ) { + inspectData && jsre.test( s.data ) ) ) { var responseContainer, jsonpCallback = s.jsonpCallback = @@ -7051,20 +7940,12 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { previous = window[ jsonpCallback ], url = s.url, data = s.data, - replace = "$1" + jsonpCallback + "$2", - cleanUp = function() { - // Set callback back to previous value - window[ jsonpCallback ] = previous; - // Call if it was a function and we have a response - if ( responseContainer && jQuery.isFunction( previous ) ) { - window[ jsonpCallback ]( responseContainer[ 0 ] ); - } - }; + replace = "$1" + jsonpCallback + "$2"; if ( s.jsonp !== false ) { url = url.replace( jsre, replace ); if ( s.url === url ) { - if ( dataIsString ) { + if ( inspectData ) { data = data.replace( jsre, replace ); } if ( s.data === data ) { @@ -7082,8 +7963,15 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { responseContainer = [ response ]; }; - // Install cleanUp function - jqXHR.then( cleanUp, cleanUp ); + // Clean-up function + jqXHR.always(function() { + // Set callback back to previous value + window[ jsonpCallback ] = previous; + // Call if it was a function and we have a response + if ( responseContainer && jQuery.isFunction( previous ) ) { + window[ jsonpCallback ]( responseContainer[ 0 ] ); + } + }); // Use data converter to retrieve json after script execution s.converters["script json"] = function() { @@ -7099,7 +7987,7 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { // Delegate to script return "script"; } -} ); +}); @@ -7129,7 +8017,7 @@ jQuery.ajaxPrefilter( "script", function( s ) { s.type = "GET"; s.global = false; } -} ); +}); // Bind script tag hack transport jQuery.ajaxTransport( "script", function(s) { @@ -7157,7 +8045,7 @@ jQuery.ajaxTransport( "script", function(s) { // Attach handlers for all browsers script.onload = script.onreadystatechange = function( _, isAbort ) { - if ( !script.readyState || /loaded|complete/.test( script.readyState ) ) { + if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { // Handle memory leak in IE script.onload = script.onreadystatechange = null; @@ -7188,27 +8076,20 @@ jQuery.ajaxTransport( "script", function(s) { } }; } -} ); +}); -var // #5280: next active xhr id and list of active xhrs' callbacks - xhrId = jQuery.now(), - xhrCallbacks, - - // XHR used to determine supports properties - testXHR; - -// #5280: Internet Explorer will keep connections alive if we don't abort on unload -function xhrOnUnloadAbort() { - jQuery( window ).unload(function() { +var // #5280: Internet Explorer will keep connections alive if we don't abort on unload + xhrOnUnloadAbort = window.ActiveXObject ? function() { // Abort all pending requests for ( var key in xhrCallbacks ) { xhrCallbacks[ key ]( 0, 1 ); } - }); -} + } : false, + xhrId = 0, + xhrCallbacks; // Functions to create xhrs function createStandardXHR() { @@ -7238,15 +8119,13 @@ jQuery.ajaxSettings.xhr = window.ActiveXObject ? // For all other browsers, use the standard XMLHttpRequest object createStandardXHR; -// Test if we can create an xhr object -testXHR = jQuery.ajaxSettings.xhr(); -jQuery.support.ajax = !!testXHR; - -// Does this browser support crossDomain XHR requests -jQuery.support.cors = testXHR && ( "withCredentials" in testXHR ); - -// No need for the temporary xhr anymore -testXHR = undefined; +// Determine support properties +(function( xhr ) { + jQuery.extend( jQuery.support, { + ajax: !!xhr, + cors: !!xhr && ( "withCredentials" in xhr ) + }); +})( jQuery.ajaxSettings.xhr() ); // Create transport if the browser can provide an xhr if ( jQuery.support.ajax ) { @@ -7285,11 +8164,12 @@ if ( jQuery.support.ajax ) { xhr.overrideMimeType( s.mimeType ); } - // Requested-With header - // Not set for crossDomain requests with no content - // (see why at http://trac.dojotoolkit.org/ticket/9486) - // Won't change header if already provided - if ( !( s.crossDomain && !s.hasContent ) && !headers["X-Requested-With"] ) { + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !s.crossDomain && !headers["X-Requested-With"] ) { headers[ "X-Requested-With" ] = "XMLHttpRequest"; } @@ -7328,7 +8208,9 @@ if ( jQuery.support.ajax ) { // Do not keep as active anymore if ( handle ) { xhr.onreadystatechange = jQuery.noop; - delete xhrCallbacks[ handle ]; + if ( xhrOnUnloadAbort ) { + delete xhrCallbacks[ handle ]; + } } // If it's an abort @@ -7389,15 +8271,18 @@ if ( jQuery.support.ajax ) { if ( !s.async || xhr.readyState === 4 ) { callback(); } else { - // Create the active xhrs callbacks list if needed - // and attach the unload handler - if ( !xhrCallbacks ) { - xhrCallbacks = {}; - xhrOnUnloadAbort(); + handle = ++xhrId; + if ( xhrOnUnloadAbort ) { + // Create the active xhrs callbacks list if needed + // and attach the unload handler + if ( !xhrCallbacks ) { + xhrCallbacks = {}; + jQuery( window ).unload( xhrOnUnloadAbort ); + } + // Add to list of active xhrs callbacks + xhrCallbacks[ handle ] = callback; } - // Add to list of active xhrs callbacks - handle = xhrId++; - xhr.onreadystatechange = xhrCallbacks[ handle ] = callback; + xhr.onreadystatechange = callback; } }, @@ -7415,6 +8300,7 @@ if ( jQuery.support.ajax ) { var elemdisplay = {}, + iframe, iframeDoc, rfxtypes = /^(?:toggle|show|hide)$/, rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i, timerId, @@ -7425,42 +8311,50 @@ var elemdisplay = {}, [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ], // opacity animations [ "opacity" ] - ]; + ], + fxNow; jQuery.fn.extend({ show: function( speed, easing, callback ) { var elem, display; if ( speed || speed === 0 ) { - return this.animate( genFx("show", 3), speed, easing, callback); + return this.animate( genFx("show", 3), speed, easing, callback ); } else { for ( var i = 0, j = this.length; i < j; i++ ) { - elem = this[i]; - display = elem.style.display; + elem = this[ i ]; - // Reset the inline display of this element to learn if it is - // being hidden by cascaded rules or not - if ( !jQuery._data(elem, "olddisplay") && display === "none" ) { - display = elem.style.display = ""; - } + if ( elem.style ) { + display = elem.style.display; - // Set elements which have been overridden with display: none - // in a stylesheet to whatever the default browser style is - // for such an element - if ( display === "" && jQuery.css( elem, "display" ) === "none" ) { - jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName)); + // Reset the inline display of this element to learn if it is + // being hidden by cascaded rules or not + if ( !jQuery._data(elem, "olddisplay") && display === "none" ) { + display = elem.style.display = ""; + } + + // Set elements which have been overridden with display: none + // in a stylesheet to whatever the default browser style is + // for such an element + if ( (display === "" && jQuery.css(elem, "display") === "none") || + !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) { + jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) ); + } } } // Set the display of most of the elements in a second loop // to avoid the constant reflow for ( i = 0; i < j; i++ ) { - elem = this[i]; - display = elem.style.display; + elem = this[ i ]; - if ( display === "" || display === "none" ) { - elem.style.display = jQuery._data(elem, "olddisplay") || ""; + if ( elem.style ) { + display = elem.style.display; + + if ( display === "" || display === "none" ) { + elem.style.display = jQuery._data( elem, "olddisplay" ) || ""; + } } } @@ -7473,18 +8367,27 @@ jQuery.fn.extend({ return this.animate( genFx("hide", 3), speed, easing, callback); } else { - for ( var i = 0, j = this.length; i < j; i++ ) { - var display = jQuery.css( this[i], "display" ); + var elem, display, + i = 0, + j = this.length; - if ( display !== "none" && !jQuery._data( this[i], "olddisplay" ) ) { - jQuery._data( this[i], "olddisplay", display ); + for ( ; i < j; i++ ) { + elem = this[i]; + if ( elem.style ) { + display = jQuery.css( elem, "display" ); + + if ( display !== "none" && !jQuery._data( elem, "olddisplay" ) ) { + jQuery._data( elem, "olddisplay", display ); + } } } // Set the display of the elements in a second loop // to avoid the constant reflow for ( i = 0; i < j; i++ ) { - this[i].style.display = "none"; + if ( this[i].style ) { + this[i].style.display = "none"; + } } return this; @@ -7519,35 +8422,70 @@ jQuery.fn.extend({ }, animate: function( prop, speed, easing, callback ) { - var optall = jQuery.speed(speed, easing, callback); + var optall = jQuery.speed( speed, easing, callback ); if ( jQuery.isEmptyObject( prop ) ) { - return this.each( optall.complete ); + return this.each( optall.complete, [ false ] ); } - return this[ optall.queue === false ? "each" : "queue" ](function() { + // Do not change referenced properties as per-property easing will be lost + prop = jQuery.extend( {}, prop ); + + function doAnimation() { // XXX 'this' does not always have a nodeName when running the // test suite - var opt = jQuery.extend({}, optall), p, + if ( optall.queue === false ) { + jQuery._mark( this ); + } + + var opt = jQuery.extend( {}, optall ), isElement = this.nodeType === 1, hidden = isElement && jQuery(this).is(":hidden"), - self = this; + name, val, p, e, hooks, replace, + parts, start, end, unit, + method; + // will store per property easing and be used to determine when an animation is complete + opt.animatedProperties = {}; + + // first pass over propertys to expand / normalize for ( p in prop ) { - var name = jQuery.camelCase( p ); - + name = jQuery.camelCase( p ); if ( p !== name ) { prop[ name ] = prop[ p ]; delete prop[ p ]; - p = name; + } + + if ( ( hooks = jQuery.cssHooks[ name ] ) && "expand" in hooks ) { + replace = hooks.expand( prop[ name ] ); + delete prop[ name ]; + + // not quite $.extend, this wont overwrite keys already present. + // also - reusing 'p' from above because we have the correct "name" + for ( p in replace ) { + if ( ! ( p in prop ) ) { + prop[ p ] = replace[ p ]; + } + } + } + } + + for ( name in prop ) { + val = prop[ name ]; + // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default) + if ( jQuery.isArray( val ) ) { + opt.animatedProperties[ name ] = val[ 1 ]; + val = prop[ name ] = val[ 0 ]; + } else { + opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing'; } - if ( prop[p] === "hide" && hidden || prop[p] === "show" && !hidden ) { - return opt.complete.call(this); + if ( val === "hide" && hidden || val === "show" && !hidden ) { + return opt.complete.call( this ); } - if ( isElement && ( p === "height" || p === "width" ) ) { + if ( isElement && ( name === "height" || name === "width" ) ) { // Make sure that nothing sneaks out // Record all 3 overflow attributes because IE does not // change the overflow attribute when overflowX and @@ -7555,66 +8493,60 @@ jQuery.fn.extend({ opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ]; // Set display property to inline-block for height/width - // animations on inline elements that are having width/height - // animated + // animations on inline elements that are having width/height animated if ( jQuery.css( this, "display" ) === "inline" && jQuery.css( this, "float" ) === "none" ) { - if ( !jQuery.support.inlineBlockNeedsLayout ) { + + // inline-level elements accept inline-block; + // block-level elements need to be inline with layout + if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( this.nodeName ) === "inline" ) { this.style.display = "inline-block"; } else { - var display = defaultDisplay(this.nodeName); - - // inline-level elements accept inline-block; - // block-level elements need to be inline with layout - if ( display === "inline" ) { - this.style.display = "inline-block"; - - } else { - this.style.display = "inline"; - this.style.zoom = 1; - } + this.style.zoom = 1; } } } - - if ( jQuery.isArray( prop[p] ) ) { - // Create (if needed) and add to specialEasing - (opt.specialEasing = opt.specialEasing || {})[p] = prop[p][1]; - prop[p] = prop[p][0]; - } } if ( opt.overflow != null ) { this.style.overflow = "hidden"; } - opt.curAnim = jQuery.extend({}, prop); + for ( p in prop ) { + e = new jQuery.fx( this, opt, p ); + val = prop[ p ]; - jQuery.each( prop, function( name, val ) { - var e = new jQuery.fx( self, opt, name ); + if ( rfxtypes.test( val ) ) { - if ( rfxtypes.test(val) ) { - e[ val === "toggle" ? hidden ? "show" : "hide" : val ]( prop ); + // Tracks whether to show or hide based on private + // data attached to the element + method = jQuery._data( this, "toggle" + p ) || ( val === "toggle" ? hidden ? "show" : "hide" : 0 ); + if ( method ) { + jQuery._data( this, "toggle" + p, method === "show" ? "hide" : "show" ); + e[ method ](); + } else { + e[ val ](); + } } else { - var parts = rfxnum.exec(val), - start = e.cur(); + parts = rfxnum.exec( val ); + start = e.cur(); if ( parts ) { - var end = parseFloat( parts[2] ), - unit = parts[3] || ( jQuery.cssNumber[ name ] ? "" : "px" ); + end = parseFloat( parts[2] ); + unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" ); // We need to compute starting value if ( unit !== "px" ) { - jQuery.style( self, name, (end || 1) + unit); - start = ((end || 1) / e.cur()) * start; - jQuery.style( self, name, start + unit); + jQuery.style( this, p, (end || 1) + unit); + start = ( (end || 1) / e.cur() ) * start; + jQuery.style( this, p, start + unit); } // If a +=/-= token was provided, we're doing a relative animation if ( parts[1] ) { - end = ((parts[1] === "-=" ? -1 : 1) * end) + start; + end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start; } e.custom( start, end, unit ); @@ -7623,48 +8555,94 @@ jQuery.fn.extend({ e.custom( start, val, "" ); } } - }); + } // For JS strict compliance return true; - }); + } + + return optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); }, - stop: function( clearQueue, gotoEnd ) { - var timers = jQuery.timers; - - if ( clearQueue ) { - this.queue([]); + stop: function( type, clearQueue, gotoEnd ) { + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); } - this.each(function() { - // go in reverse order so anything added to the queue during the loop is ignored - for ( var i = timers.length - 1; i >= 0; i-- ) { - if ( timers[i].elem === this ) { - if (gotoEnd) { - // force the next step to be the last - timers[i](true); - } + return this.each(function() { + var index, + hadTimers = false, + timers = jQuery.timers, + data = jQuery._data( this ); - timers.splice(i, 1); + // clear marker counters if we know they won't be + if ( !gotoEnd ) { + jQuery._unmark( true, this ); + } + + function stopQueue( elem, data, index ) { + var hooks = data[ index ]; + jQuery.removeData( elem, index, true ); + hooks.stop( gotoEnd ); + } + + if ( type == null ) { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && index.indexOf(".run") === index.length - 4 ) { + stopQueue( this, data, index ); + } + } + } else if ( data[ index = type + ".run" ] && data[ index ].stop ){ + stopQueue( this, data, index ); + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) { + if ( gotoEnd ) { + + // force the next step to be the last + timers[ index ]( true ); + } else { + timers[ index ].saveState(); + } + hadTimers = true; + timers.splice( index, 1 ); } } + + // start the next in the queue if the last step wasn't forced + // timers currently will call their complete callbacks, which will dequeue + // but only if they were gotoEnd + if ( !( gotoEnd && hadTimers ) ) { + jQuery.dequeue( this, type ); + } }); - - // start the next in the queue if the last step wasn't forced - if ( !gotoEnd ) { - this.dequeue(); - } - - return this; } }); +// Animations created synchronously will run synchronously +function createFxNow() { + setTimeout( clearFxNow, 0 ); + return ( fxNow = jQuery.now() ); +} + +function clearFxNow() { + fxNow = undefined; +} + +// Generate parameters to create a standard animation function genFx( type, num ) { var obj = {}; - jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() { + jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() { obj[ this ] = type; }); @@ -7673,9 +8651,9 @@ function genFx( type, num ) { // Generate shortcuts for custom animations jQuery.each({ - slideDown: genFx("show", 1), - slideUp: genFx("hide", 1), - slideToggle: genFx("toggle", 1), + slideDown: genFx( "show", 1 ), + slideUp: genFx( "hide", 1 ), + slideToggle: genFx( "toggle", 1 ), fadeIn: { opacity: "show" }, fadeOut: { opacity: "hide" }, fadeToggle: { opacity: "toggle" } @@ -7687,25 +8665,34 @@ jQuery.each({ jQuery.extend({ speed: function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { complete: fn || !fn && easing || jQuery.isFunction( speed ) && speed, duration: speed, - easing: fn && easing || easing && !jQuery.isFunction(easing) && easing + easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing }; opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : - opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[opt.duration] : jQuery.fx.speeds._default; + opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; + + // normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } // Queueing opt.old = opt.complete; - opt.complete = function() { - if ( opt.queue !== false ) { - jQuery(this).dequeue(); - } + + opt.complete = function( noUnmark ) { if ( jQuery.isFunction( opt.old ) ) { opt.old.call( this ); } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } else if ( noUnmark !== false ) { + jQuery._unmark( this ); + } }; return opt; @@ -7716,7 +8703,7 @@ jQuery.extend({ return firstNum + diff * p; }, swing: function( p, n, firstNum, diff ) { - return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum; + return ( ( -Math.cos( p*Math.PI ) / 2 ) + 0.5 ) * diff + firstNum; } }, @@ -7727,9 +8714,7 @@ jQuery.extend({ this.elem = elem; this.prop = prop; - if ( !options.orig ) { - options.orig = {}; - } + options.orig = options.orig || {}; } }); @@ -7741,12 +8726,12 @@ jQuery.fx.prototype = { this.options.step.call( this.elem, this.now, this ); } - (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this ); + ( jQuery.fx.step[ this.prop ] || jQuery.fx.step._default )( this ); }, // Get the current size cur: function() { - if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) { + if ( this.elem[ this.prop ] != null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) { return this.elem[ this.prop ]; } @@ -7763,34 +8748,49 @@ jQuery.fx.prototype = { var self = this, fx = jQuery.fx; - this.startTime = jQuery.now(); - this.start = from; + this.startTime = fxNow || createFxNow(); this.end = to; - this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" ); - this.now = this.start; + this.now = this.start = from; this.pos = this.state = 0; + this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" ); function t( gotoEnd ) { - return self.step(gotoEnd); + return self.step( gotoEnd ); } + t.queue = this.options.queue; t.elem = this.elem; + t.saveState = function() { + if ( jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) { + if ( self.options.hide ) { + jQuery._data( self.elem, "fxshow" + self.prop, self.start ); + } else if ( self.options.show ) { + jQuery._data( self.elem, "fxshow" + self.prop, self.end ); + } + } + }; if ( t() && jQuery.timers.push(t) && !timerId ) { - timerId = setInterval(fx.tick, fx.interval); + timerId = setInterval( fx.tick, fx.interval ); } }, // Simple 'show' function show: function() { + var dataShow = jQuery._data( this.elem, "fxshow" + this.prop ); + // Remember where we started, so that we can go back to it later - this.options.orig[this.prop] = jQuery.style( this.elem, this.prop ); + this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop ); this.options.show = true; // Begin the animation - // Make sure that we start at a small width/height to avoid any - // flash of content - this.custom(this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur()); + // Make sure that we start at a small width/height to avoid any flash of content + if ( dataShow !== undefined ) { + // This show is picking up where a previous hide or show left off + this.custom( this.cur(), dataShow ); + } else { + this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() ); + } // Start by showing the element jQuery( this.elem ).show(); @@ -7799,69 +8799,84 @@ jQuery.fx.prototype = { // Simple 'hide' function hide: function() { // Remember where we started, so that we can go back to it later - this.options.orig[this.prop] = jQuery.style( this.elem, this.prop ); + this.options.orig[ this.prop ] = jQuery._data( this.elem, "fxshow" + this.prop ) || jQuery.style( this.elem, this.prop ); this.options.hide = true; // Begin the animation - this.custom(this.cur(), 0); + this.custom( this.cur(), 0 ); }, // Each step of an animation step: function( gotoEnd ) { - var t = jQuery.now(), done = true; + var p, n, complete, + t = fxNow || createFxNow(), + done = true, + elem = this.elem, + options = this.options; - if ( gotoEnd || t >= this.options.duration + this.startTime ) { + if ( gotoEnd || t >= options.duration + this.startTime ) { this.now = this.end; this.pos = this.state = 1; this.update(); - this.options.curAnim[ this.prop ] = true; + options.animatedProperties[ this.prop ] = true; - for ( var i in this.options.curAnim ) { - if ( this.options.curAnim[i] !== true ) { + for ( p in options.animatedProperties ) { + if ( options.animatedProperties[ p ] !== true ) { done = false; } } if ( done ) { // Reset the overflow - if ( this.options.overflow != null && !jQuery.support.shrinkWrapBlocks ) { - var elem = this.elem, - options = this.options; + if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) { - jQuery.each( [ "", "X", "Y" ], function (index, value) { - elem.style[ "overflow" + value ] = options.overflow[index]; - } ); + jQuery.each( [ "", "X", "Y" ], function( index, value ) { + elem.style[ "overflow" + value ] = options.overflow[ index ]; + }); } // Hide the element if the "hide" operation was done - if ( this.options.hide ) { - jQuery(this.elem).hide(); + if ( options.hide ) { + jQuery( elem ).hide(); } // Reset the properties, if the item has been hidden or shown - if ( this.options.hide || this.options.show ) { - for ( var p in this.options.curAnim ) { - jQuery.style( this.elem, p, this.options.orig[p] ); + if ( options.hide || options.show ) { + for ( p in options.animatedProperties ) { + jQuery.style( elem, p, options.orig[ p ] ); + jQuery.removeData( elem, "fxshow" + p, true ); + // Toggle data is no longer needed + jQuery.removeData( elem, "toggle" + p, true ); } } // Execute the complete function - this.options.complete.call( this.elem ); + // in the event that the complete function throws an exception + // we must ensure it won't be called twice. #5684 + + complete = options.complete; + if ( complete ) { + + options.complete = false; + complete.call( elem ); + } } return false; } else { - var n = t - this.startTime; - this.state = n / this.options.duration; - - // Perform the easing function, defaults to swing - var specialEasing = this.options.specialEasing && this.options.specialEasing[this.prop]; - var defaultEasing = this.options.easing || (jQuery.easing.swing ? "swing" : "linear"); - this.pos = jQuery.easing[specialEasing || defaultEasing](this.state, n, 0, 1, this.options.duration); - this.now = this.start + ((this.end - this.start) * this.pos); + // classical easing cannot be used with an Infinity duration + if ( options.duration == Infinity ) { + this.now = t; + } else { + n = t - this.startTime; + this.state = n / options.duration; + // Perform the easing function, defaults to swing + this.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration ); + this.now = this.start + ( (this.end - this.start) * this.pos ); + } // Perform the next step of the animation this.update(); } @@ -7872,11 +8887,15 @@ jQuery.fx.prototype = { jQuery.extend( jQuery.fx, { tick: function() { - var timers = jQuery.timers; + var timer, + timers = jQuery.timers, + i = 0; - for ( var i = 0; i < timers.length; i++ ) { - if ( !timers[i]() ) { - timers.splice(i--, 1); + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + // Checks the timer has not already been removed + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); } } @@ -7906,7 +8925,7 @@ jQuery.extend( jQuery.fx, { _default: function( fx ) { if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) { - fx.elem.style[ fx.prop ] = (fx.prop === "width" || fx.prop === "height" ? Math.max(0, fx.now) : fx.now) + fx.unit; + fx.elem.style[ fx.prop ] = fx.now + fx.unit; } else { fx.elem[ fx.prop ] = fx.now; } @@ -7914,6 +8933,14 @@ jQuery.extend( jQuery.fx, { } }); +// Adds width/height step functions +// Do not set anything below 0 +jQuery.each([ "width", "height" ], function( i, prop ) { + jQuery.fx.step[ prop ] = function( fx ) { + jQuery.style( fx.elem, prop, Math.max(0, fx.now) + fx.unit ); + }; +}); + if ( jQuery.expr && jQuery.expr.filters ) { jQuery.expr.filters.animated = function( elem ) { return jQuery.grep(jQuery.timers, function( fn ) { @@ -7922,17 +8949,45 @@ if ( jQuery.expr && jQuery.expr.filters ) { }; } +// Try to restore the default display value of an element function defaultDisplay( nodeName ) { - if ( !elemdisplay[ nodeName ] ) { - var elem = jQuery("<" + nodeName + ">").appendTo("body"), - display = elem.css("display"); + if ( !elemdisplay[ nodeName ] ) { + + var body = document.body, + elem = jQuery( "<" + nodeName + ">" ).appendTo( body ), + display = elem.css( "display" ); elem.remove(); + // If the simple way fails, + // get element's real default display by attaching it to a temp iframe if ( display === "none" || display === "" ) { - display = "block"; + // No iframe to use yet, so create it + if ( !iframe ) { + iframe = document.createElement( "iframe" ); + iframe.frameBorder = iframe.width = iframe.height = 0; + } + + body.appendChild( iframe ); + + // Create a cacheable copy of the iframe document on first call. + // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML + // document to it; WebKit & Firefox won't allow reusing the iframe document. + if ( !iframeDoc || !iframe.createElement ) { + iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; + iframeDoc.write( ( document.compatMode === "CSS1Compat" ? "" : "" ) + "" ); + iframeDoc.close(); + } + + elem = iframeDoc.createElement( nodeName ); + + iframeDoc.body.appendChild( elem ); + + display = jQuery.css( elem, "display" ); + body.removeChild( iframe ); } + // Store the correct default display elemdisplay[ nodeName ] = display; } @@ -7942,45 +8997,27 @@ function defaultDisplay( nodeName ) { -var rtable = /^t(?:able|d|h)$/i, +var getOffset, + rtable = /^t(?:able|d|h)$/i, rroot = /^(?:body|html)$/i; if ( "getBoundingClientRect" in document.documentElement ) { - jQuery.fn.offset = function( options ) { - var elem = this[0], box; - - if ( options ) { - return this.each(function( i ) { - jQuery.offset.setOffset( this, options, i ); - }); - } - - if ( !elem || !elem.ownerDocument ) { - return null; - } - - if ( elem === elem.ownerDocument.body ) { - return jQuery.offset.bodyOffset( elem ); - } - + getOffset = function( elem, doc, docElem, box ) { try { box = elem.getBoundingClientRect(); } catch(e) {} - var doc = elem.ownerDocument, - docElem = doc.documentElement; - // Make sure we're not dealing with a disconnected DOM node if ( !box || !jQuery.contains( docElem, elem ) ) { return box ? { top: box.top, left: box.left } : { top: 0, left: 0 }; } var body = doc.body, - win = getWindow(doc), + win = getWindow( doc ), clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, - scrollTop = (win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop ), - scrollLeft = (win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft), + scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop, + scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft, top = box.top + scrollTop - clientTop, left = box.left + scrollLeft - clientLeft; @@ -7988,30 +9025,10 @@ if ( "getBoundingClientRect" in document.documentElement ) { }; } else { - jQuery.fn.offset = function( options ) { - var elem = this[0]; - - if ( options ) { - return this.each(function( i ) { - jQuery.offset.setOffset( this, options, i ); - }); - } - - if ( !elem || !elem.ownerDocument ) { - return null; - } - - if ( elem === elem.ownerDocument.body ) { - return jQuery.offset.bodyOffset( elem ); - } - - jQuery.offset.initialize(); - + getOffset = function( elem, doc, docElem ) { var computedStyle, offsetParent = elem.offsetParent, prevOffsetParent = elem, - doc = elem.ownerDocument, - docElem = doc.documentElement, body = doc.body, defaultView = doc.defaultView, prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle, @@ -8019,7 +9036,7 @@ if ( "getBoundingClientRect" in document.documentElement ) { left = elem.offsetLeft; while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) { - if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) { + if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) { break; } @@ -8031,7 +9048,7 @@ if ( "getBoundingClientRect" in document.documentElement ) { top += elem.offsetTop; left += elem.offsetLeft; - if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) { + if ( jQuery.support.doesNotAddBorder && !(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) { top += parseFloat( computedStyle.borderTopWidth ) || 0; left += parseFloat( computedStyle.borderLeftWidth ) || 0; } @@ -8040,7 +9057,7 @@ if ( "getBoundingClientRect" in document.documentElement ) { offsetParent = elem.offsetParent; } - if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) { + if ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) { top += parseFloat( computedStyle.borderTopWidth ) || 0; left += parseFloat( computedStyle.borderLeftWidth ) || 0; } @@ -8053,7 +9070,7 @@ if ( "getBoundingClientRect" in document.documentElement ) { left += body.offsetLeft; } - if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) { + if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) { top += Math.max( docElem.scrollTop, body.scrollTop ); left += Math.max( docElem.scrollLeft, body.scrollLeft ); } @@ -8062,48 +9079,36 @@ if ( "getBoundingClientRect" in document.documentElement ) { }; } +jQuery.fn.offset = function( options ) { + if ( arguments.length ) { + return options === undefined ? + this : + this.each(function( i ) { + jQuery.offset.setOffset( this, options, i ); + }); + } + + var elem = this[0], + doc = elem && elem.ownerDocument; + + if ( !doc ) { + return null; + } + + if ( elem === doc.body ) { + return jQuery.offset.bodyOffset( elem ); + } + + return getOffset( elem, doc, doc.documentElement ); +}; + jQuery.offset = { - initialize: function() { - var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.css(body, "marginTop") ) || 0, - html = "
"; - - jQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } ); - - container.innerHTML = html; - body.insertBefore( container, body.firstChild ); - innerDiv = container.firstChild; - checkDiv = innerDiv.firstChild; - td = innerDiv.nextSibling.firstChild.firstChild; - - this.doesNotAddBorder = (checkDiv.offsetTop !== 5); - this.doesAddBorderForTableAndCells = (td.offsetTop === 5); - - checkDiv.style.position = "fixed"; - checkDiv.style.top = "20px"; - - // safari subtracts parent border width here which is 5px - this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15); - checkDiv.style.position = checkDiv.style.top = ""; - - innerDiv.style.overflow = "hidden"; - innerDiv.style.position = "relative"; - - this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5); - - this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop); - - body.removeChild( container ); - body = container = innerDiv = checkDiv = table = td = null; - jQuery.offset.initialize = jQuery.noop; - }, bodyOffset: function( body ) { var top = body.offsetTop, left = body.offsetLeft; - jQuery.offset.initialize(); - - if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) { + if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) { top += parseFloat( jQuery.css(body, "marginTop") ) || 0; left += parseFloat( jQuery.css(body, "marginLeft") ) || 0; } @@ -8123,26 +9128,28 @@ jQuery.offset = { curOffset = curElem.offset(), curCSSTop = jQuery.css( elem, "top" ), curCSSLeft = jQuery.css( elem, "left" ), - calculatePosition = (position === "absolute" && jQuery.inArray('auto', [curCSSTop, curCSSLeft]) > -1), + calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, props = {}, curPosition = {}, curTop, curLeft; - // need to be able to calculate position if either top or left is auto and position is absolute + // need to be able to calculate position if either top or left is auto and position is either absolute or fixed if ( calculatePosition ) { curPosition = curElem.position(); + curTop = curPosition.top; + curLeft = curPosition.left; + } else { + curTop = parseFloat( curCSSTop ) || 0; + curLeft = parseFloat( curCSSLeft ) || 0; } - curTop = calculatePosition ? curPosition.top : parseInt( curCSSTop, 10 ) || 0; - curLeft = calculatePosition ? curPosition.left : parseInt( curCSSLeft, 10 ) || 0; - if ( jQuery.isFunction( options ) ) { options = options.call( elem, i, curOffset ); } - if (options.top != null) { - props.top = (options.top - curOffset.top) + curTop; + if ( options.top != null ) { + props.top = ( options.top - curOffset.top ) + curTop; } - if (options.left != null) { - props.left = (options.left - curOffset.left) + curLeft; + if ( options.left != null ) { + props.left = ( options.left - curOffset.left ) + curLeft; } if ( "using" in options ) { @@ -8155,6 +9162,7 @@ jQuery.offset = { jQuery.fn.extend({ + position: function() { if ( !this[0] ) { return null; @@ -8199,40 +9207,30 @@ jQuery.fn.extend({ // Create scrollLeft and scrollTop methods -jQuery.each( ["Left", "Top"], function( i, name ) { - var method = "scroll" + name; +jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) { + var top = /Y/.test( prop ); - jQuery.fn[ method ] = function(val) { - var elem = this[0], win; + jQuery.fn[ method ] = function( val ) { + return jQuery.access( this, function( elem, method, val ) { + var win = getWindow( elem ); - if ( !elem ) { - return null; - } + if ( val === undefined ) { + return win ? (prop in win) ? win[ prop ] : + jQuery.support.boxModel && win.document.documentElement[ method ] || + win.document.body[ method ] : + elem[ method ]; + } - if ( val !== undefined ) { - // Set the scroll offset - return this.each(function() { - win = getWindow( this ); + if ( win ) { + win.scrollTo( + !top ? val : jQuery( win ).scrollLeft(), + top ? val : jQuery( win ).scrollTop() + ); - if ( win ) { - win.scrollTo( - !i ? val : jQuery(win).scrollLeft(), - i ? val : jQuery(win).scrollTop() - ); - - } else { - this[ method ] = val; - } - }); - } else { - win = getWindow( elem ); - - // Return the scroll offset - return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] : - jQuery.support.boxModel && win.document.documentElement[ method ] || - win.document.body[ method ] : - elem[ method ]; - } + } else { + elem[ method ] = val; + } + }, method, val, arguments.length, null ); }; }); @@ -8247,70 +9245,90 @@ function getWindow( elem ) { -// Create innerHeight, innerWidth, outerHeight and outerWidth methods -jQuery.each([ "Height", "Width" ], function( i, name ) { - - var type = name.toLowerCase(); +// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods +jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { + var clientProp = "client" + name, + scrollProp = "scroll" + name, + offsetProp = "offset" + name; // innerHeight and innerWidth - jQuery.fn["inner" + name] = function() { - return this[0] ? - parseFloat( jQuery.css( this[0], type, "padding" ) ) : + jQuery.fn[ "inner" + name ] = function() { + var elem = this[0]; + return elem ? + elem.style ? + parseFloat( jQuery.css( elem, type, "padding" ) ) : + this[ type ]() : null; }; // outerHeight and outerWidth - jQuery.fn["outer" + name] = function( margin ) { - return this[0] ? - parseFloat( jQuery.css( this[0], type, margin ? "margin" : "border" ) ) : + jQuery.fn[ "outer" + name ] = function( margin ) { + var elem = this[0]; + return elem ? + elem.style ? + parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) : + this[ type ]() : null; }; - jQuery.fn[ type ] = function( size ) { - // Get window width or height - var elem = this[0]; - if ( !elem ) { - return size == null ? null : this; - } + jQuery.fn[ type ] = function( value ) { + return jQuery.access( this, function( elem, type, value ) { + var doc, docElemProp, orig, ret; - if ( jQuery.isFunction( size ) ) { - return this.each(function( i ) { - var self = jQuery( this ); - self[ type ]( size.call( this, i, self[ type ]() ) ); - }); - } + if ( jQuery.isWindow( elem ) ) { + // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat + doc = elem.document; + docElemProp = doc.documentElement[ clientProp ]; + return doc.compatMode === "CSS1Compat" && docElemProp || + doc.body && doc.body[ clientProp ] || docElemProp; + } - if ( jQuery.isWindow( elem ) ) { - // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode - // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat - var docElemProp = elem.document.documentElement[ "client" + name ]; - return elem.document.compatMode === "CSS1Compat" && docElemProp || - elem.document.body[ "client" + name ] || docElemProp; + // Get document width or height + if ( elem.nodeType === 9 ) { + // Either scroll[Width/Height] or offset[Width/Height], whichever is greater + doc = elem.documentElement; + return Math.max( + doc[ clientProp ], + elem.body[ scrollProp ], doc[ scrollProp ], + elem.body[ offsetProp ], doc[ offsetProp ] + ); + } - // Get document width or height - } else if ( elem.nodeType === 9 ) { - // Either scroll[Width/Height] or offset[Width/Height], whichever is greater - return Math.max( - elem.documentElement["client" + name], - elem.body["scroll" + name], elem.documentElement["scroll" + name], - elem.body["offset" + name], elem.documentElement["offset" + name] - ); - - // Get or set width or height on the element - } else if ( size === undefined ) { - var orig = jQuery.css( elem, type ), + // Get width or height on the element + if ( value === undefined ) { + orig = jQuery.css( elem, type ); ret = parseFloat( orig ); + return jQuery.isNumeric( ret ) ? ret : orig; + } - return jQuery.isNaN( ret ) ? orig : ret; - - // Set the width or height on the element (default to pixels if value is unitless) - } else { - return this.css( type, typeof size === "string" ? size : size + "px" ); - } + // Set the width or height on the element + jQuery( elem ).css( type, value ); + }, type, value, arguments.length, null ); }; - }); + + +// Expose jQuery to the global object window.jQuery = window.$ = jQuery; -})(window); + +// Expose jQuery as an AMD module, but only for AMD loaders that +// understand the issues with loading multiple versions of jQuery +// in a page that all might call define(). The loader will indicate +// they have special allowances for multiple jQuery versions by +// specifying define.amd.jQuery = true. Register as a named module, +// since jQuery can be concatenated with other files that may use define, +// but not use a proper concatenation script that understands anonymous +// AMD modules. A named AMD is safest and most robust way to register. +// Lowercase jquery is used because AMD module names are derived from +// file names, and jQuery is normally delivered in a lowercase file name. +// Do this after creating the global so that if an AMD module wants to call +// noConflict to hide this version of jQuery, it will work. +if ( typeof define === "function" && define.amd && define.amd.jQuery ) { + define( "jquery", [], function () { return jQuery; } ); +} + + + +})( window ); diff --git a/addons/web/static/lib/novajs/src/nova.js b/addons/web/static/lib/novajs/src/nova.js new file mode 100644 index 00000000000..848bcbc1407 --- /dev/null +++ b/addons/web/static/lib/novajs/src/nova.js @@ -0,0 +1,450 @@ +/* +Copyright (c) 2011, OpenERP S.A. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +nova = (function() { + var lib = {}; + lib.internal = {}; + + /* + * (Almost) unmodified John Resig's inheritance + */ + /* + * Simple JavaScript Inheritance By John Resig http://ejohn.org/ MIT + * Licensed. + */ + // Inspired by base2 and Prototype + (function() { + var initializing = false, fnTest = /xyz/.test(function() { + xyz; + }) ? /\b_super\b/ : /.*/; + // The base Class implementation (does nothing) + this.Class = function() { + }; + + // Create a new Class that inherits from this class + this.Class.extend = function(prop) { + var _super = this.prototype; + + // Instantiate a web class (but only create the instance, + // don't run the init constructor) + initializing = true; + var prototype = new this(); + initializing = false; + + // Copy the properties over onto the new prototype + for (var name in prop) { + // Check if we're overwriting an existing function + prototype[name] = typeof prop[name] == "function" && + typeof _super[name] == "function" && + fnTest.test(prop[name]) ? + (function(name, fn) { + return function() { + var tmp = this._super; + + // Add a new ._super() method that is the same + // method but on the super-class + this._super = _super[name]; + + // The method only need to be bound temporarily, so + // we remove it when we're done executing + var ret = fn.apply(this, arguments); + this._super = tmp; + + return ret; + }; + })(name, prop[name]) : + prop[name]; + } + + // The dummy class constructor + function Class() { + // All construction is actually done in the init method + if (!initializing && this.init) { + var ret = this.init.apply(this, arguments); + if (ret) { return ret; } + } + return this; + } + Class.include = function (properties) { + for (var name in properties) { + if (typeof properties[name] !== 'function' + || !fnTest.test(properties[name])) { + prototype[name] = properties[name]; + } else if (typeof prototype[name] === 'function' + && prototype.hasOwnProperty(name)) { + prototype[name] = (function (name, fn, previous) { + return function () { + var tmp = this._super; + this._super = previous; + var ret = fn.apply(this, arguments); + this._super = tmp; + return ret; + } + })(name, properties[name], prototype[name]); + } else if (typeof _super[name] === 'function') { + prototype[name] = (function (name, fn) { + return function () { + var tmp = this._super; + this._super = _super[name]; + var ret = fn.apply(this, arguments); + this._super = tmp; + return ret; + } + })(name, properties[name]); + } + } + }; + + // Populate our constructed prototype object + Class.prototype = prototype; + + // Enforce the constructor to be what we expect + Class.constructor = Class; + + // And make this class extendable + Class.extend = arguments.callee; + + return Class; + }; + }).call(lib); + // end of John Resig's code + + lib.DestroyableMixin = { + init: function() { + this.__destroyableDestroyed = false; + }, + isDestroyed : function() { + return this.__destroyableDestroyed; + }, + destroy : function() { + this.__destroyableDestroyed = true; + } + }; + + lib.ParentedMixin = _.extend({}, lib.DestroyableMixin, { + __parentedMixin : true, + init: function() { + lib.DestroyableMixin.init.call(this); + this.__parentedChildren = []; + this.__parentedParent = null; + }, + setParent : function(parent) { + if (this.getParent()) { + if (this.getParent().__parentedMixin) { + this.getParent().__parentedChildren = _.without(this + .getParent().getChildren(), this); + } + } + this.__parentedParent = parent; + if (parent && parent.__parentedMixin) { + parent.__parentedChildren.push(this); + } + }, + getParent : function() { + return this.__parentedParent; + }, + getChildren : function() { + return _.clone(this.__parentedChildren); + }, + destroy : function() { + _.each(this.getChildren(), function(el) { + el.destroy(); + }); + this.setParent(undefined); + lib.DestroyableMixin.destroy.call(this); + } + }); + + /* + * Yes, we steal Backbone's events :) + * + * This class just handle the dispatching of events, it is not meant to be extended, + * nor used directly. All integration with parenting and automatic unregistration of + * events is done in EventDispatcherMixin. + */ + // (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc. + // Backbone may be freely distributed under the MIT license. + // For all details and documentation: + // http://backbonejs.org + lib.internal.Events = lib.Class.extend({ + + on : function(events, callback, context) { + var ev; + events = events.split(/\s+/); + var calls = this._callbacks || (this._callbacks = {}); + while (ev = events.shift()) { + var list = calls[ev] || (calls[ev] = {}); + var tail = list.tail || (list.tail = list.next = {}); + tail.callback = callback; + tail.context = context; + list.tail = tail.next = {}; + } + return this; + }, + + off : function(events, callback, context) { + var ev, calls, node; + if (!events) { + delete this._callbacks; + } else if (calls = this._callbacks) { + events = events.split(/\s+/); + while (ev = events.shift()) { + node = calls[ev]; + delete calls[ev]; + if (!callback || !node) + continue; + while ((node = node.next) && node.next) { + if (node.callback === callback + && (!context || node.context === context)) + continue; + this.on(ev, node.callback, node.context); + } + } + } + return this; + }, + + trigger : function(events) { + var event, node, calls, tail, args, all, rest; + if (!(calls = this._callbacks)) + return this; + all = calls['all']; + (events = events.split(/\s+/)).push(null); + // Save references to the current heads & tails. + while (event = events.shift()) { + if (all) + events.push({ + next : all.next, + tail : all.tail, + event : event + }); + if (!(node = calls[event])) + continue; + events.push({ + next : node.next, + tail : node.tail + }); + } + rest = Array.prototype.slice.call(arguments, 1); + while (node = events.pop()) { + tail = node.tail; + args = node.event ? [ node.event ].concat(rest) : rest; + while ((node = node.next) !== tail) { + node.callback.apply(node.context || this, args); + } + } + return this; + } + }); + // end of Backbone's events class + + lib.EventDispatcherMixin = _.extend({}, lib.ParentedMixin, { + __eventDispatcherMixin: true, + init: function() { + lib.ParentedMixin.init.call(this); + this.__edispatcherEvents = new lib.internal.Events(); + this.__edispatcherRegisteredEvents = []; + }, + on: function(events, dest, func) { + var self = this; + events = events.split(/\s+/); + _.each(events, function(eventName) { + self.__edispatcherEvents.on(eventName, func, dest); + if (dest && dest.__eventDispatcherMixin) { + dest.__edispatcherRegisteredEvents.push({name: eventName, func: func, source: self}); + } + }); + return this; + }, + off: function(events, dest, func) { + var self = this; + events = events.split(/\s+/); + _.each(events, function(eventName) { + self.__edispatcherEvents.off(eventName, func, dest); + if (dest && dest.__eventDispatcherMixin) { + dest.__edispatcherRegisteredEvents = _.filter(dest.__edispatcherRegisteredEvents, function(el) { + return !(el.name === eventName && el.func === func && el.source === self); + }); + } + }); + return this; + }, + trigger: function(events) { + this.__edispatcherEvents.trigger.apply(this.__edispatcherEvents, arguments); + return this; + }, + destroy: function() { + var self = this; + _.each(this.__edispatcherRegisteredEvents, function(event) { + event.source.__edispatcherEvents.off(event.name, event.func, self); + }); + this.__edispatcherRegisteredEvents = []; + this.__edispatcherEvents.off(); + lib.ParentedMixin.destroy.call(this); + } + }); + + lib.GetterSetterMixin = _.extend({}, lib.EventDispatcherMixin, { + init: function() { + lib.EventDispatcherMixin.init.call(this); + this.__getterSetterInternalMap = {}; + }, + set: function(map) { + var self = this; + var changed = false; + _.each(map, function(val, key) { + var tmp = self.__getterSetterInternalMap[key]; + if (tmp === val) + return; + changed = true; + self.__getterSetterInternalMap[key] = val; + self.trigger("change:" + key, self, { + oldValue: tmp, + newValue: val + }); + }); + if (changed) + self.trigger("change", self); + }, + get: function(key) { + return this.__getterSetterInternalMap[key]; + } + }); + + lib.Widget = lib.Class.extend(_.extend({}, lib.GetterSetterMixin, { + /** + * Tag name when creating a default $element. + * @type string + */ + tagName: 'div', + /** + * Constructs the widget and sets its parent if a parent is given. + * + * @constructs openerp.web.Widget + * @extends openerp.web.CallbackEnabled + * + * @param {openerp.web.Widget} parent Binds the current instance to the given Widget instance. + * When that widget is destroyed by calling destroy(), the current instance will be + * destroyed too. Can be null. + * @param {String} element_id Deprecated. Sets the element_id. Only useful when you want + * to bind the current Widget to an already existing part of the DOM, which is not compatible + * with the DOM insertion methods provided by the current implementation of Widget. So + * for new components this argument should not be provided any more. + */ + init: function(parent) { + lib.GetterSetterMixin.init.call(this); + this.$element = $(document.createElement(this.tagName)); + + this.setParent(parent); + }, + /** + * Destroys the current widget, also destroys all its children before destroying itself. + */ + destroy: function() { + _.each(this.getChildren(), function(el) { + el.destroy(); + }); + if(this.$element != null) { + this.$element.remove(); + } + lib.GetterSetterMixin.destroy.call(this); + }, + /** + * Renders the current widget and appends it to the given jQuery object or Widget. + * + * @param target A jQuery object or a Widget instance. + */ + appendTo: function(target) { + var self = this; + return this.__widgetRenderAndInsert(function(t) { + self.$element.appendTo(t); + }, target); + }, + /** + * Renders the current widget and prepends it to the given jQuery object or Widget. + * + * @param target A jQuery object or a Widget instance. + */ + prependTo: function(target) { + var self = this; + return this.__widgetRenderAndInsert(function(t) { + self.$element.prependTo(t); + }, target); + }, + /** + * Renders the current widget and inserts it after to the given jQuery object or Widget. + * + * @param target A jQuery object or a Widget instance. + */ + insertAfter: function(target) { + var self = this; + return this.__widgetRenderAndInsert(function(t) { + self.$element.insertAfter(t); + }, target); + }, + /** + * Renders the current widget and inserts it before to the given jQuery object or Widget. + * + * @param target A jQuery object or a Widget instance. + */ + insertBefore: function(target) { + var self = this; + return this.__widgetRenderAndInsert(function(t) { + self.$element.insertBefore(t); + }, target); + }, + /** + * Renders the current widget and replaces the given jQuery object. + * + * @param target A jQuery object or a Widget instance. + */ + replace: function(target) { + return this.__widgetRenderAndInsert(_.bind(function(t) { + this.$element.replaceAll(t); + }, this), target); + }, + __widgetRenderAndInsert: function(insertion, target) { + this.renderElement(); + insertion(target); + return this.start(); + }, + /** + * This is the method to implement to render the Widget. + */ + renderElement: function() {}, + /** + * Method called after rendering. Mostly used to bind actions, perform asynchronous + * calls, etc... + * + * By convention, the method should return a promise to inform the caller when + * this widget has been initialized. + * + * @returns {jQuery.Deferred} + */ + start: function() {} + })); + + return lib; +})(); diff --git a/addons/web_mobile/static/openerp/dynamics/jquery-1.5.1.js b/addons/web/static/lib/novajs/test/jquery-1.6.4.js old mode 100755 new mode 100644 similarity index 73% rename from addons/web_mobile/static/openerp/dynamics/jquery-1.5.1.js rename to addons/web/static/lib/novajs/test/jquery-1.6.4.js index 78fcfa469b3..2c12adbf3e8 --- a/addons/web_mobile/static/openerp/dynamics/jquery-1.5.1.js +++ b/addons/web/static/lib/novajs/test/jquery-1.6.4.js @@ -1,5 +1,5 @@ /*! - * jQuery JavaScript Library v1.5.1 + * jQuery JavaScript Library v1.6.4 * http://jquery.com/ * * Copyright 2011, John Resig @@ -11,12 +11,14 @@ * Copyright 2011, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * - * Date: Wed Feb 23 13:55:29 2011 -0500 + * Date: Mon Sep 12 18:54:48 2011 -0400 */ (function( window, undefined ) { // Use the correct document accordingly with window argument (sandbox) -var document = window.document; +var document = window.document, + navigator = window.navigator, + location = window.location; var jQuery = (function() { // Define a local copy of jQuery @@ -35,8 +37,8 @@ var jQuery = function( selector, context ) { rootjQuery, // A simple way to check for HTML strings or ID strings - // (both of which we optimize for) - quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/, + // Prioritize #id over to avoid XSS via location.hash (#9521) + quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, // Check if a string has a non-whitespace character in it rnotwhite = /\S/, @@ -63,21 +65,24 @@ var jQuery = function( selector, context ) { rmsie = /(msie) ([\w.]+)/, rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + // Matches dashed string for camelizing + rdashAlpha = /-([a-z]|[0-9])/ig, + rmsPrefix = /^-ms-/, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return ( letter + "" ).toUpperCase(); + }, + // Keep a UserAgent string for use with jQuery.browser userAgent = navigator.userAgent, // For matching the engine and version of the browser browserMatch, - // Has the ready events already been bound? - readyBound = false, - // The deferred used on DOM ready readyList, - // Promise methods - promiseMethods = "then done fail isResolved isRejected promise".split( " " ), - // The ready event handler DOMContentLoaded, @@ -113,7 +118,7 @@ jQuery.fn = jQuery.prototype = { if ( selector === "body" && !context && document.body ) { this.context = document; this[0] = document.body; - this.selector = "body"; + this.selector = selector; this.length = 1; return this; } @@ -121,7 +126,13 @@ jQuery.fn = jQuery.prototype = { // Handle HTML strings if ( typeof selector === "string" ) { // Are we dealing with HTML string or an ID? - match = quickExpr.exec( selector ); + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = quickExpr.exec( selector ); + } // Verify a match, and that no context was specified for #id if ( match && (match[1] || !context) ) { @@ -202,7 +213,7 @@ jQuery.fn = jQuery.prototype = { selector: "", // The current version of jQuery being used - jquery: "1.5.1", + jquery: "1.6.4", // The default length of a jQuery object is 0 length: 0, @@ -378,9 +389,11 @@ jQuery.extend = jQuery.fn.extend = function() { jQuery.extend({ noConflict: function( deep ) { - window.$ = _$; + if ( window.$ === jQuery ) { + window.$ = _$; + } - if ( deep ) { + if ( deep && window.jQuery === jQuery ) { window.jQuery = _jQuery; } @@ -394,15 +407,19 @@ jQuery.extend({ // the ready event fires. See #6781 readyWait: 1, + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + // Handle when the DOM is ready ready: function( wait ) { - // A third-party is pushing the ready event forwards - if ( wait === true ) { - jQuery.readyWait--; - } - - // Make sure that the DOM is not already loaded - if ( !jQuery.readyWait || (wait !== true && !jQuery.isReady) ) { + // Either a released hold or an DOMready/load event and not yet ready + if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( !document.body ) { return setTimeout( jQuery.ready, 1 ); @@ -427,11 +444,11 @@ jQuery.extend({ }, bindReady: function() { - if ( readyBound ) { + if ( readyList ) { return; } - readyBound = true; + readyList = jQuery._Deferred(); // Catch cases where $(document).ready() is called after the // browser event has already occurred. @@ -452,7 +469,7 @@ jQuery.extend({ } else if ( document.attachEvent ) { // ensure firing before onload, // maybe late but safe also for iframes - document.attachEvent("onreadystatechange", DOMContentLoaded); + document.attachEvent( "onreadystatechange", DOMContentLoaded ); // A fallback to window.onload, that will always work window.attachEvent( "onload", jQuery.ready ); @@ -505,10 +522,15 @@ jQuery.extend({ return false; } - // Not own constructor property must be Object - if ( obj.constructor && - !hasOwn.call(obj, "constructor") && - !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + try { + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 return false; } @@ -540,67 +562,66 @@ jQuery.extend({ // Make sure leading/trailing whitespace is removed (IE can't handle it) data = jQuery.trim( data ); + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + // Make sure the incoming data is actual JSON // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test(data.replace(rvalidescape, "@") - .replace(rvalidtokens, "]") - .replace(rvalidbraces, "")) ) { + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { - // Try to use the native JSON parser first - return window.JSON && window.JSON.parse ? - window.JSON.parse( data ) : - (new Function("return " + data))(); + return (new Function( "return " + data ))(); - } else { - jQuery.error( "Invalid JSON: " + data ); } + jQuery.error( "Invalid JSON: " + data ); }, // Cross-browser xml parsing - // (xml & tmp used internally) - parseXML: function( data , xml , tmp ) { - - if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); - xml.async = "false"; - xml.loadXML( data ); + parseXML: function( data ) { + var xml, tmp; + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; } - - tmp = xml.documentElement; - - if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) { + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { jQuery.error( "Invalid XML: " + data ); } - return xml; }, noop: function() {}, - // Evalulates a script in a global context + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context globalEval: function( data ) { - if ( data && rnotwhite.test(data) ) { - // Inspired by code by Andrea Giammarchi - // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html - var head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement, - script = document.createElement( "script" ); - - if ( jQuery.support.scriptEval() ) { - script.appendChild( document.createTextNode( data ) ); - } else { - script.text = data; - } - - // Use insertBefore instead of appendChild to circumvent an IE6 bug. - // This arises when a base node is used (#2709). - head.insertBefore( script, head.firstChild ); - head.removeChild( script ); + if ( data && rnotwhite.test( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); } }, + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + nodeName: function( elem, name ) { return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); }, @@ -609,7 +630,7 @@ jQuery.extend({ each: function( object, callback, args ) { var name, i = 0, length = object.length, - isObj = length === undefined || jQuery.isFunction(object); + isObj = length === undefined || jQuery.isFunction( object ); if ( args ) { if ( isObj ) { @@ -635,8 +656,11 @@ jQuery.extend({ } } } else { - for ( var value = object[0]; - i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} + for ( ; i < length; ) { + if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { + break; + } + } } } @@ -667,7 +691,7 @@ jQuery.extend({ // The extra typeof function check is to prevent crashes // in Safari 2 (See: #3039) // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 - var type = jQuery.type(array); + var type = jQuery.type( array ); if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { push.call( ret, array ); @@ -680,8 +704,12 @@ jQuery.extend({ }, inArray: function( elem, array ) { - if ( array.indexOf ) { - return array.indexOf( elem ); + if ( !array ) { + return -1; + } + + if ( indexOf ) { + return indexOf.call( array, elem ); } for ( var i = 0, length = array.length; i < length; i++ ) { @@ -731,15 +759,30 @@ jQuery.extend({ // arg is for internal usage only map: function( elems, callback, arg ) { - var ret = [], value; + var value, key, ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; // Go through the array, translating each of the items to their - // new value (or values). - for ( var i = 0, length = elems.length; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); - if ( value != null ) { - ret[ ret.length ] = value; + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } } } @@ -750,36 +793,35 @@ jQuery.extend({ // A global GUID counter for objects guid: 1, - proxy: function( fn, proxy, thisObject ) { - if ( arguments.length === 2 ) { - if ( typeof proxy === "string" ) { - thisObject = fn; - fn = thisObject[ proxy ]; - proxy = undefined; - - } else if ( proxy && !jQuery.isFunction( proxy ) ) { - thisObject = proxy; - proxy = undefined; - } + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + if ( typeof context === "string" ) { + var tmp = fn[ context ]; + context = fn; + fn = tmp; } - if ( !proxy && fn ) { + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + var args = slice.call( arguments, 2 ), proxy = function() { - return fn.apply( thisObject || this, arguments ); + return fn.apply( context, args.concat( slice.call( arguments ) ) ); }; - } // Set the guid of unique handler to the same of original handler, so it can be removed - if ( fn ) { - proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - } + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - // So proxy can be declared as an argument return proxy; }, // Mutifunctional method to get and set values to a collection - // The value/s can be optionally by executed if its a function + // The value/s can optionally be executed if it's a function access: function( elems, key, value, exec, fn, pass ) { var length = elems.length; @@ -811,171 +853,6 @@ jQuery.extend({ return (new Date()).getTime(); }, - // Create a simple deferred (one callbacks list) - _Deferred: function() { - var // callbacks list - callbacks = [], - // stored [ context , args ] - fired, - // to avoid firing when already doing so - firing, - // flag to know if the deferred has been cancelled - cancelled, - // the deferred itself - deferred = { - - // done( f1, f2, ...) - done: function() { - if ( !cancelled ) { - var args = arguments, - i, - length, - elem, - type, - _fired; - if ( fired ) { - _fired = fired; - fired = 0; - } - for ( i = 0, length = args.length; i < length; i++ ) { - elem = args[ i ]; - type = jQuery.type( elem ); - if ( type === "array" ) { - deferred.done.apply( deferred, elem ); - } else if ( type === "function" ) { - callbacks.push( elem ); - } - } - if ( _fired ) { - deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] ); - } - } - return this; - }, - - // resolve with given context and args - resolveWith: function( context, args ) { - if ( !cancelled && !fired && !firing ) { - firing = 1; - try { - while( callbacks[ 0 ] ) { - callbacks.shift().apply( context, args ); - } - } - // We have to add a catch block for - // IE prior to 8 or else the finally - // block will never get executed - catch (e) { - throw e; - } - finally { - fired = [ context, args ]; - firing = 0; - } - } - return this; - }, - - // resolve with this as context and given arguments - resolve: function() { - deferred.resolveWith( jQuery.isFunction( this.promise ) ? this.promise() : this, arguments ); - return this; - }, - - // Has this deferred been resolved? - isResolved: function() { - return !!( firing || fired ); - }, - - // Cancel - cancel: function() { - cancelled = 1; - callbacks = []; - return this; - } - }; - - return deferred; - }, - - // Full fledged deferred (two callbacks list) - Deferred: function( func ) { - var deferred = jQuery._Deferred(), - failDeferred = jQuery._Deferred(), - promise; - // Add errorDeferred methods, then and promise - jQuery.extend( deferred, { - then: function( doneCallbacks, failCallbacks ) { - deferred.done( doneCallbacks ).fail( failCallbacks ); - return this; - }, - fail: failDeferred.done, - rejectWith: failDeferred.resolveWith, - reject: failDeferred.resolve, - isRejected: failDeferred.isResolved, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - if ( obj == null ) { - if ( promise ) { - return promise; - } - promise = obj = {}; - } - var i = promiseMethods.length; - while( i-- ) { - obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ]; - } - return obj; - } - } ); - // Make sure only one callback list will be used - deferred.done( failDeferred.cancel ).fail( deferred.cancel ); - // Unexpose cancel - delete deferred.cancel; - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - return deferred; - }, - - // Deferred helper - when: function( object ) { - var lastIndex = arguments.length, - deferred = lastIndex <= 1 && object && jQuery.isFunction( object.promise ) ? - object : - jQuery.Deferred(), - promise = deferred.promise(); - - if ( lastIndex > 1 ) { - var array = slice.call( arguments, 0 ), - count = lastIndex, - iCallback = function( index ) { - return function( value ) { - array[ index ] = arguments.length > 1 ? slice.call( arguments, 0 ) : value; - if ( !( --count ) ) { - deferred.resolveWith( promise, array ); - } - }; - }; - while( ( lastIndex-- ) ) { - object = array[ lastIndex ]; - if ( object && jQuery.isFunction( object.promise ) ) { - object.promise().then( iCallback(lastIndex), deferred.reject ); - } else { - --count; - } - } - if ( !count ) { - deferred.resolveWith( promise, array ); - } - } else if ( deferred !== object ) { - deferred.resolve( object ); - } - return promise; - }, - // Use of jQuery.browser is frowned upon. // More details: http://docs.jquery.com/Utilities/jQuery.browser uaMatch: function( ua ) { @@ -991,32 +868,29 @@ jQuery.extend({ }, sub: function() { - function jQuerySubclass( selector, context ) { - return new jQuerySubclass.fn.init( selector, context ); + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); } - jQuery.extend( true, jQuerySubclass, this ); - jQuerySubclass.superclass = this; - jQuerySubclass.fn = jQuerySubclass.prototype = this(); - jQuerySubclass.fn.constructor = jQuerySubclass; - jQuerySubclass.subclass = this.subclass; - jQuerySubclass.fn.init = function init( selector, context ) { - if ( context && context instanceof jQuery && !(context instanceof jQuerySubclass) ) { - context = jQuerySubclass(context); + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); } - return jQuery.fn.init.call( this, selector, context, rootjQuerySubclass ); + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); }; - jQuerySubclass.fn.init.prototype = jQuerySubclass.fn; - var rootjQuerySubclass = jQuerySubclass(document); - return jQuerySubclass; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; }, browser: {} }); -// Create readyList deferred -readyList = jQuery._Deferred(); - // Populate the class2type map jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); @@ -1033,12 +907,6 @@ if ( jQuery.browser.webkit ) { jQuery.browser.safari = true; } -if ( indexOf ) { - jQuery.inArray = function( elem, array ) { - return indexOf.call( array, elem ); - }; -} - // IE doesn't match non-breaking spaces with \s if ( rnotwhite.test( "\xA0" ) ) { trimLeft = /^[\s\xA0]+/; @@ -1084,51 +952,268 @@ function doScrollCheck() { jQuery.ready(); } -// Expose jQuery to the global object return jQuery; })(); -(function() { +var // Promise methods + promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ), + // Static reference to slice + sliceDeferred = [].slice; - jQuery.support = {}; +jQuery.extend({ + // Create a simple deferred (one callbacks list) + _Deferred: function() { + var // callbacks list + callbacks = [], + // stored [ context , args ] + fired, + // to avoid firing when already doing so + firing, + // flag to know if the deferred has been cancelled + cancelled, + // the deferred itself + deferred = { - var div = document.createElement("div"); + // done( f1, f2, ...) + done: function() { + if ( !cancelled ) { + var args = arguments, + i, + length, + elem, + type, + _fired; + if ( fired ) { + _fired = fired; + fired = 0; + } + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + deferred.done.apply( deferred, elem ); + } else if ( type === "function" ) { + callbacks.push( elem ); + } + } + if ( _fired ) { + deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] ); + } + } + return this; + }, - div.style.display = "none"; - div.innerHTML = "
a"; + // resolve with given context and args + resolveWith: function( context, args ) { + if ( !cancelled && !fired && !firing ) { + // make sure args are available (#8421) + args = args || []; + firing = 1; + try { + while( callbacks[ 0 ] ) { + callbacks.shift().apply( context, args ); + } + } + finally { + fired = [ context, args ]; + firing = 0; + } + } + return this; + }, - var all = div.getElementsByTagName("*"), - a = div.getElementsByTagName("a")[0], - select = document.createElement("select"), - opt = select.appendChild( document.createElement("option") ), - input = div.getElementsByTagName("input")[0]; + // resolve with this as context and given arguments + resolve: function() { + deferred.resolveWith( this, arguments ); + return this; + }, + + // Has this deferred been resolved? + isResolved: function() { + return !!( firing || fired ); + }, + + // Cancel + cancel: function() { + cancelled = 1; + callbacks = []; + return this; + } + }; + + return deferred; + }, + + // Full fledged deferred (two callbacks list) + Deferred: function( func ) { + var deferred = jQuery._Deferred(), + failDeferred = jQuery._Deferred(), + promise; + // Add errorDeferred methods, then and promise + jQuery.extend( deferred, { + then: function( doneCallbacks, failCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ); + return this; + }, + always: function() { + return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments ); + }, + fail: failDeferred.done, + rejectWith: failDeferred.resolveWith, + reject: failDeferred.resolve, + isRejected: failDeferred.isResolved, + pipe: function( fnDone, fnFail ) { + return jQuery.Deferred(function( newDefer ) { + jQuery.each( { + done: [ fnDone, "resolve" ], + fail: [ fnFail, "reject" ] + }, function( handler, data ) { + var fn = data[ 0 ], + action = data[ 1 ], + returned; + if ( jQuery.isFunction( fn ) ) { + deferred[ handler ](function() { + returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise().then( newDefer.resolve, newDefer.reject ); + } else { + newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); + } + }); + } else { + deferred[ handler ]( newDefer[ action ] ); + } + }); + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + if ( promise ) { + return promise; + } + promise = obj = {}; + } + var i = promiseMethods.length; + while( i-- ) { + obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ]; + } + return obj; + } + }); + // Make sure only one callback list will be used + deferred.done( failDeferred.cancel ).fail( deferred.cancel ); + // Unexpose cancel + delete deferred.cancel; + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + return deferred; + }, + + // Deferred helper + when: function( firstParam ) { + var args = arguments, + i = 0, + length = args.length, + count = length, + deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? + firstParam : + jQuery.Deferred(); + function resolveFunc( i ) { + return function( value ) { + args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + if ( !( --count ) ) { + // Strange bug in FF4: + // Values changed onto the arguments object sometimes end up as undefined values + // outside the $.when method. Cloning the object into a fresh array solves the issue + deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) ); + } + }; + } + if ( length > 1 ) { + for( ; i < length; i++ ) { + if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) { + args[ i ].promise().then( resolveFunc(i), deferred.reject ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( deferred, args ); + } + } else if ( deferred !== firstParam ) { + deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); + } + return deferred.promise(); + } +}); + + + +jQuery.support = (function() { + + var div = document.createElement( "div" ), + documentElement = document.documentElement, + all, + a, + select, + opt, + input, + marginDiv, + support, + fragment, + body, + testElementParent, + testElement, + testElementStyle, + tds, + events, + eventName, + i, + isSupported; + + // Preliminary tests + div.setAttribute("className", "t"); + div.innerHTML = "
a"; + + + all = div.getElementsByTagName( "*" ); + a = div.getElementsByTagName( "a" )[ 0 ]; // Can't get basic test support if ( !all || !all.length || !a ) { - return; + return {}; } - jQuery.support = { + // First batch of supports tests + select = document.createElement( "select" ); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName( "input" )[ 0 ]; + + support = { // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: div.firstChild.nodeType === 3, + leadingWhitespace: ( div.firstChild.nodeType === 3 ), // Make sure that tbody elements aren't automatically inserted // IE will insert them into empty tables - tbody: !div.getElementsByTagName("tbody").length, + tbody: !div.getElementsByTagName( "tbody" ).length, // Make sure that link elements get serialized correctly by innerHTML // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName("link").length, + htmlSerialize: !!div.getElementsByTagName( "link" ).length, // Get the style information from getAttribute - // (IE uses .cssText insted) - style: /red/.test( a.getAttribute("style") ), + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), // Make sure that URLs aren't manipulated // (IE normalizes it by default) - hrefNormalized: a.getAttribute("href") === "/a", + hrefNormalized: ( a.getAttribute( "href" ) === "/a" ), // Make sure that element opacity exists // (IE uses filter instead) @@ -1142,180 +1227,194 @@ return jQuery; // Make sure that if no value is specified for a checkbox // that it defaults to "on". // (WebKit defaults to "" instead) - checkOn: input.value === "on", + checkOn: ( input.value === "on" ), // Make sure that a selected-by-default option has a working selected property. // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) optSelected: opt.selected, + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, deleteExpando: true, - optDisabled: false, - checkClone: false, noCloneEvent: true, - noCloneChecked: true, - boxModel: null, inlineBlockNeedsLayout: false, shrinkWrapBlocks: false, - reliableHiddenOffsets: true + reliableMarginRight: true }; + // Make sure checked status is properly cloned input.checked = true; - jQuery.support.noCloneChecked = input.cloneNode( true ).checked; + support.noCloneChecked = input.cloneNode( true ).checked; // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as diabled) + // (WebKit marks them as disabled) select.disabled = true; - jQuery.support.optDisabled = !opt.disabled; - - var _scriptEval = null; - jQuery.support.scriptEval = function() { - if ( _scriptEval === null ) { - var root = document.documentElement, - script = document.createElement("script"), - id = "script" + jQuery.now(); - - try { - script.appendChild( document.createTextNode( "window." + id + "=1;" ) ); - } catch(e) {} - - root.insertBefore( script, root.firstChild ); - - // Make sure that the execution of code works by injecting a script - // tag with appendChild/createTextNode - // (IE doesn't support this, fails, and uses .text instead) - if ( window[ id ] ) { - _scriptEval = true; - delete window[ id ]; - } else { - _scriptEval = false; - } - - root.removeChild( script ); - // release memory in IE - root = script = id = null; - } - - return _scriptEval; - }; + support.optDisabled = !opt.disabled; // Test to see if it's possible to delete an expando from an element // Fails in Internet Explorer try { delete div.test; - - } catch(e) { - jQuery.support.deleteExpando = false; + } catch( e ) { + support.deleteExpando = false; } if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { - div.attachEvent("onclick", function click() { + div.attachEvent( "onclick", function() { // Cloning a node shouldn't copy over any // bound event handlers (IE does this) - jQuery.support.noCloneEvent = false; - div.detachEvent("onclick", click); + support.noCloneEvent = false; }); - div.cloneNode(true).fireEvent("onclick"); + div.cloneNode( true ).fireEvent( "onclick" ); } - div = document.createElement("div"); - div.innerHTML = ""; + // Check if a radio maintains it's value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute("type", "radio"); + support.radioValue = input.value === "t"; - var fragment = document.createDocumentFragment(); + input.setAttribute("checked", "checked"); + div.appendChild( input ); + fragment = document.createDocumentFragment(); fragment.appendChild( div.firstChild ); // WebKit doesn't clone checked state correctly in fragments - jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked; + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + div.innerHTML = ""; // Figure out if the W3C box model works as expected - // document.body must exist before we can do this - jQuery(function() { - var div = document.createElement("div"), - body = document.getElementsByTagName("body")[0]; + div.style.width = div.style.paddingLeft = "1px"; - // Frameset documents with no body should not run this code - if ( !body ) { - return; - } + body = document.getElementsByTagName( "body" )[ 0 ]; + // We use our own, invisible, body unless the body is already present + // in which case we use a div (#9239) + testElement = document.createElement( body ? "div" : "body" ); + testElementStyle = { + visibility: "hidden", + width: 0, + height: 0, + border: 0, + margin: 0, + background: "none" + }; + if ( body ) { + jQuery.extend( testElementStyle, { + position: "absolute", + left: "-1000px", + top: "-1000px" + }); + } + for ( i in testElementStyle ) { + testElement.style[ i ] = testElementStyle[ i ]; + } + testElement.appendChild( div ); + testElementParent = body || documentElement; + testElementParent.insertBefore( testElement, testElementParent.firstChild ); - div.style.width = div.style.paddingLeft = "1px"; - body.appendChild( div ); - jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2; + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; - if ( "zoom" in div.style ) { - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - // (IE < 8 does this) - div.style.display = "inline"; - div.style.zoom = 1; - jQuery.support.inlineBlockNeedsLayout = div.offsetWidth === 2; + support.boxModel = div.offsetWidth === 2; - // Check if elements with layout shrink-wrap their children - // (IE 6 does this) - div.style.display = ""; - div.innerHTML = "
"; - jQuery.support.shrinkWrapBlocks = div.offsetWidth !== 2; - } + if ( "zoom" in div.style ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.style.display = "inline"; + div.style.zoom = 1; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); - div.innerHTML = "
t
"; - var tds = div.getElementsByTagName("td"); + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = ""; + div.innerHTML = "
"; + support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); + } - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - // (only IE 8 fails this test) - jQuery.support.reliableHiddenOffsets = tds[0].offsetHeight === 0; + div.innerHTML = "
t
"; + tds = div.getElementsByTagName( "td" ); - tds[0].style.display = ""; - tds[1].style.display = "none"; + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + isSupported = ( tds[ 0 ].offsetHeight === 0 ); - // Check if empty table cells still have offsetWidth/Height - // (IE < 8 fail this test) - jQuery.support.reliableHiddenOffsets = jQuery.support.reliableHiddenOffsets && tds[0].offsetHeight === 0; - div.innerHTML = ""; + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; - body.removeChild( div ).style.display = "none"; - div = tds = null; - }); + // Check if empty table cells still have offsetWidth/Height + // (IE < 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + div.innerHTML = ""; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + if ( document.defaultView && document.defaultView.getComputedStyle ) { + marginDiv = document.createElement( "div" ); + marginDiv.style.width = "0"; + marginDiv.style.marginRight = "0"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; + } + + // Remove the body element we added + testElement.innerHTML = ""; + testElementParent.removeChild( testElement ); // Technique from Juriy Zaytsev // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ - var eventSupported = function( eventName ) { - var el = document.createElement("div"); - eventName = "on" + eventName; - - // We only care about the case where non-standard event systems - // are used, namely in IE. Short-circuiting here helps us to - // avoid an eval call (in setAttribute) which can cause CSP - // to go haywire. See: https://developer.mozilla.org/en/Security/CSP - if ( !el.attachEvent ) { - return true; + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for( i in { + submit: 1, + change: 1, + focusin: 1 + } ) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; } + } - var isSupported = (eventName in el); - if ( !isSupported ) { - el.setAttribute(eventName, "return;"); - isSupported = typeof el[eventName] === "function"; - } - el = null; + // Null connected elements to avoid leaks in IE + testElement = fragment = select = opt = body = marginDiv = div = input = null; - return isSupported; - }; - - jQuery.support.submitBubbles = eventSupported("submit"); - jQuery.support.changeBubbles = eventSupported("change"); - - // release memory in IE - div = all = a = null; + return support; })(); +// Keep track of boxModel +jQuery.boxModel = jQuery.support.boxModel; -var rbrace = /^(?:\{.*\}|\[.*\])$/; + + +var rbrace = /^(?:\{.*\}|\[.*\])$/, + rmultiDash = /([A-Z])/g; jQuery.extend({ cache: {}, @@ -1347,7 +1446,9 @@ jQuery.extend({ return; } - var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache, + var thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", // We have to handle DOM nodes and JS objects differently because IE6-7 // can't GC object references properly across the DOM-JS boundary @@ -1363,7 +1464,7 @@ jQuery.extend({ // Avoid doing any more work than we need to when trying to get data on an // object that has no data at all - if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) { + if ( (!id || (pvt && id && (cache[ id ] && !cache[ id ][ internalKey ]))) && getByName && data === undefined ) { return; } @@ -1412,7 +1513,7 @@ jQuery.extend({ } if ( data !== undefined ) { - thisCache[ name ] = data; + thisCache[ jQuery.camelCase( name ) ] = data; } // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should @@ -1422,7 +1523,24 @@ jQuery.extend({ return thisCache[ internalKey ] && thisCache[ internalKey ].events; } - return getByName ? thisCache[ name ] : thisCache; + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; }, removeData: function( elem, name, pvt /* Internal Use Only */ ) { @@ -1430,7 +1548,12 @@ jQuery.extend({ return; } - var internalKey = jQuery.expando, isNode = elem.nodeType, + var thisCache, + + // Reference to internal data cache key + internalKey = jQuery.expando, + + isNode = elem.nodeType, // See jQuery.data for more information cache = isNode ? jQuery.cache : elem, @@ -1445,9 +1568,16 @@ jQuery.extend({ } if ( name ) { - var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ]; + + thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ]; if ( thisCache ) { + + // Support interoperable removal of hyphenated or camelcased keys + if ( !thisCache[ name ] ) { + name = jQuery.camelCase( name ); + } + delete thisCache[ name ]; // If there is no data left in the cache, we want to continue @@ -1474,7 +1604,8 @@ jQuery.extend({ // Browsers that fail expando deletion also refuse to delete expandos on // the window, but it will allow it on all other JS objects; other browsers // don't care - if ( jQuery.support.deleteExpando || cache != window ) { + // Ensure that `cache` is not a window object #10080 + if ( jQuery.support.deleteExpando || !cache.setInterval ) { delete cache[ id ]; } else { cache[ id ] = null; @@ -1538,12 +1669,13 @@ jQuery.fn.extend({ data = jQuery.data( this[0] ); if ( this[0].nodeType === 1 ) { - var attr = this[0].attributes, name; + var attr = this[0].attributes, name; for ( var i = 0, l = attr.length; i < l; i++ ) { name = attr[i].name; if ( name.indexOf( "data-" ) === 0 ) { - name = name.substr( 5 ); + name = jQuery.camelCase( name.substring(5) ); + dataAttr( this[0], name, data[ name ] ); } } @@ -1597,7 +1729,10 @@ function dataAttr( elem, key, data ) { // If nothing was found internally, try to fetch any // data from the HTML5 data-* attribute if ( data === undefined && elem.nodeType === 1 ) { - data = elem.getAttribute( "data-" + key ); + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); if ( typeof data === "string" ) { try { @@ -1636,35 +1771,76 @@ function isEmptyDataObject( obj ) { +function handleQueueMarkDefer( elem, type, src ) { + var deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + defer = jQuery.data( elem, deferDataKey, undefined, true ); + if ( defer && + ( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) && + ( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) { + // Give room for hard-coded callbacks to fire first + // and eventually mark/queue something else on the element + setTimeout( function() { + if ( !jQuery.data( elem, queueDataKey, undefined, true ) && + !jQuery.data( elem, markDataKey, undefined, true ) ) { + jQuery.removeData( elem, deferDataKey, true ); + defer.resolve(); + } + }, 0 ); + } +} + jQuery.extend({ - queue: function( elem, type, data ) { - if ( !elem ) { - return; + + _mark: function( elem, type ) { + if ( elem ) { + type = (type || "fx") + "mark"; + jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true ); } + }, - type = (type || "fx") + "queue"; - var q = jQuery._data( elem, type ); + _unmark: function( force, elem, type ) { + if ( force !== true ) { + type = elem; + elem = force; + force = false; + } + if ( elem ) { + type = type || "fx"; + var key = type + "mark", + count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 ); + if ( count ) { + jQuery.data( elem, key, count, true ); + } else { + jQuery.removeData( elem, key, true ); + handleQueueMarkDefer( elem, type, "mark" ); + } + } + }, - // Speed up dequeue by getting out quickly if this is just a lookup - if ( !data ) { + queue: function( elem, type, data ) { + if ( elem ) { + type = (type || "fx") + "queue"; + var q = jQuery.data( elem, type, undefined, true ); + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !q || jQuery.isArray(data) ) { + q = jQuery.data( elem, type, jQuery.makeArray(data), true ); + } else { + q.push( data ); + } + } return q || []; } - - if ( !q || jQuery.isArray(data) ) { - q = jQuery._data( elem, type, jQuery.makeArray(data) ); - - } else { - q.push( data ); - } - - return q; }, dequeue: function( elem, type ) { type = type || "fx"; var queue = jQuery.queue( elem, type ), - fn = queue.shift(); + fn = queue.shift(), + defer; // If the fx queue is dequeued, always remove the progress sentinel if ( fn === "inprogress" ) { @@ -1685,6 +1861,7 @@ jQuery.extend({ if ( !queue.length ) { jQuery.removeData( elem, type + "queue", true ); + handleQueueMarkDefer( elem, type, "queue" ); } } }); @@ -1699,7 +1876,7 @@ jQuery.fn.extend({ if ( data === undefined ) { return jQuery.queue( this[0], type ); } - return this.each(function( i ) { + return this.each(function() { var queue = jQuery.queue( this, type, data ); if ( type === "fx" && queue[0] !== "inprogress" ) { @@ -1712,7 +1889,6 @@ jQuery.fn.extend({ jQuery.dequeue( this, type ); }); }, - // Based off of the plugin by Clint Helfers, with permission. // http://blindsignals.com/index.php/2009/07/jquery-delay/ delay: function( time, type ) { @@ -1726,9 +1902,41 @@ jQuery.fn.extend({ }, time ); }); }, - clearQueue: function( type ) { return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, object ) { + if ( typeof type !== "string" ) { + object = type; + type = undefined; + } + type = type || "fx"; + var defer = jQuery.Deferred(), + elements = this, + i = elements.length, + count = 1, + deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + tmp; + function resolve() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + } + while( i-- ) { + if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || + ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || + jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && + jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) { + count++; + tmp.done( resolve ); + } + } + resolve(); + return defer.promise(); } }); @@ -1736,66 +1944,66 @@ jQuery.fn.extend({ var rclass = /[\n\t\r]/g, - rspaces = /\s+/, + rspace = /\s+/, rreturn = /\r/g, - rspecialurl = /^(?:href|src|style)$/, rtype = /^(?:button|input)$/i, rfocusable = /^(?:button|input|object|select|textarea)$/i, rclickable = /^a(?:rea)?$/i, - rradiocheck = /^(?:radio|checkbox)$/i; - -jQuery.props = { - "for": "htmlFor", - "class": "className", - readonly: "readOnly", - maxlength: "maxLength", - cellspacing: "cellSpacing", - rowspan: "rowSpan", - colspan: "colSpan", - tabindex: "tabIndex", - usemap: "useMap", - frameborder: "frameBorder" -}; + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + nodeHook, boolHook; jQuery.fn.extend({ attr: function( name, value ) { return jQuery.access( this, name, value, true, jQuery.attr ); }, - removeAttr: function( name, fn ) { - return this.each(function(){ - jQuery.attr( this, name, "" ); - if ( this.nodeType === 1 ) { - this.removeAttribute( name ); - } + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.prop ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} }); }, addClass: function( value ) { - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - self.addClass( value.call(this, i, self.attr("class")) ); + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); }); } if ( value && typeof value === "string" ) { - var classNames = (value || "").split( rspaces ); + classNames = value.split( rspace ); - for ( var i = 0, l = this.length; i < l; i++ ) { - var elem = this[i]; + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; if ( elem.nodeType === 1 ) { - if ( !elem.className ) { + if ( !elem.className && classNames.length === 1 ) { elem.className = value; } else { - var className = " " + elem.className + " ", - setClass = elem.className; + setClass = " " + elem.className + " "; - for ( var c = 0, cl = classNames.length; c < cl; c++ ) { - if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) { - setClass += " " + classNames[c]; + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { + setClass += classNames[ c ] + " "; } } elem.className = jQuery.trim( setClass ); @@ -1808,24 +2016,25 @@ jQuery.fn.extend({ }, removeClass: function( value ) { - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - self.removeClass( value.call(this, i, self.attr("class")) ); + var classNames, i, l, elem, className, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); }); } if ( (value && typeof value === "string") || value === undefined ) { - var classNames = (value || "").split( rspaces ); + classNames = (value || "").split( rspace ); - for ( var i = 0, l = this.length; i < l; i++ ) { - var elem = this[i]; + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; if ( elem.nodeType === 1 && elem.className ) { if ( value ) { - var className = (" " + elem.className + " ").replace(rclass, " "); - for ( var c = 0, cl = classNames.length; c < cl; c++ ) { - className = className.replace(" " + classNames[c] + " ", " "); + className = (" " + elem.className + " ").replace( rclass, " " ); + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[ c ] + " ", " "); } elem.className = jQuery.trim( className ); @@ -1844,9 +2053,8 @@ jQuery.fn.extend({ isBool = typeof stateVal === "boolean"; if ( jQuery.isFunction( value ) ) { - return this.each(function(i) { - var self = jQuery(this); - self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal ); + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); }); } @@ -1857,7 +2065,7 @@ jQuery.fn.extend({ i = 0, self = jQuery( this ), state = stateVal, - classNames = value.split( rspaces ); + classNames = value.split( rspace ); while ( (className = classNames[ i++ ]) ) { // check each className given, space seperated list @@ -1880,7 +2088,7 @@ jQuery.fn.extend({ hasClass: function( selector ) { var className = " " + selector + " "; for ( var i = 0, l = this.length; i < l; i++ ) { - if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { return true; } } @@ -1889,82 +2097,42 @@ jQuery.fn.extend({ }, val: function( value ) { + var hooks, ret, + elem = this[0]; + if ( !arguments.length ) { - var elem = this[0]; - if ( elem ) { - if ( jQuery.nodeName( elem, "option" ) ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; + hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; } - // We need to handle select boxes special - if ( jQuery.nodeName( elem, "select" ) ) { - var index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { - var option = options[ i ]; - - // Don't return options that are disabled or in a disabled optgroup - if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && - (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { - - // Get the specific value for the option - value = jQuery(option).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - // Fixes Bug #2551 -- select.val() broken in IE after form.reset() - if ( one && !values.length && options.length ) { - return jQuery( options[ index ] ).val(); - } - - return values; - } - - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) { - return elem.getAttribute("value") === null ? "on" : elem.value; - } - - // Everything else, we just grab the value - return (elem.value || "").replace(rreturn, ""); + ret = elem.value; + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; } return undefined; } - var isFunction = jQuery.isFunction(value); + var isFunction = jQuery.isFunction( value ); - return this.each(function(i) { - var self = jQuery(this), val = value; + return this.each(function( i ) { + var self = jQuery(this), val; if ( this.nodeType !== 1 ) { return; } if ( isFunction ) { - val = value.call(this, i, self.val()); + val = value.call( this, i, self.val() ); + } else { + val = value; } // Treat null/undefined as ""; convert numbers to string @@ -1972,27 +2140,16 @@ jQuery.fn.extend({ val = ""; } else if ( typeof val === "number" ) { val += ""; - } else if ( jQuery.isArray(val) ) { - val = jQuery.map(val, function (value) { + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { return value == null ? "" : value + ""; }); } - if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) { - this.checked = jQuery.inArray( self.val(), val ) >= 0; + hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; - } else if ( jQuery.nodeName( this, "select" ) ) { - var values = jQuery.makeArray(val); - - jQuery( "option", this ).each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - this.selectedIndex = -1; - } - - } else { + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { this.value = val; } }); @@ -2000,6 +2157,72 @@ jQuery.fn.extend({ }); jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, + index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + attrFn: { val: true, css: true, @@ -2010,124 +2233,346 @@ jQuery.extend({ height: true, offset: true }, - + + attrFix: { + // Always normalize to ensure hook usage + tabindex: "tabIndex" + }, + attr: function( elem, name, value, pass ) { + var nType = elem.nodeType; + // don't get/set attributes on text, comment and attribute nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || elem.nodeType === 2 ) { + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return undefined; } if ( pass && name in jQuery.attrFn ) { - return jQuery(elem)[name](value); + return jQuery( elem )[ name ]( value ); } - var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), - // Whether we are setting (or getting) - set = value !== undefined; + // Fallback to prop when attributes are not supported + if ( !("getAttribute" in elem) ) { + return jQuery.prop( elem, name, value ); + } - // Try to normalize/fix the name - name = notxml && jQuery.props[ name ] || name; + var ret, hooks, + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - // Only do all the following if this is a node (faster for style) - if ( elem.nodeType === 1 ) { - // These attributes require special treatment - var special = rspecialurl.test( name ); + // Normalize the name if needed + if ( notxml ) { + name = jQuery.attrFix[ name ] || name; - // Safari mis-reports the default selected property of an option - // Accessing the parent's selectedIndex property fixes it - if ( name === "selected" && !jQuery.support.optSelected ) { - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; + hooks = jQuery.attrHooks[ name ]; - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } + if ( !hooks ) { + // Use boolHook for boolean attributes + if ( rboolean.test( name ) ) { + hooks = boolHook; + + // Use nodeHook if available( IE6/7 ) + } else if ( nodeHook ) { + hooks = nodeHook; } } + } - // If applicable, access the attribute via the DOM 0 way - // 'in' checks fail in Blackberry 4.7 #6931 - if ( (name in elem || elem[ name ] !== undefined) && notxml && !special ) { - if ( set ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } + if ( value !== undefined ) { - if ( value === null ) { - if ( elem.nodeType === 1 ) { - elem.removeAttribute( name ); - } - - } else { - elem[ name ] = value; - } - } - - // browsers index elements by id/name on forms, give priority to attributes. - if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { - return elem.getAttributeNode( name ).nodeValue; - } - - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - if ( name === "tabIndex" ) { - var attributeNode = elem.getAttributeNode( "tabIndex" ); - - return attributeNode && attributeNode.specified ? - attributeNode.value : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - - return elem[ name ]; - } - - if ( !jQuery.support.style && notxml && name === "style" ) { - if ( set ) { - elem.style.cssText = "" + value; - } - - return elem.style.cssText; - } - - if ( set ) { - // convert the value to a string (all browsers do this but IE) see #1070 - elem.setAttribute( name, "" + value ); - } - - // Ensure that missing attributes return undefined - // Blackberry 4.7 returns "" from getAttribute #6938 - if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); return undefined; + + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, "" + value ); + return value; } - var attr = !jQuery.support.hrefNormalized && notxml && special ? - // Some attributes require a special call on IE - elem.getAttribute( name, 2 ) : - elem.getAttribute( name ); + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + ret = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined - return attr === null ? undefined : attr; + return ret === null ? + undefined : + ret; } - // Handle everything which isn't a DOM element node - if ( set ) { - elem[ name ] = value; + }, + + removeAttr: function( elem, name ) { + var propName; + if ( elem.nodeType === 1 ) { + name = jQuery.attrFix[ name ] || name; + + jQuery.attr( elem, name, "" ); + elem.removeAttribute( name ); + + // Set corresponding property to false for boolean attributes + if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) { + elem[ propName ] = false; + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + // Use the value property for back compat + // Use the nodeHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return undefined; + } + + var ret, hooks, + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return (elem[ name ] = value); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } } - return elem[ name ]; } }); +// Add the tabindex propHook to attrHooks for back-compat +jQuery.attrHooks.tabIndex = jQuery.propHooks.tabIndex; + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + // Fall back to attribute presence where some booleans are not supported + var attrNode; + return jQuery.prop( elem, name ) === true || ( attrNode = elem.getAttributeNode( name ) ) && attrNode.nodeValue !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !jQuery.support.getSetAttribute ) { + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + // Return undefined if nodeValue is empty string + return ret && ret.nodeValue !== "" ? + ret.nodeValue : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + ret = document.createAttribute( name ); + elem.setAttributeNode( ret ); + } + return (ret.nodeValue = value + ""); + } + }; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return (elem.style.cssText = "" + value); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0); + } + } + }); +}); + var rnamespaces = /\.(.*)$/, rformElems = /^(?:textarea|input|select)$/i, rperiod = /\./g, - rspace = / /g, + rspaces = / /g, rescape = /[^\w\s.|`]/g, fcleanup = function( nm ) { return nm.replace(rescape, "\\$&"); @@ -2147,17 +2592,6 @@ jQuery.event = { return; } - // TODO :: Use a try/catch until it's safe to pull this out (likely 1.6) - // Minor release fix for bug #8018 - try { - // For whatever reason, IE has trouble passing the window object - // around, causing it to be cloned in the process - if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) { - elem = window; - } - } - catch ( e ) {} - if ( handler === false ) { handler = returnFalse; } else if ( !handler ) { @@ -2194,10 +2628,10 @@ jQuery.event = { } if ( !eventHandle ) { - elemData.handle = eventHandle = function() { - // Handle the second event of a trigger and when - // an event is called after a page has unloaded - return typeof jQuery !== "undefined" && !jQuery.event.triggered ? + elemData.handle = eventHandle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? jQuery.event.handle.apply( eventHandle.elem, arguments ) : undefined; }; @@ -2267,7 +2701,7 @@ jQuery.event = { // Add the function to the element's handler list handlers.push( handleObj ); - // Keep track of which events have been used, for global triggering + // Keep track of which events have been used, for event optimization jQuery.event.global[ type ] = true; } @@ -2400,186 +2834,189 @@ jQuery.event = { } } }, - - // bubbling is internal - trigger: function( event, data, elem /*, bubbling */ ) { - // Event object or event type - var type = event.type || event, - bubbling = arguments[3]; - - if ( !bubbling ) { - event = typeof event === "object" ? - // jQuery.Event object - event[ jQuery.expando ] ? event : - // Object literal - jQuery.extend( jQuery.Event(type), event ) : - // Just the event type (string) - jQuery.Event(type); - - if ( type.indexOf("!") >= 0 ) { - event.type = type = type.slice(0, -1); - event.exclusive = true; - } - - // Handle a global trigger - if ( !elem ) { - // Don't bubble custom events when global (to avoid too much overhead) - event.stopPropagation(); - - // Only trigger if we've ever bound an event for it - if ( jQuery.event.global[ type ] ) { - // XXX This code smells terrible. event.js should not be directly - // inspecting the data cache - jQuery.each( jQuery.cache, function() { - // internalKey variable is just used to make it easier to find - // and potentially change this stuff later; currently it just - // points to jQuery.expando - var internalKey = jQuery.expando, - internalCache = this[ internalKey ]; - if ( internalCache && internalCache.events && internalCache.events[ type ] ) { - jQuery.event.trigger( event, data, internalCache.handle.elem ); - } - }); - } - } - - // Handle triggering a single element - - // don't do events on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { - return undefined; - } - - // Clean up in case it is reused - event.result = undefined; - event.target = elem; - - // Clone the incoming data, if any - data = jQuery.makeArray( data ); - data.unshift( event ); - } - - event.currentTarget = elem; - - // Trigger the event, it is assumed that "handle" is a function - var handle = jQuery._data( elem, "handle" ); - - if ( handle ) { - handle.apply( elem, data ); - } - - var parent = elem.parentNode || elem.ownerDocument; - - // Trigger an inline bound script - try { - if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) { - if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) { - event.result = false; - event.preventDefault(); - } - } - - // prevent IE from throwing an error for some elements with some event types, see #3533 - } catch (inlineError) {} - - if ( !event.isPropagationStopped() && parent ) { - jQuery.event.trigger( event, data, parent, true ); - - } else if ( !event.isDefaultPrevented() ) { - var old, - target = event.target, - targetType = type.replace( rnamespaces, "" ), - isClick = jQuery.nodeName( target, "a" ) && targetType === "click", - special = jQuery.event.special[ targetType ] || {}; - - if ( (!special._default || special._default.call( elem, event ) === false) && - !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) { - - try { - if ( target[ targetType ] ) { - // Make sure that we don't accidentally re-trigger the onFOO events - old = target[ "on" + targetType ]; - - if ( old ) { - target[ "on" + targetType ] = null; - } - - jQuery.event.triggered = true; - target[ targetType ](); - } - - // prevent IE from throwing an error for some elements with some event types, see #3533 - } catch (triggerError) {} - - if ( old ) { - target[ "on" + targetType ] = old; - } - - jQuery.event.triggered = false; - } - } + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true }, - handle: function( event ) { - var all, handlers, namespaces, namespace_re, events, - namespace_sort = [], - args = jQuery.makeArray( arguments ); + trigger: function( event, data, elem, onlyHandlers ) { + // Event object or event type + var type = event.type || event, + namespaces = [], + exclusive; - event = args[0] = jQuery.event.fix( event || window.event ); - event.currentTarget = this; - - // Namespaced event handlers - all = event.type.indexOf(".") < 0 && !event.exclusive; - - if ( !all ) { - namespaces = event.type.split("."); - event.type = namespaces.shift(); - namespace_sort = namespaces.slice(0).sort(); - namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)"); + if ( type.indexOf("!") >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; } - event.namespace = event.namespace || namespace_sort.join("."); + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } - events = jQuery._data(this, "events"); + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } - handlers = (events || {})[ event.type ]; + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); - if ( events && handlers ) { - // Clone the handlers to prevent manipulation - handlers = handlers.slice(0); + event.type = type; + event.exclusive = exclusive; + event.namespace = namespaces.join("."); + event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)"); + + // triggerHandler() and global events don't bubble or run the default action + if ( onlyHandlers || !elem ) { + event.preventDefault(); + event.stopPropagation(); + } - for ( var j = 0, l = handlers.length; j < l; j++ ) { - var handleObj = handlers[ j ]; - - // Filter the functions by class - if ( all || namespace_re.test( handleObj.namespace ) ) { - // Pass in a reference to the handler function itself - // So that we can later remove it - event.handler = handleObj.handler; - event.data = handleObj.data; - event.handleObj = handleObj; - - var ret = handleObj.handler.apply( this, args ); - - if ( ret !== undefined ) { - event.result = ret; - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - - if ( event.isImmediatePropagationStopped() ) { - break; - } + // Handle a global trigger + if ( !elem ) { + // TODO: Stop taunting the data cache; remove global events and always attach to document + jQuery.each( jQuery.cache, function() { + // internalKey variable is just used to make it easier to find + // and potentially change this stuff later; currently it just + // points to jQuery.expando + var internalKey = jQuery.expando, + internalCache = this[ internalKey ]; + if ( internalCache && internalCache.events && internalCache.events[ type ] ) { + jQuery.event.trigger( event, data, internalCache.handle.elem ); } + }); + return; + } + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // Clean up the event in case it is being reused + event.result = undefined; + event.target = elem; + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data != null ? jQuery.makeArray( data ) : []; + data.unshift( event ); + + var cur = elem, + // IE doesn't like method names with a colon (#3533, #8272) + ontype = type.indexOf(":") < 0 ? "on" + type : ""; + + // Fire event on the current element, then bubble up the DOM tree + do { + var handle = jQuery._data( cur, "handle" ); + + event.currentTarget = cur; + if ( handle ) { + handle.apply( cur, data ); + } + + // Trigger an inline bound script + if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) { + event.result = false; + event.preventDefault(); + } + + // Bubble up to document, then to window + cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window; + } while ( cur && !event.isPropagationStopped() ); + + // If nobody prevented the default action, do it now + if ( !event.isDefaultPrevented() ) { + var old, + special = jQuery.event.special[ type ] || {}; + + if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction)() check here because IE6/7 fails that test. + // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch. + try { + if ( ontype && elem[ type ] ) { + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; + + if ( old ) { + elem[ ontype ] = null; + } + + jQuery.event.triggered = type; + elem[ type ](); + } + } catch ( ieError ) {} + + if ( old ) { + elem[ ontype ] = old; + } + + jQuery.event.triggered = undefined; } } - + return event.result; }, - props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), + handle: function( event ) { + event = jQuery.event.fix( event || window.event ); + // Snapshot the handlers list since a called handler may add/remove events. + var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0), + run_all = !event.exclusive && !event.namespace, + args = Array.prototype.slice.call( arguments, 0 ); + + // Use the fix-ed Event rather than the (read-only) native event + args[0] = event; + event.currentTarget = this; + + for ( var j = 0, l = handlers.length; j < l; j++ ) { + var handleObj = handlers[ j ]; + + // Triggered event must 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event. + if ( run_all || event.namespace_re.test( handleObj.namespace ) ) { + // Pass in a reference to the handler function itself + // So that we can later remove it + event.handler = handleObj.handler; + event.data = handleObj.data; + event.handleObj = handleObj; + + var ret = handleObj.handler.apply( this, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + return event.result; + }, + + props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), fix: function( event ) { if ( event[ jQuery.expando ] ) { @@ -2614,8 +3051,9 @@ jQuery.event = { // Calculate pageX/Y if missing and clientX/Y available if ( event.pageX == null && event.clientX != null ) { - var doc = document.documentElement, - body = document.body; + var eventDocument = event.target.ownerDocument || document, + doc = eventDocument.documentElement, + body = eventDocument.body; event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); @@ -2694,10 +3132,10 @@ jQuery.removeEvent = document.removeEventListener ? } }; -jQuery.Event = function( src ) { +jQuery.Event = function( src, props ) { // Allow instantiation without the 'new' keyword if ( !this.preventDefault ) { - return new jQuery.Event( src ); + return new jQuery.Event( src, props ); } // Event object @@ -2715,6 +3153,11 @@ jQuery.Event = function( src ) { this.type = src; } + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + // timeStamp is buggy for some events on Firefox(#3843) // So we won't rely on the native value this.timeStamp = jQuery.now(); @@ -2776,33 +3219,27 @@ jQuery.Event.prototype = { // Checks if an event happened on an element within another element // Used in jQuery.event.special.mouseenter and mouseleave handlers var withinElement = function( event ) { + // Check if mouse(over|out) are still within the same parent element - var parent = event.relatedTarget; + var related = event.relatedTarget, + inside = false, + eventType = event.type; - // Firefox sometimes assigns relatedTarget a XUL element - // which we cannot access the parentNode property of - try { + event.type = event.data; - // Chrome does something similar, the parentNode property - // can be accessed but is null. - if ( parent !== document && !parent.parentNode ) { - return; - } - // Traverse up the tree - while ( parent && parent !== this ) { - parent = parent.parentNode; + if ( related !== this ) { + + if ( related ) { + inside = jQuery.contains( this, related ); } - if ( parent !== this ) { - // set the correct event type - event.type = event.data; + if ( !inside ) { - // handle event if we actually just moused on to a non sub-element jQuery.event.handle.apply( this, arguments ); - } - // assuming we've left the element since we most likely mousedover a xul element - } catch(e) { } + event.type = eventType; + } + } }, // In case of event delegation, we only need to rename the event.type, @@ -2832,10 +3269,11 @@ if ( !jQuery.support.submitBubbles ) { jQuery.event.special.submit = { setup: function( data, namespaces ) { - if ( this.nodeName && this.nodeName.toLowerCase() !== "form" ) { + if ( !jQuery.nodeName( this, "form" ) ) { jQuery.event.add(this, "click.specialSubmit", function( e ) { + // Avoid triggering error on non-existent type attribute in IE VML (#7071) var elem = e.target, - type = elem.type; + type = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.type : ""; if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { trigger( "submit", this, arguments ); @@ -2844,7 +3282,7 @@ if ( !jQuery.support.submitBubbles ) { jQuery.event.add(this, "keypress.specialSubmit", function( e ) { var elem = e.target, - type = elem.type; + type = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.type : ""; if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { trigger( "submit", this, arguments ); @@ -2869,7 +3307,8 @@ if ( !jQuery.support.changeBubbles ) { var changeFilters, getVal = function( elem ) { - var type = elem.type, val = elem.value; + var type = jQuery.nodeName( elem, "input" ) ? elem.type : "", + val = elem.value; if ( type === "radio" || type === "checkbox" ) { val = elem.checked; @@ -2881,7 +3320,7 @@ if ( !jQuery.support.changeBubbles ) { }).join("-") : ""; - } else if ( elem.nodeName.toLowerCase() === "select" ) { + } else if ( jQuery.nodeName( elem, "select" ) ) { val = elem.selectedIndex; } @@ -2921,9 +3360,9 @@ if ( !jQuery.support.changeBubbles ) { beforedeactivate: testChange, click: function( e ) { - var elem = e.target, type = elem.type; + var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; - if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) { + if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) { testChange.call( this, e ); } }, @@ -2931,9 +3370,9 @@ if ( !jQuery.support.changeBubbles ) { // Change has to be called before submit // Keydown will be called before keypress, which is used in submit-event delegation keydown: function( e ) { - var elem = e.target, type = elem.type; + var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; - if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") || + if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) || (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || type === "select-multiple" ) { testChange.call( this, e ); @@ -2990,27 +3429,43 @@ function trigger( type, elem, args ) { } // Create "bubbling" focus and blur events -if ( document.addEventListener ) { +if ( !jQuery.support.focusinBubbles ) { jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0; + jQuery.event.special[ fix ] = { setup: function() { - this.addEventListener( orig, handler, true ); + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } }, teardown: function() { - this.removeEventListener( orig, handler, true ); + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } } }; - function handler( e ) { - e = jQuery.event.fix( e ); + function handler( donor ) { + // Donor event is always a native one; fix it and switch its type. + // Let focusin/out handler cancel the donor focus/blur event. + var e = jQuery.event.fix( donor ); e.type = fix; - return jQuery.event.handle.call( this, e ); + e.originalEvent = {}; + jQuery.event.trigger( e, null, e.target ); + if ( e.isDefaultPrevented() ) { + donor.preventDefault(); + } } }); } jQuery.each(["bind", "one"], function( i, name ) { jQuery.fn[ name ] = function( type, data, fn ) { + var handler; + // Handle object literals if ( typeof type === "object" ) { for ( var key in type ) { @@ -3019,15 +3474,20 @@ jQuery.each(["bind", "one"], function( i, name ) { return this; } - if ( jQuery.isFunction( data ) || data === false ) { + if ( arguments.length === 2 || data === false ) { fn = data; data = undefined; } - var handler = name === "one" ? jQuery.proxy( fn, function( event ) { - jQuery( this ).unbind( event, handler ); - return fn.apply( this, arguments ); - }) : fn; + if ( name === "one" ) { + handler = function( event ) { + jQuery( this ).unbind( event, handler ); + return fn.apply( this, arguments ); + }; + handler.guid = fn.guid || jQuery.guid++; + } else { + handler = fn; + } if ( type === "unload" && name !== "one" ) { this.one( type, data, fn ); @@ -3065,7 +3525,7 @@ jQuery.fn.extend({ undelegate: function( selector, types, fn ) { if ( arguments.length === 0 ) { - return this.unbind( "live" ); + return this.unbind( "live" ); } else { return this.die( types, null, fn, selector ); @@ -3080,35 +3540,34 @@ jQuery.fn.extend({ triggerHandler: function( type, data ) { if ( this[0] ) { - var event = jQuery.Event( type ); - event.preventDefault(); - event.stopPropagation(); - jQuery.event.trigger( event, data, this[0] ); - return event.result; + return jQuery.event.trigger( type, data, this[0], true ); } }, toggle: function( fn ) { // Save reference to arguments for access in closure var args = arguments, - i = 1; + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; while ( i < args.length ) { - jQuery.proxy( fn, args[ i++ ] ); + args[ i++ ].guid = guid; } - return this.click( jQuery.proxy( fn, function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - })); + return this.click( toggler ); }, hover: function( fnOver, fnOut ) { @@ -3137,8 +3596,16 @@ jQuery.each(["live", "die"], function( i, name ) { return this; } - if ( jQuery.isFunction( data ) ) { - fn = data; + if ( name === "die" && !types && + origSelector && origSelector.charAt(0) === "." ) { + + context.unbind( origSelector ); + + return this; + } + + if ( data === false || jQuery.isFunction( data ) ) { + fn = data || returnFalse; data = undefined; } @@ -3160,7 +3627,7 @@ jQuery.each(["live", "die"], function( i, name ) { preType = type; - if ( type === "focus" || type === "blur" ) { + if ( liveMap[ type ] ) { types.push( liveMap[ type ] + namespaces ); type = type + namespaces; @@ -3231,6 +3698,11 @@ function liveHandler( event ) { if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { event.type = handleObj.preType; related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; + + // Make sure not to accidentally match a child element with the same selector + if ( related && jQuery.contains( elem, related ) ) { + related = elem; + } } if ( !related || related !== elem ) { @@ -3269,7 +3741,7 @@ function liveHandler( event ) { } function liveConvert( type, selector ) { - return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&"); + return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&"); } jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + @@ -3294,6 +3766,7 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl }); + /*! * Sizzle CSS Selector Engine * Copyright 2011, The Dojo Foundation @@ -3918,43 +4391,53 @@ var Expr = Sizzle.selectors = { }, text: function( elem ) { + var attr = elem.getAttribute( "type" ), type = elem.type; // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) // use getAttribute instead to test this case - return "text" === elem.getAttribute( 'type' ); + return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); }, + radio: function( elem ) { - return "radio" === elem.type; + return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; }, checkbox: function( elem ) { - return "checkbox" === elem.type; + return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; }, file: function( elem ) { - return "file" === elem.type; + return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; }, + password: function( elem ) { - return "password" === elem.type; + return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; }, submit: function( elem ) { - return "submit" === elem.type; + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "submit" === elem.type; }, image: function( elem ) { - return "image" === elem.type; + return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; }, reset: function( elem ) { - return "reset" === elem.type; + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "reset" === elem.type; }, button: function( elem ) { - return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; + var name = elem.nodeName.toLowerCase(); + return name === "input" && "button" === elem.type || name === "button"; }, input: function( elem ) { return (/input|select|textarea|button/i).test( elem.nodeName ); + }, + + focus: function( elem ) { + return elem === elem.ownerDocument.activeElement; } }, setFilters: { @@ -4207,6 +4690,16 @@ if ( document.documentElement.compareDocumentPosition ) { } else { sortOrder = function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + var al, bl, ap = [], bp = [], @@ -4214,13 +4707,8 @@ if ( document.documentElement.compareDocumentPosition ) { bup = b.parentNode, cur = aup; - // The nodes are identical, we can exit early - if ( a === b ) { - hasDuplicate = true; - return 0; - // If the nodes are siblings (or identical) we can do a quick check - } else if ( aup === bup ) { + if ( aup === bup ) { return siblingCheck( a, b ); // If no parents were found then the nodes are disconnected @@ -4496,19 +4984,23 @@ if ( document.querySelectorAll ) { (function(){ var html = document.documentElement, - matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector, - pseudoWorks = false; - - try { - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( document.documentElement, "[test!='']:sizzle" ); - - } catch( pseudoError ) { - pseudoWorks = true; - } + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; if ( matches ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9 fails this) + var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + Sizzle.matchesSelector = function( node, expr ) { // Make sure that attribute selectors are quoted expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); @@ -4516,7 +5008,15 @@ if ( document.querySelectorAll ) { if ( !Sizzle.isXML( node ) ) { try { if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { - return matches.call( node, expr ); + var ret = matches.call( node, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || !disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9, so check for that + node.document && node.document.nodeType !== 11 ) { + return ret; + } } } catch(e) {} } @@ -4705,17 +5205,30 @@ var runtil = /Until$/, jQuery.fn.extend({ find: function( selector ) { - var ret = this.pushStack( "", "find", selector ), - length = 0; + var self = this, + i, l; - for ( var i = 0, l = this.length; i < l; i++ ) { + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + var ret = this.pushStack( "", "find", selector ), + length, n, r; + + for ( i = 0, l = this.length; i < l; i++ ) { length = ret.length; jQuery.find( selector, this[i], ret ); if ( i > 0 ) { // Make sure that the results are unique - for ( var n = length; n < ret.length; n++ ) { - for ( var r = 0; r < length; r++ ) { + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { if ( ret[r] === ret[n] ) { ret.splice(n--, 1); break; @@ -4748,12 +5261,15 @@ jQuery.fn.extend({ }, is: function( selector ) { - return !!selector && jQuery.filter( selector, this ).length > 0; + return !!selector && ( typeof selector === "string" ? + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); }, closest: function( selectors, context ) { var ret = [], i, l, cur = this[0]; - + + // Array if ( jQuery.isArray( selectors ) ) { var match, selector, matches = {}, @@ -4763,8 +5279,8 @@ jQuery.fn.extend({ for ( i = 0, l = selectors.length; i < l; i++ ) { selector = selectors[i]; - if ( !matches[selector] ) { - matches[selector] = jQuery.expr.match.POS.test( selector ) ? + if ( !matches[ selector ] ) { + matches[ selector ] = POS.test( selector ) ? jQuery( selector, context || this.context ) : selector; } @@ -4772,9 +5288,9 @@ jQuery.fn.extend({ while ( cur && cur.ownerDocument && cur !== context ) { for ( selector in matches ) { - match = matches[selector]; + match = matches[ selector ]; - if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) { + if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) { ret.push({ selector: selector, elem: cur, level: level }); } } @@ -4787,8 +5303,10 @@ jQuery.fn.extend({ return ret; } - var pos = POS.test( selectors ) ? - jQuery( selectors, context || this.context ) : null; + // String + var pos = POS.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; for ( i = 0, l = this.length; i < l; i++ ) { cur = this[i]; @@ -4800,14 +5318,14 @@ jQuery.fn.extend({ } else { cur = cur.parentNode; - if ( !cur || !cur.ownerDocument || cur === context ) { + if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { break; } } } } - ret = ret.length > 1 ? jQuery.unique(ret) : ret; + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; return this.pushStack( ret, "closest", selectors ); }, @@ -4815,12 +5333,17 @@ jQuery.fn.extend({ // Determine the position of an element within // the matched set of elements index: function( elem ) { - if ( !elem || typeof elem === "string" ) { - return jQuery.inArray( this[0], - // If it receives a string, the selector is used - // If it receives nothing, the siblings are used - elem ? jQuery( elem ) : this.parent().children() ); + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + // Locate the position of the desired element return jQuery.inArray( // If it receives a jQuery object, the first element is used @@ -4830,7 +5353,7 @@ jQuery.fn.extend({ add: function( selector, context ) { var set = typeof selector === "string" ? jQuery( selector, context ) : - jQuery.makeArray( selector ), + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), all = jQuery.merge( this.get(), set ); return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? @@ -4968,6 +5491,11 @@ jQuery.extend({ // Implement the identical functionality for filter and not function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + if ( jQuery.isFunction( qualifier ) ) { return jQuery.grep(elements, function( elem, i ) { var retVal = !!qualifier.call( elem, i, elem ); @@ -5008,6 +5536,8 @@ var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, rnocache = /<(?:script|object|embed|option|style)/i, // checked="checked" or checked rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, + rscriptType = /\/(java|ecma)script/i, + rcleanScript = /^\s*", "" ], legend: [ 1, "
", "
" ], @@ -5068,7 +5598,7 @@ jQuery.fn.extend({ } return elem; - }).append(this); + }).append( this ); } return this; @@ -5260,7 +5790,9 @@ jQuery.fn.extend({ } }); } else { - return this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ); + return this.length ? + this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) : + this; } }, @@ -5374,21 +5906,27 @@ function cloneCopyEvent( src, dest ) { } } -function cloneFixAttributes(src, dest) { +function cloneFixAttributes( src, dest ) { + var nodeName; + // We do not need to do anything for non-Elements if ( dest.nodeType !== 1 ) { return; } - var nodeName = dest.nodeName.toLowerCase(); - // clearAttributes removes the attributes, which we don't want, // but also removes the attachEvent events, which we *do* want - dest.clearAttributes(); + if ( dest.clearAttributes ) { + dest.clearAttributes(); + } // mergeAttributes, in contrast, only merges back on the // original attributes, not the events - dest.mergeAttributes(src); + if ( dest.mergeAttributes ) { + dest.mergeAttributes( src ); + } + + nodeName = dest.nodeName.toLowerCase(); // IE6-8 fail to clone children inside object elements that use // the proprietary classid attribute value (rather than the type @@ -5427,8 +5965,21 @@ function cloneFixAttributes(src, dest) { } jQuery.buildFragment = function( args, nodes, scripts ) { - var fragment, cacheable, cacheresults, - doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document); + var fragment, cacheable, cacheresults, doc; + + // nodes may contain either an explicit document object, + // a jQuery collection or context object. + // If nodes[0] contains a valid object to assign to doc + if ( nodes && nodes[0] ) { + doc = nodes[0].ownerDocument || nodes[0]; + } + + // Ensure that an attr object doesn't incorrectly stand in as a document object + // Chrome and Firefox seem to allow this to occur and will throw exception + // Fixes #8950 + if ( !doc.createDocumentFragment ) { + doc = document; + } // Only cache "small" (1/2 KB) HTML strings that are associated with the main document // Cloning options loses the selected state, so don't cache them @@ -5438,11 +5989,10 @@ jQuery.buildFragment = function( args, nodes, scripts ) { args[0].charAt(0) === "<" && !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) { cacheable = true; + cacheresults = jQuery.fragments[ args[0] ]; - if ( cacheresults ) { - if ( cacheresults !== 1 ) { - fragment = cacheresults; - } + if ( cacheresults && cacheresults !== 1 ) { + fragment = cacheresults; } } @@ -5491,7 +6041,7 @@ jQuery.each({ function getAll( elem ) { if ( "getElementsByTagName" in elem ) { return elem.getElementsByTagName( "*" ); - + } else if ( "querySelectorAll" in elem ) { return elem.querySelectorAll( "*" ); @@ -5500,6 +6050,21 @@ function getAll( elem ) { } } +// Used in clean, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( elem.type === "checkbox" || elem.type === "radio" ) { + elem.defaultChecked = elem.checked; + } +} +// Finds all inputs and passes them to fixDefaultChecked +function findInputs( elem ) { + if ( jQuery.nodeName( elem, "input" ) ) { + fixDefaultChecked( elem ); + } else if ( "getElementsByTagName" in elem ) { + jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); + } +} + jQuery.extend({ clone: function( elem, dataAndEvents, deepDataAndEvents ) { var clone = elem.cloneNode(true), @@ -5526,7 +6091,10 @@ jQuery.extend({ // with an element if you are cloning the body and one of the // elements on the page has a name or id of "length" for ( i = 0; srcElements[i]; ++i ) { - cloneFixAttributes( srcElements[i], destElements[i] ); + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[i] ) { + cloneFixAttributes( srcElements[i], destElements[i] ); + } } } @@ -5544,10 +6112,15 @@ jQuery.extend({ } } + srcElements = destElements = null; + // Return the cloned set return clone; -}, + }, + clean: function( elems, context, fragment, scripts ) { + var checkScriptType; + context = context || document; // !context.createElement fails in IE with an error but returns typeof 'object' @@ -5555,7 +6128,7 @@ jQuery.extend({ context = context.ownerDocument || context[0] && context[0].ownerDocument || document; } - var ret = []; + var ret = [], j; for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { if ( typeof elem === "number" ) { @@ -5567,54 +6140,67 @@ jQuery.extend({ } // Convert html string into DOM nodes - if ( typeof elem === "string" && !rhtml.test( elem ) ) { - elem = context.createTextNode( elem ); + if ( typeof elem === "string" ) { + if ( !rhtml.test( elem ) ) { + elem = context.createTextNode( elem ); + } else { + // Fix "XHTML"-style tags in all browsers + elem = elem.replace(rxhtmlTag, "<$1>"); - } else if ( typeof elem === "string" ) { - // Fix "XHTML"-style tags in all browsers - elem = elem.replace(rxhtmlTag, "<$1>"); + // Trim whitespace, otherwise indexOf won't work as expected + var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(), + wrap = wrapMap[ tag ] || wrapMap._default, + depth = wrap[0], + div = context.createElement("div"); - // Trim whitespace, otherwise indexOf won't work as expected - var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(), - wrap = wrapMap[ tag ] || wrapMap._default, - depth = wrap[0], - div = context.createElement("div"); + // Go to html and back, then peel off extra wrappers + div.innerHTML = wrap[1] + elem + wrap[2]; - // Go to html and back, then peel off extra wrappers - div.innerHTML = wrap[1] + elem + wrap[2]; + // Move to the right depth + while ( depth-- ) { + div = div.lastChild; + } - // Move to the right depth - while ( depth-- ) { - div = div.lastChild; - } + // Remove IE's autoinserted from table fragments + if ( !jQuery.support.tbody ) { - // Remove IE's autoinserted from table fragments - if ( !jQuery.support.tbody ) { + // String was a , *may* have spurious + var hasBody = rtbody.test(elem), + tbody = tag === "table" && !hasBody ? + div.firstChild && div.firstChild.childNodes : - // String was a
, *may* have spurious - var hasBody = rtbody.test(elem), - tbody = tag === "table" && !hasBody ? - div.firstChild && div.firstChild.childNodes : + // String was a bare or + wrap[1] === "
" && !hasBody ? + div.childNodes : + []; - // String was a bare or - wrap[1] === "
" && !hasBody ? - div.childNodes : - []; - - for ( var j = tbody.length - 1; j >= 0 ; --j ) { - if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { - tbody[ j ].parentNode.removeChild( tbody[ j ] ); + for ( j = tbody.length - 1; j >= 0 ; --j ) { + if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { + tbody[ j ].parentNode.removeChild( tbody[ j ] ); + } } } - } + // IE completely kills leading whitespace when innerHTML is used + if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); + } - // IE completely kills leading whitespace when innerHTML is used - if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { - div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); + elem = div.childNodes; } + } - elem = div.childNodes; + // Resets defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + var len; + if ( !jQuery.support.appendChecked ) { + if ( elem[0] && typeof (len = elem.length) === "number" ) { + for ( j = 0; j < len; j++ ) { + findInputs( elem[j] ); + } + } else { + findInputs( elem ); + } } if ( elem.nodeType ) { @@ -5625,13 +6211,18 @@ jQuery.extend({ } if ( fragment ) { + checkScriptType = function( elem ) { + return !elem.type || rscriptType.test( elem.type ); + }; for ( i = 0; ret[i]; i++ ) { if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) { scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] ); } else { if ( ret[i].nodeType === 1 ) { - ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) ); + var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType ); + + ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); } fragment.appendChild( ret[i] ); } @@ -5693,7 +6284,7 @@ function evalScript( i, elem ) { dataType: "script" }); } else { - jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); + jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) ); } if ( elem.parentNode ) { @@ -5706,10 +6297,11 @@ function evalScript( i, elem ) { var ralpha = /alpha\([^)]*\)/i, ropacity = /opacity=([^)]*)/, - rdashAlpha = /-([a-z])/ig, - rupper = /([A-Z])/g, + // fixed for IE9, see #8346 + rupper = /([A-Z]|^ms)/g, rnumpx = /^-?\d+(?:px)?$/i, rnum = /^-?\d/, + rrelNum = /^([\-+])=([\-+.\de]+)/, cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssWidth = [ "Left", "Right" ], @@ -5717,11 +6309,7 @@ var ralpha = /alpha\([^)]*\)/i, curCSS, getComputedStyle, - currentStyle, - - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }; + currentStyle; jQuery.fn.css = function( name, value ) { // Setting 'undefined' is a no-op @@ -5756,11 +6344,14 @@ jQuery.extend({ // Exclude the following css properties to add px cssNumber: { - "zIndex": true, + "fillOpacity": true, "fontWeight": true, + "lineHeight": true, "opacity": true, - "zoom": true, - "lineHeight": true + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true }, // Add in properties whose names you wish to fix before @@ -5778,20 +6369,29 @@ jQuery.extend({ } // Make sure that we're working with the right name - var ret, origName = jQuery.camelCase( name ), + var ret, type, origName = jQuery.camelCase( name ), style = elem.style, hooks = jQuery.cssHooks[ origName ]; name = jQuery.cssProps[ origName ] || origName; // Check if we're setting a value if ( value !== undefined ) { + type = typeof value; + + // convert relative number strings (+= or -=) to relative numbers. #7345 + if ( type === "string" && (ret = rrelNum.exec( value )) ) { + value = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) ); + // Fixes bug #9237 + type = "number"; + } + // Make sure that NaN and null values aren't set. See: #7116 - if ( typeof value === "number" && isNaN( value ) || value == null ) { + if ( value == null || type === "number" && isNaN( value ) ) { return; } // If a number was passed in, add 'px' to the (except for certain CSS properties) - if ( typeof value === "number" && !jQuery.cssNumber[ origName ] ) { + if ( type === "number" && !jQuery.cssNumber[ origName ] ) { value += "px"; } @@ -5816,11 +6416,17 @@ jQuery.extend({ }, css: function( elem, name, extra ) { - // Make sure that we're working with the right name - var ret, origName = jQuery.camelCase( name ), - hooks = jQuery.cssHooks[ origName ]; + var ret, hooks; - name = jQuery.cssProps[ origName ] || origName; + // Make sure that we're working with the right name + name = jQuery.camelCase( name ); + hooks = jQuery.cssHooks[ name ]; + name = jQuery.cssProps[ name ] || name; + + // cssFloat needs a special treatment + if ( name === "cssFloat" ) { + name = "float"; + } // If a hook was provided get the computed value from there if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) { @@ -5828,7 +6434,7 @@ jQuery.extend({ // Otherwise, if a way to get the computed value exists, use that } else if ( curCSS ) { - return curCSS( elem, name, origName ); + return curCSS( elem, name ); } }, @@ -5848,10 +6454,6 @@ jQuery.extend({ for ( name in options ) { elem.style[ name ] = old[ name ]; } - }, - - camelCase: function( string ) { - return string.replace( rdashAlpha, fcamelCase ); } }); @@ -5865,44 +6467,21 @@ jQuery.each(["height", "width"], function( i, name ) { if ( computed ) { if ( elem.offsetWidth !== 0 ) { - val = getWH( elem, name, extra ); - + return getWH( elem, name, extra ); } else { jQuery.swap( elem, cssShow, function() { val = getWH( elem, name, extra ); }); } - if ( val <= 0 ) { - val = curCSS( elem, name, name ); - - if ( val === "0px" && currentStyle ) { - val = currentStyle( elem, name, name ); - } - - if ( val != null ) { - // Should return "auto" instead of 0, use 0 for - // temporary backwards-compat - return val === "" || val === "auto" ? "0px" : val; - } - } - - if ( val < 0 || val == null ) { - val = elem.style[ name ]; - - // Should return "auto" instead of 0, use 0 for - // temporary backwards-compat - return val === "" || val === "auto" ? "0px" : val; - } - - return typeof val === "string" ? val : val + "px"; + return val; } }, set: function( elem, value ) { if ( rnumpx.test( value ) ) { // ignore negative width and height values #1599 - value = parseFloat(value); + value = parseFloat( value ); if ( value >= 0 ) { return value + "px"; @@ -5919,33 +6498,67 @@ if ( !jQuery.support.opacity ) { jQuery.cssHooks.opacity = { get: function( elem, computed ) { // IE uses filters for opacity - return ropacity.test((computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "") ? - (parseFloat(RegExp.$1) / 100) + "" : + return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? + ( parseFloat( RegExp.$1 ) / 100 ) + "" : computed ? "1" : ""; }, set: function( elem, value ) { - var style = elem.style; + var style = elem.style, + currentStyle = elem.currentStyle, + opacity = jQuery.isNaN( value ) ? "" : "alpha(opacity=" + value * 100 + ")", + filter = currentStyle && currentStyle.filter || style.filter || ""; // IE has trouble with opacity if it does not have layout // Force it by setting the zoom level style.zoom = 1; - // Set the alpha filter to set the opacity - var opacity = jQuery.isNaN(value) ? - "" : - "alpha(opacity=" + value * 100 + ")", - filter = style.filter || ""; + // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 + if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) { - style.filter = ralpha.test(filter) ? - filter.replace(ralpha, opacity) : - style.filter + ' ' + opacity; + // Setting style.filter to null, "" & " " still leave "filter:" in the cssText + // if "filter:" is present at all, clearType is disabled, we want to avoid this + // style.removeAttribute is IE Only, but so apparently is this code path... + style.removeAttribute( "filter" ); + + // if there there is no filter style applied in a css rule, we are done + if ( currentStyle && !currentStyle.filter ) { + return; + } + } + + // otherwise, set new filter values + style.filter = ralpha.test( filter ) ? + filter.replace( ralpha, opacity ) : + filter + " " + opacity; } }; } +jQuery(function() { + // This hook cannot be added until DOM ready because the support test + // for it is not run until after DOM ready + if ( !jQuery.support.reliableMarginRight ) { + jQuery.cssHooks.marginRight = { + get: function( elem, computed ) { + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + // Work around by temporarily setting element display to inline-block + var ret; + jQuery.swap( elem, { "display": "inline-block" }, function() { + if ( computed ) { + ret = curCSS( elem, "margin-right", "marginRight" ); + } else { + ret = elem.style.marginRight; + } + }); + return ret; + } + }; + } +}); + if ( document.defaultView && document.defaultView.getComputedStyle ) { - getComputedStyle = function( elem, newName, name ) { + getComputedStyle = function( elem, name ) { var ret, defaultView, computedStyle; name = name.replace( rupper, "-$1" ).toLowerCase(); @@ -6002,27 +6615,50 @@ if ( document.documentElement.currentStyle ) { curCSS = getComputedStyle || currentStyle; function getWH( elem, name, extra ) { - var which = name === "width" ? cssWidth : cssHeight, - val = name === "width" ? elem.offsetWidth : elem.offsetHeight; - if ( extra === "border" ) { - return val; + // Start with offset property + var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, + which = name === "width" ? cssWidth : cssHeight; + + if ( val > 0 ) { + if ( extra !== "border" ) { + jQuery.each( which, function() { + if ( !extra ) { + val -= parseFloat( jQuery.css( elem, "padding" + this ) ) || 0; + } + if ( extra === "margin" ) { + val += parseFloat( jQuery.css( elem, extra + this ) ) || 0; + } else { + val -= parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0; + } + }); + } + + return val + "px"; } - jQuery.each( which, function() { - if ( !extra ) { - val -= parseFloat(jQuery.css( elem, "padding" + this )) || 0; - } + // Fall back to computed then uncomputed css if necessary + val = curCSS( elem, name, name ); + if ( val < 0 || val == null ) { + val = elem.style[ name ] || 0; + } + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; - if ( extra === "margin" ) { - val += parseFloat(jQuery.css( elem, "margin" + this )) || 0; + // Add padding, border, margin + if ( extra ) { + jQuery.each( which, function() { + val += parseFloat( jQuery.css( elem, "padding" + this ) ) || 0; + if ( extra !== "padding" ) { + val += parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0; + } + if ( extra === "margin" ) { + val += parseFloat( jQuery.css( elem, extra + this ) ) || 0; + } + }); + } - } else { - val -= parseFloat(jQuery.css( elem, "border" + this + "Width" )) || 0; - } - }); - - return val; + return val + "px"; } if ( jQuery.expr && jQuery.expr.filters ) { @@ -6046,9 +6682,9 @@ var r20 = /%20/g, rCRLF = /\r?\n/g, rhash = /#.*$/, rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL - rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, + rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /(?:^file|^widget|\-extension):$/, + rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, rnoContent = /^(?:GET|HEAD)$/, rprotocol = /^\/\//, rquery = /\?/, @@ -6056,11 +6692,7 @@ var r20 = /%20/g, rselectTextarea = /^(?:select|textarea)/i, rspacesAjax = /\s+/, rts = /([?&])_=[^&]*/, - rucHeaders = /(^|\-)([a-z])/g, - rucHeadersFunc = function( _, $1, $2 ) { - return $1 + $2.toUpperCase(); - }, - rurl = /^([\w\+\.\-]+:)\/\/([^\/?#:]*)(?::(\d+))?/, + rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/, // Keep a copy of the old load method _load = jQuery.fn.load, @@ -6087,12 +6719,15 @@ var r20 = /%20/g, ajaxLocation, // Document location segments - ajaxLocParts; + ajaxLocParts, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = ["*/"] + ["*"]; // #8138, IE may throw an exception when accessing -// a field from document.location if document.domain has been set +// a field from window.location if document.domain has been set try { - ajaxLocation = document.location.href; + ajaxLocation = location.href; } catch( e ) { // Use the href attribute of an A element // since IE will modify it given document.location @@ -6102,7 +6737,7 @@ try { } // Segment location into parts -ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ); +ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport function addToPrefiltersOrTransports( structure ) { @@ -6140,7 +6775,7 @@ function addToPrefiltersOrTransports( structure ) { }; } -//Base inspection function for prefilters and transports +// Base inspection function for prefilters and transports function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR, dataType /* internal */, inspected /* internal */ ) { @@ -6180,6 +6815,22 @@ function inspectPrefiltersOrTransports( structure, options, originalOptions, jqX return selection; } +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + for( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } +} + jQuery.fn.extend({ load: function( url, params, callback ) { if ( typeof url !== "string" && _load ) { @@ -6289,7 +6940,7 @@ jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".sp jQuery.fn[ o ] = function( f ){ return this.bind( o, f ); }; -} ); +}); jQuery.each( [ "get", "post" ], function( i, method ) { jQuery[ method ] = function( url, data, callback, type ) { @@ -6308,7 +6959,7 @@ jQuery.each( [ "get", "post" ], function( i, method ) { dataType: type }); }; -} ); +}); jQuery.extend({ @@ -6323,23 +6974,16 @@ jQuery.extend({ // Creates a full fledged settings object into target // with both ajaxSettings and settings fields. // If target is omitted, writes into ajaxSettings. - ajaxSetup: function ( target, settings ) { - if ( !settings ) { - // Only one parameter, we extend ajaxSettings - settings = target; - target = jQuery.extend( true, jQuery.ajaxSettings, settings ); + ajaxSetup: function( target, settings ) { + if ( settings ) { + // Building a settings object + ajaxExtend( target, jQuery.ajaxSettings ); } else { - // target was provided, we extend into it - jQuery.extend( true, target, jQuery.ajaxSettings, settings ); - } - // Flatten fields we don't want deep extended - for( var field in { context: 1, url: 1 } ) { - if ( field in settings ) { - target[ field ] = settings[ field ]; - } else if( field in jQuery.ajaxSettings ) { - target[ field ] = jQuery.ajaxSettings[ field ]; - } + // Extending ajaxSettings + settings = target; + target = jQuery.ajaxSettings; } + ajaxExtend( target, settings ); return target; }, @@ -6360,7 +7004,6 @@ jQuery.extend({ cache: null, traditional: false, headers: {}, - crossDomain: null, */ accepts: { @@ -6368,7 +7011,7 @@ jQuery.extend({ html: "text/html", text: "text/plain", json: "application/json, text/javascript", - "*": "*/*" + "*": allTypes }, contents: { @@ -6398,6 +7041,15 @@ jQuery.extend({ // Parse text as xml "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + context: true, + url: true } }, @@ -6435,6 +7087,7 @@ jQuery.extend({ ifModifiedKey, // Headers (they are sent all at once) requestHeaders = {}, + requestHeadersNames = {}, // Response headers responseHeadersString, responseHeaders, @@ -6458,7 +7111,9 @@ jQuery.extend({ // Caches the header setRequestHeader: function( name, value ) { if ( !state ) { - requestHeaders[ name.toLowerCase().replace( rucHeaders, rucHeadersFunc ) ] = value; + var lname = name.toLowerCase(); + name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; + requestHeaders[ name ] = value; } return this; }, @@ -6505,7 +7160,7 @@ jQuery.extend({ // Callback for when everything is done // It is defined here because jslint complains if it is declared // at the end of the function (which would be more logical and readable) - function done( status, statusText, responses, headers ) { + function done( status, nativeStatusText, responses, headers ) { // Called once if ( state === 2 ) { @@ -6528,11 +7183,12 @@ jQuery.extend({ responseHeadersString = headers || ""; // Set readyState - jqXHR.readyState = status ? 4 : 0; + jqXHR.readyState = status > 0 ? 4 : 0; var isSuccess, success, error, + statusText = nativeStatusText, response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined, lastModified, etag; @@ -6584,7 +7240,7 @@ jQuery.extend({ // Set data for the fake xhr object jqXHR.status = status; - jqXHR.statusText = statusText; + jqXHR.statusText = "" + ( nativeStatusText || statusText ); // Success/Error if ( isSuccess ) { @@ -6606,7 +7262,7 @@ jQuery.extend({ completeDeferred.resolveWith( callbackContext, [ jqXHR, statusText ] ); if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s] ); + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); // Handle the global AJAX counter if ( !( --jQuery.active ) ) { jQuery.event.trigger( "ajaxStop" ); @@ -6645,7 +7301,7 @@ jQuery.extend({ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax ); // Determine if a cross-domain request is in order - if ( !s.crossDomain ) { + if ( s.crossDomain == null ) { parts = rurl.exec( s.url.toLowerCase() ); s.crossDomain = !!( parts && ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] || @@ -6687,6 +7343,8 @@ jQuery.extend({ // If data is available, append data to url if ( s.data ) { s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data; + // #9682: remove data so that it's not used in an eventual retry + delete s.data; } // Get ifModifiedKey before adding the anti-cache parameter @@ -6706,24 +7364,27 @@ jQuery.extend({ // Set the correct header, if data is being sent if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - requestHeaders[ "Content-Type" ] = s.contentType; + jqXHR.setRequestHeader( "Content-Type", s.contentType ); } // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. if ( s.ifModified ) { ifModifiedKey = ifModifiedKey || s.url; if ( jQuery.lastModified[ ifModifiedKey ] ) { - requestHeaders[ "If-Modified-Since" ] = jQuery.lastModified[ ifModifiedKey ]; + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] ); } if ( jQuery.etag[ ifModifiedKey ] ) { - requestHeaders[ "If-None-Match" ] = jQuery.etag[ ifModifiedKey ]; + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] ); } } // Set the Accepts header for the server, depending on the dataType - requestHeaders.Accept = s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? - s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) : - s.accepts[ "*" ]; + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? + s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); // Check for headers option for ( i in s.headers ) { @@ -6767,7 +7428,7 @@ jQuery.extend({ transport.send( requestHeaders, done ); } catch (e) { // Propagate exception as error if not done - if ( status < 2 ) { + if ( state < 2 ) { done( -1, e ); // Simply rethrow otherwise } else { @@ -6799,7 +7460,7 @@ jQuery.extend({ // Serialize the form elements jQuery.each( a, function() { add( this.name, this.value ); - } ); + }); } else { // If traditional, encode the "old" way (the way 1.3.2 or older @@ -6815,7 +7476,7 @@ jQuery.extend({ }); function buildParams( prefix, obj, traditional, add ) { - if ( jQuery.isArray( obj ) && obj.length ) { + if ( jQuery.isArray( obj ) ) { // Serialize array item. jQuery.each( obj, function( i, v ) { if ( traditional || rbracket.test( prefix ) ) { @@ -6835,16 +7496,9 @@ function buildParams( prefix, obj, traditional, add ) { }); } else if ( !traditional && obj != null && typeof obj === "object" ) { - // If we see an array here, it is empty and should be treated as an empty - // object - if ( jQuery.isArray( obj ) || jQuery.isEmptyObject( obj ) ) { - add( prefix, "" ); - // Serialize object item. - } else { - for ( var name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } + for ( var name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); } } else { @@ -7024,7 +7678,7 @@ function ajaxConvert( s, response ) { var jsc = jQuery.now(), - jsre = /(\=)\?(&|$)|()\?\?()/i; + jsre = /(\=)\?(&|$)|\?\?/i; // Default jsonp settings jQuery.ajaxSetup({ @@ -7037,13 +7691,12 @@ jQuery.ajaxSetup({ // Detect, normalize options and install callbacks for jsonp requests jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { - var dataIsString = ( typeof s.data === "string" ); + var inspectData = s.contentType === "application/x-www-form-urlencoded" && + ( typeof s.data === "string" ); if ( s.dataTypes[ 0 ] === "jsonp" || - originalSettings.jsonpCallback || - originalSettings.jsonp != null || s.jsonp !== false && ( jsre.test( s.url ) || - dataIsString && jsre.test( s.data ) ) ) { + inspectData && jsre.test( s.data ) ) ) { var responseContainer, jsonpCallback = s.jsonpCallback = @@ -7051,20 +7704,12 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { previous = window[ jsonpCallback ], url = s.url, data = s.data, - replace = "$1" + jsonpCallback + "$2", - cleanUp = function() { - // Set callback back to previous value - window[ jsonpCallback ] = previous; - // Call if it was a function and we have a response - if ( responseContainer && jQuery.isFunction( previous ) ) { - window[ jsonpCallback ]( responseContainer[ 0 ] ); - } - }; + replace = "$1" + jsonpCallback + "$2"; if ( s.jsonp !== false ) { url = url.replace( jsre, replace ); if ( s.url === url ) { - if ( dataIsString ) { + if ( inspectData ) { data = data.replace( jsre, replace ); } if ( s.data === data ) { @@ -7082,8 +7727,15 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { responseContainer = [ response ]; }; - // Install cleanUp function - jqXHR.then( cleanUp, cleanUp ); + // Clean-up function + jqXHR.always(function() { + // Set callback back to previous value + window[ jsonpCallback ] = previous; + // Call if it was a function and we have a response + if ( responseContainer && jQuery.isFunction( previous ) ) { + window[ jsonpCallback ]( responseContainer[ 0 ] ); + } + }); // Use data converter to retrieve json after script execution s.converters["script json"] = function() { @@ -7099,7 +7751,7 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { // Delegate to script return "script"; } -} ); +}); @@ -7129,7 +7781,7 @@ jQuery.ajaxPrefilter( "script", function( s ) { s.type = "GET"; s.global = false; } -} ); +}); // Bind script tag hack transport jQuery.ajaxTransport( "script", function(s) { @@ -7157,7 +7809,7 @@ jQuery.ajaxTransport( "script", function(s) { // Attach handlers for all browsers script.onload = script.onreadystatechange = function( _, isAbort ) { - if ( !script.readyState || /loaded|complete/.test( script.readyState ) ) { + if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { // Handle memory leak in IE script.onload = script.onreadystatechange = null; @@ -7188,27 +7840,20 @@ jQuery.ajaxTransport( "script", function(s) { } }; } -} ); +}); -var // #5280: next active xhr id and list of active xhrs' callbacks - xhrId = jQuery.now(), - xhrCallbacks, - - // XHR used to determine supports properties - testXHR; - -// #5280: Internet Explorer will keep connections alive if we don't abort on unload -function xhrOnUnloadAbort() { - jQuery( window ).unload(function() { +var // #5280: Internet Explorer will keep connections alive if we don't abort on unload + xhrOnUnloadAbort = window.ActiveXObject ? function() { // Abort all pending requests for ( var key in xhrCallbacks ) { xhrCallbacks[ key ]( 0, 1 ); } - }); -} + } : false, + xhrId = 0, + xhrCallbacks; // Functions to create xhrs function createStandardXHR() { @@ -7238,15 +7883,13 @@ jQuery.ajaxSettings.xhr = window.ActiveXObject ? // For all other browsers, use the standard XMLHttpRequest object createStandardXHR; -// Test if we can create an xhr object -testXHR = jQuery.ajaxSettings.xhr(); -jQuery.support.ajax = !!testXHR; - -// Does this browser support crossDomain XHR requests -jQuery.support.cors = testXHR && ( "withCredentials" in testXHR ); - -// No need for the temporary xhr anymore -testXHR = undefined; +// Determine support properties +(function( xhr ) { + jQuery.extend( jQuery.support, { + ajax: !!xhr, + cors: !!xhr && ( "withCredentials" in xhr ) + }); +})( jQuery.ajaxSettings.xhr() ); // Create transport if the browser can provide an xhr if ( jQuery.support.ajax ) { @@ -7285,11 +7928,12 @@ if ( jQuery.support.ajax ) { xhr.overrideMimeType( s.mimeType ); } - // Requested-With header - // Not set for crossDomain requests with no content - // (see why at http://trac.dojotoolkit.org/ticket/9486) - // Won't change header if already provided - if ( !( s.crossDomain && !s.hasContent ) && !headers["X-Requested-With"] ) { + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !s.crossDomain && !headers["X-Requested-With"] ) { headers[ "X-Requested-With" ] = "XMLHttpRequest"; } @@ -7328,7 +7972,9 @@ if ( jQuery.support.ajax ) { // Do not keep as active anymore if ( handle ) { xhr.onreadystatechange = jQuery.noop; - delete xhrCallbacks[ handle ]; + if ( xhrOnUnloadAbort ) { + delete xhrCallbacks[ handle ]; + } } // If it's an abort @@ -7389,15 +8035,18 @@ if ( jQuery.support.ajax ) { if ( !s.async || xhr.readyState === 4 ) { callback(); } else { - // Create the active xhrs callbacks list if needed - // and attach the unload handler - if ( !xhrCallbacks ) { - xhrCallbacks = {}; - xhrOnUnloadAbort(); + handle = ++xhrId; + if ( xhrOnUnloadAbort ) { + // Create the active xhrs callbacks list if needed + // and attach the unload handler + if ( !xhrCallbacks ) { + xhrCallbacks = {}; + jQuery( window ).unload( xhrOnUnloadAbort ); + } + // Add to list of active xhrs callbacks + xhrCallbacks[ handle ] = callback; } - // Add to list of active xhrs callbacks - handle = xhrId++; - xhr.onreadystatechange = xhrCallbacks[ handle ] = callback; + xhr.onreadystatechange = callback; } }, @@ -7415,6 +8064,7 @@ if ( jQuery.support.ajax ) { var elemdisplay = {}, + iframe, iframeDoc, rfxtypes = /^(?:toggle|show|hide)$/, rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i, timerId, @@ -7425,7 +8075,8 @@ var elemdisplay = {}, [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ], // opacity animations [ "opacity" ] - ]; + ], + fxNow; jQuery.fn.extend({ show: function( speed, easing, callback ) { @@ -7437,19 +8088,22 @@ jQuery.fn.extend({ } else { for ( var i = 0, j = this.length; i < j; i++ ) { elem = this[i]; - display = elem.style.display; - // Reset the inline display of this element to learn if it is - // being hidden by cascaded rules or not - if ( !jQuery._data(elem, "olddisplay") && display === "none" ) { - display = elem.style.display = ""; - } + if ( elem.style ) { + display = elem.style.display; - // Set elements which have been overridden with display: none - // in a stylesheet to whatever the default browser style is - // for such an element - if ( display === "" && jQuery.css( elem, "display" ) === "none" ) { - jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName)); + // Reset the inline display of this element to learn if it is + // being hidden by cascaded rules or not + if ( !jQuery._data(elem, "olddisplay") && display === "none" ) { + display = elem.style.display = ""; + } + + // Set elements which have been overridden with display: none + // in a stylesheet to whatever the default browser style is + // for such an element + if ( display === "" && jQuery.css( elem, "display" ) === "none" ) { + jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName)); + } } } @@ -7457,10 +8111,13 @@ jQuery.fn.extend({ // to avoid the constant reflow for ( i = 0; i < j; i++ ) { elem = this[i]; - display = elem.style.display; - if ( display === "" || display === "none" ) { - elem.style.display = jQuery._data(elem, "olddisplay") || ""; + if ( elem.style ) { + display = elem.style.display; + + if ( display === "" || display === "none" ) { + elem.style.display = jQuery._data(elem, "olddisplay") || ""; + } } } @@ -7474,17 +8131,21 @@ jQuery.fn.extend({ } else { for ( var i = 0, j = this.length; i < j; i++ ) { - var display = jQuery.css( this[i], "display" ); + if ( this[i].style ) { + var display = jQuery.css( this[i], "display" ); - if ( display !== "none" && !jQuery._data( this[i], "olddisplay" ) ) { - jQuery._data( this[i], "olddisplay", display ); + if ( display !== "none" && !jQuery._data( this[i], "olddisplay" ) ) { + jQuery._data( this[i], "olddisplay", display ); + } } } // Set the display of the elements in a second loop // to avoid the constant reflow for ( i = 0; i < j; i++ ) { - this[i].style.display = "none"; + if ( this[i].style ) { + this[i].style.display = "none"; + } } return this; @@ -7522,32 +8183,54 @@ jQuery.fn.extend({ var optall = jQuery.speed(speed, easing, callback); if ( jQuery.isEmptyObject( prop ) ) { - return this.each( optall.complete ); + return this.each( optall.complete, [ false ] ); } + // Do not change referenced properties as per-property easing will be lost + prop = jQuery.extend( {}, prop ); + return this[ optall.queue === false ? "each" : "queue" ](function() { // XXX 'this' does not always have a nodeName when running the // test suite - var opt = jQuery.extend({}, optall), p, + if ( optall.queue === false ) { + jQuery._mark( this ); + } + + var opt = jQuery.extend( {}, optall ), isElement = this.nodeType === 1, hidden = isElement && jQuery(this).is(":hidden"), - self = this; + name, val, p, + display, e, + parts, start, end, unit; + + // will store per property easing and be used to determine when an animation is complete + opt.animatedProperties = {}; for ( p in prop ) { - var name = jQuery.camelCase( p ); + // property name normalization + name = jQuery.camelCase( p ); if ( p !== name ) { prop[ name ] = prop[ p ]; delete prop[ p ]; - p = name; } - if ( prop[p] === "hide" && hidden || prop[p] === "show" && !hidden ) { - return opt.complete.call(this); + val = prop[ name ]; + + // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default) + if ( jQuery.isArray( val ) ) { + opt.animatedProperties[ name ] = val[ 1 ]; + val = prop[ name ] = val[ 0 ]; + } else { + opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing'; } - if ( isElement && ( p === "height" || p === "width" ) ) { + if ( val === "hide" && hidden || val === "show" && !hidden ) { + return opt.complete.call( this ); + } + + if ( isElement && ( name === "height" || name === "width" ) ) { // Make sure that nothing sneaks out // Record all 3 overflow attributes because IE does not // change the overflow attribute when overflowX and @@ -7563,7 +8246,7 @@ jQuery.fn.extend({ this.style.display = "inline-block"; } else { - var display = defaultDisplay(this.nodeName); + display = defaultDisplay( this.nodeName ); // inline-level elements accept inline-block; // block-level elements need to be inline with layout @@ -7577,44 +8260,37 @@ jQuery.fn.extend({ } } } - - if ( jQuery.isArray( prop[p] ) ) { - // Create (if needed) and add to specialEasing - (opt.specialEasing = opt.specialEasing || {})[p] = prop[p][1]; - prop[p] = prop[p][0]; - } } if ( opt.overflow != null ) { this.style.overflow = "hidden"; } - opt.curAnim = jQuery.extend({}, prop); - - jQuery.each( prop, function( name, val ) { - var e = new jQuery.fx( self, opt, name ); + for ( p in prop ) { + e = new jQuery.fx( this, opt, p ); + val = prop[ p ]; if ( rfxtypes.test(val) ) { - e[ val === "toggle" ? hidden ? "show" : "hide" : val ]( prop ); + e[ val === "toggle" ? hidden ? "show" : "hide" : val ](); } else { - var parts = rfxnum.exec(val), - start = e.cur(); + parts = rfxnum.exec( val ); + start = e.cur(); if ( parts ) { - var end = parseFloat( parts[2] ), - unit = parts[3] || ( jQuery.cssNumber[ name ] ? "" : "px" ); + end = parseFloat( parts[2] ); + unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" ); // We need to compute starting value if ( unit !== "px" ) { - jQuery.style( self, name, (end || 1) + unit); + jQuery.style( this, p, (end || 1) + unit); start = ((end || 1) / e.cur()) * start; - jQuery.style( self, name, start + unit); + jQuery.style( this, p, start + unit); } // If a +=/-= token was provided, we're doing a relative animation if ( parts[1] ) { - end = ((parts[1] === "-=" ? -1 : 1) * end) + start; + end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start; } e.custom( start, end, unit ); @@ -7623,7 +8299,7 @@ jQuery.fn.extend({ e.custom( start, val, "" ); } } - }); + } // For JS strict compliance return true; @@ -7631,15 +8307,18 @@ jQuery.fn.extend({ }, stop: function( clearQueue, gotoEnd ) { - var timers = jQuery.timers; - if ( clearQueue ) { this.queue([]); } this.each(function() { - // go in reverse order so anything added to the queue during the loop is ignored - for ( var i = timers.length - 1; i >= 0; i-- ) { + var timers = jQuery.timers, + i = timers.length; + // clear marker counters if we know they won't be + if ( !gotoEnd ) { + jQuery._unmark( true, this ); + } + while ( i-- ) { if ( timers[i].elem === this ) { if (gotoEnd) { // force the next step to be the last @@ -7661,6 +8340,17 @@ jQuery.fn.extend({ }); +// Animations created synchronously will run synchronously +function createFxNow() { + setTimeout( clearFxNow, 0 ); + return ( fxNow = jQuery.now() ); +} + +function clearFxNow() { + fxNow = undefined; +} + +// Generate parameters to create a standard animation function genFx( type, num ) { var obj = {}; @@ -7699,13 +8389,16 @@ jQuery.extend({ // Queueing opt.old = opt.complete; - opt.complete = function() { - if ( opt.queue !== false ) { - jQuery(this).dequeue(); - } + opt.complete = function( noUnmark ) { if ( jQuery.isFunction( opt.old ) ) { opt.old.call( this ); } + + if ( opt.queue !== false ) { + jQuery.dequeue( this ); + } else if ( noUnmark !== false ) { + jQuery._unmark( this ); + } }; return opt; @@ -7727,9 +8420,7 @@ jQuery.extend({ this.elem = elem; this.prop = prop; - if ( !options.orig ) { - options.orig = {}; - } + options.orig = options.orig || {}; } }); @@ -7763,7 +8454,7 @@ jQuery.fx.prototype = { var self = this, fx = jQuery.fx; - this.startTime = jQuery.now(); + this.startTime = fxNow || createFxNow(); this.start = from; this.end = to; this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" ); @@ -7777,7 +8468,7 @@ jQuery.fx.prototype = { t.elem = this.elem; if ( t() && jQuery.timers.push(t) && !timerId ) { - timerId = setInterval(fx.tick, fx.interval); + timerId = setInterval( fx.tick, fx.interval ); } }, @@ -7808,60 +8499,64 @@ jQuery.fx.prototype = { // Each step of an animation step: function( gotoEnd ) { - var t = jQuery.now(), done = true; + var t = fxNow || createFxNow(), + done = true, + elem = this.elem, + options = this.options, + i, n; - if ( gotoEnd || t >= this.options.duration + this.startTime ) { + if ( gotoEnd || t >= options.duration + this.startTime ) { this.now = this.end; this.pos = this.state = 1; this.update(); - this.options.curAnim[ this.prop ] = true; + options.animatedProperties[ this.prop ] = true; - for ( var i in this.options.curAnim ) { - if ( this.options.curAnim[i] !== true ) { + for ( i in options.animatedProperties ) { + if ( options.animatedProperties[i] !== true ) { done = false; } } if ( done ) { // Reset the overflow - if ( this.options.overflow != null && !jQuery.support.shrinkWrapBlocks ) { - var elem = this.elem, - options = this.options; + if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) { jQuery.each( [ "", "X", "Y" ], function (index, value) { elem.style[ "overflow" + value ] = options.overflow[index]; - } ); + }); } // Hide the element if the "hide" operation was done - if ( this.options.hide ) { - jQuery(this.elem).hide(); + if ( options.hide ) { + jQuery(elem).hide(); } // Reset the properties, if the item has been hidden or shown - if ( this.options.hide || this.options.show ) { - for ( var p in this.options.curAnim ) { - jQuery.style( this.elem, p, this.options.orig[p] ); + if ( options.hide || options.show ) { + for ( var p in options.animatedProperties ) { + jQuery.style( elem, p, options.orig[p] ); } } // Execute the complete function - this.options.complete.call( this.elem ); + options.complete.call( elem ); } return false; } else { - var n = t - this.startTime; - this.state = n / this.options.duration; - - // Perform the easing function, defaults to swing - var specialEasing = this.options.specialEasing && this.options.specialEasing[this.prop]; - var defaultEasing = this.options.easing || (jQuery.easing.swing ? "swing" : "linear"); - this.pos = jQuery.easing[specialEasing || defaultEasing](this.state, n, 0, 1, this.options.duration); - this.now = this.start + ((this.end - this.start) * this.pos); + // classical easing cannot be used with an Infinity duration + if ( options.duration == Infinity ) { + this.now = t; + } else { + n = t - this.startTime; + this.state = n / options.duration; + // Perform the easing function, defaults to swing + this.pos = jQuery.easing[ options.animatedProperties[ this.prop ] ]( this.state, n, 0, 1, options.duration ); + this.now = this.start + ((this.end - this.start) * this.pos); + } // Perform the next step of the animation this.update(); } @@ -7872,9 +8567,7 @@ jQuery.fx.prototype = { jQuery.extend( jQuery.fx, { tick: function() { - var timers = jQuery.timers; - - for ( var i = 0; i < timers.length; i++ ) { + for ( var timers = jQuery.timers, i = 0 ; i < timers.length ; ++i ) { if ( !timers[i]() ) { timers.splice(i--, 1); } @@ -7922,17 +8615,47 @@ if ( jQuery.expr && jQuery.expr.filters ) { }; } +// Try to restore the default display value of an element function defaultDisplay( nodeName ) { + if ( !elemdisplay[ nodeName ] ) { - var elem = jQuery("<" + nodeName + ">").appendTo("body"), - display = elem.css("display"); + + var body = document.body, + elem = jQuery( "<" + nodeName + ">" ).appendTo( body ), + display = elem.css( "display" ); elem.remove(); + // If the simple way fails, + // get element's real default display by attaching it to a temp iframe if ( display === "none" || display === "" ) { - display = "block"; + // No iframe to use yet, so create it + if ( !iframe ) { + iframe = document.createElement( "iframe" ); + iframe.frameBorder = iframe.width = iframe.height = 0; + } + + body.appendChild( iframe ); + + // Create a cacheable copy of the iframe document on first call. + // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML + // document to it; WebKit & Firefox won't allow reusing the iframe document. + if ( !iframeDoc || !iframe.createElement ) { + iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; + iframeDoc.write( ( document.compatMode === "CSS1Compat" ? "" : "" ) + "" ); + iframeDoc.close(); + } + + elem = iframeDoc.createElement( nodeName ); + + iframeDoc.body.appendChild( elem ); + + display = jQuery.css( elem, "display" ); + + body.removeChild( iframe ); } + // Store the correct default display elemdisplay[ nodeName ] = display; } @@ -7979,8 +8702,8 @@ if ( "getBoundingClientRect" in document.documentElement ) { win = getWindow(doc), clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, - scrollTop = (win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop ), - scrollLeft = (win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft), + scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop, + scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft, top = box.top + scrollTop - clientTop, left = box.left + scrollLeft - clientLeft; @@ -8093,7 +8816,6 @@ jQuery.offset = { this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop); body.removeChild( container ); - body = container = innerDiv = checkDiv = table = td = null; jQuery.offset.initialize = jQuery.noop; }, @@ -8123,17 +8845,19 @@ jQuery.offset = { curOffset = curElem.offset(), curCSSTop = jQuery.css( elem, "top" ), curCSSLeft = jQuery.css( elem, "left" ), - calculatePosition = (position === "absolute" && jQuery.inArray('auto', [curCSSTop, curCSSLeft]) > -1), + calculatePosition = (position === "absolute" || position === "fixed") && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, props = {}, curPosition = {}, curTop, curLeft; - // need to be able to calculate position if either top or left is auto and position is absolute + // need to be able to calculate position if either top or left is auto and position is either absolute or fixed if ( calculatePosition ) { curPosition = curElem.position(); + curTop = curPosition.top; + curLeft = curPosition.left; + } else { + curTop = parseFloat( curCSSTop ) || 0; + curLeft = parseFloat( curCSSLeft ) || 0; } - curTop = calculatePosition ? curPosition.top : parseInt( curCSSTop, 10 ) || 0; - curLeft = calculatePosition ? curPosition.left : parseInt( curCSSLeft, 10 ) || 0; - if ( jQuery.isFunction( options ) ) { options = options.call( elem, i, curOffset ); } @@ -8202,29 +8926,16 @@ jQuery.fn.extend({ jQuery.each( ["Left", "Top"], function( i, name ) { var method = "scroll" + name; - jQuery.fn[ method ] = function(val) { - var elem = this[0], win; + jQuery.fn[ method ] = function( val ) { + var elem, win; - if ( !elem ) { - return null; - } + if ( val === undefined ) { + elem = this[ 0 ]; - if ( val !== undefined ) { - // Set the scroll offset - return this.each(function() { - win = getWindow( this ); + if ( !elem ) { + return null; + } - if ( win ) { - win.scrollTo( - !i ? val : jQuery(win).scrollLeft(), - i ? val : jQuery(win).scrollTop() - ); - - } else { - this[ method ] = val; - } - }); - } else { win = getWindow( elem ); // Return the scroll offset @@ -8233,6 +8944,21 @@ jQuery.each( ["Left", "Top"], function( i, name ) { win.document.body[ method ] : elem[ method ]; } + + // Set the scroll offset + return this.each(function() { + win = getWindow( this ); + + if ( win ) { + win.scrollTo( + !i ? val : jQuery( win ).scrollLeft(), + i ? val : jQuery( win ).scrollTop() + ); + + } else { + this[ method ] = val; + } + }); }; }); @@ -8247,22 +8973,24 @@ function getWindow( elem ) { -// Create innerHeight, innerWidth, outerHeight and outerWidth methods +// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods jQuery.each([ "Height", "Width" ], function( i, name ) { var type = name.toLowerCase(); // innerHeight and innerWidth - jQuery.fn["inner" + name] = function() { - return this[0] ? - parseFloat( jQuery.css( this[0], type, "padding" ) ) : + jQuery.fn[ "inner" + name ] = function() { + var elem = this[0]; + return elem && elem.style ? + parseFloat( jQuery.css( elem, type, "padding" ) ) : null; }; // outerHeight and outerWidth - jQuery.fn["outer" + name] = function( margin ) { - return this[0] ? - parseFloat( jQuery.css( this[0], type, margin ? "margin" : "border" ) ) : + jQuery.fn[ "outer" + name ] = function( margin ) { + var elem = this[0]; + return elem && elem.style ? + parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) : null; }; @@ -8283,9 +9011,10 @@ jQuery.each([ "Height", "Width" ], function( i, name ) { if ( jQuery.isWindow( elem ) ) { // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat - var docElemProp = elem.document.documentElement[ "client" + name ]; + var docElemProp = elem.document.documentElement[ "client" + name ], + body = elem.document.body; return elem.document.compatMode === "CSS1Compat" && docElemProp || - elem.document.body[ "client" + name ] || docElemProp; + body && body[ "client" + name ] || docElemProp; // Get document width or height } else if ( elem.nodeType === 9 ) { @@ -8312,5 +9041,6 @@ jQuery.each([ "Height", "Width" ], function( i, name ) { }); +// Expose jQuery to the global object window.jQuery = window.$ = jQuery; })(window); diff --git a/addons/web/static/lib/novajs/test/qunit.css b/addons/web/static/lib/novajs/test/qunit.css new file mode 100755 index 00000000000..bcecc4c0daf --- /dev/null +++ b/addons/web/static/lib/novajs/test/qunit.css @@ -0,0 +1,226 @@ +/** + * QUnit v1.2.0 - A JavaScript Unit Testing Framework + * + * http://docs.jquery.com/QUnit + * + * Copyright (c) 2011 John Resig, Jörn Zaefferer + * Dual licensed under the MIT (MIT-LICENSE.txt) + * or GPL (GPL-LICENSE.txt) licenses. + */ + +/** Font Family and Sizes */ + +#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { + font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; +} + +#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } +#qunit-tests { font-size: smaller; } + + +/** Resets */ + +#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { + margin: 0; + padding: 0; +} + + +/** Header */ + +#qunit-header { + padding: 0.5em 0 0.5em 1em; + + color: #8699a4; + background-color: #0d3349; + + font-size: 1.5em; + line-height: 1em; + font-weight: normal; + + border-radius: 15px 15px 0 0; + -moz-border-radius: 15px 15px 0 0; + -webkit-border-top-right-radius: 15px; + -webkit-border-top-left-radius: 15px; +} + +#qunit-header a { + text-decoration: none; + color: #c2ccd1; +} + +#qunit-header a:hover, +#qunit-header a:focus { + color: #fff; +} + +#qunit-banner { + height: 5px; +} + +#qunit-testrunner-toolbar { + padding: 0.5em 0 0.5em 2em; + color: #5E740B; + background-color: #eee; +} + +#qunit-userAgent { + padding: 0.5em 0 0.5em 2.5em; + background-color: #2b81af; + color: #fff; + text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; +} + + +/** Tests: Pass/Fail */ + +#qunit-tests { + list-style-position: inside; +} + +#qunit-tests li { + padding: 0.4em 0.5em 0.4em 2.5em; + border-bottom: 1px solid #fff; + list-style-position: inside; +} + +#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { + display: none; +} + +#qunit-tests li strong { + cursor: pointer; +} + +#qunit-tests li a { + padding: 0.5em; + color: #c2ccd1; + text-decoration: none; +} +#qunit-tests li a:hover, +#qunit-tests li a:focus { + color: #000; +} + +#qunit-tests ol { + margin-top: 0.5em; + padding: 0.5em; + + background-color: #fff; + + border-radius: 15px; + -moz-border-radius: 15px; + -webkit-border-radius: 15px; + + box-shadow: inset 0px 2px 13px #999; + -moz-box-shadow: inset 0px 2px 13px #999; + -webkit-box-shadow: inset 0px 2px 13px #999; +} + +#qunit-tests table { + border-collapse: collapse; + margin-top: .2em; +} + +#qunit-tests th { + text-align: right; + vertical-align: top; + padding: 0 .5em 0 0; +} + +#qunit-tests td { + vertical-align: top; +} + +#qunit-tests pre { + margin: 0; + white-space: pre-wrap; + word-wrap: break-word; +} + +#qunit-tests del { + background-color: #e0f2be; + color: #374e0c; + text-decoration: none; +} + +#qunit-tests ins { + background-color: #ffcaca; + color: #500; + text-decoration: none; +} + +/*** Test Counts */ + +#qunit-tests b.counts { color: black; } +#qunit-tests b.passed { color: #5E740B; } +#qunit-tests b.failed { color: #710909; } + +#qunit-tests li li { + margin: 0.5em; + padding: 0.4em 0.5em 0.4em 0.5em; + background-color: #fff; + border-bottom: none; + list-style-position: inside; +} + +/*** Passing Styles */ + +#qunit-tests li li.pass { + color: #5E740B; + background-color: #fff; + border-left: 26px solid #C6E746; +} + +#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } +#qunit-tests .pass .test-name { color: #366097; } + +#qunit-tests .pass .test-actual, +#qunit-tests .pass .test-expected { color: #999999; } + +#qunit-banner.qunit-pass { background-color: #C6E746; } + +/*** Failing Styles */ + +#qunit-tests li li.fail { + color: #710909; + background-color: #fff; + border-left: 26px solid #EE5757; + white-space: pre; +} + +#qunit-tests > li:last-child { + border-radius: 0 0 15px 15px; + -moz-border-radius: 0 0 15px 15px; + -webkit-border-bottom-right-radius: 15px; + -webkit-border-bottom-left-radius: 15px; +} + +#qunit-tests .fail { color: #000000; background-color: #EE5757; } +#qunit-tests .fail .test-name, +#qunit-tests .fail .module-name { color: #000000; } + +#qunit-tests .fail .test-actual { color: #EE5757; } +#qunit-tests .fail .test-expected { color: green; } + +#qunit-banner.qunit-fail { background-color: #EE5757; } + + +/** Result */ + +#qunit-testresult { + padding: 0.5em 0.5em 0.5em 2.5em; + + color: #2b81af; + background-color: #D2E0E6; + + border-bottom: 1px solid white; +} + +/** Fixture */ + +#qunit-fixture { + position: absolute; + top: -10000px; + left: -10000px; +} diff --git a/addons/web/static/lib/novajs/test/qunit.js b/addons/web/static/lib/novajs/test/qunit.js new file mode 100755 index 00000000000..6d2a8a7b8ab --- /dev/null +++ b/addons/web/static/lib/novajs/test/qunit.js @@ -0,0 +1,1597 @@ +/** + * QUnit v1.2.0 - A JavaScript Unit Testing Framework + * + * http://docs.jquery.com/QUnit + * + * Copyright (c) 2011 John Resig, Jörn Zaefferer + * Dual licensed under the MIT (MIT-LICENSE.txt) + * or GPL (GPL-LICENSE.txt) licenses. + */ + +(function(window) { + +var defined = { + setTimeout: typeof window.setTimeout !== "undefined", + sessionStorage: (function() { + try { + return !!sessionStorage.getItem; + } catch(e) { + return false; + } + })() +}; + +var testId = 0, + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty; + +var Test = function(name, testName, expected, testEnvironmentArg, async, callback) { + this.name = name; + this.testName = testName; + this.expected = expected; + this.testEnvironmentArg = testEnvironmentArg; + this.async = async; + this.callback = callback; + this.assertions = []; +}; +Test.prototype = { + init: function() { + var tests = id("qunit-tests"); + if (tests) { + var b = document.createElement("strong"); + b.innerHTML = "Running " + this.name; + var li = document.createElement("li"); + li.appendChild( b ); + li.className = "running"; + li.id = this.id = "test-output" + testId++; + tests.appendChild( li ); + } + }, + setup: function() { + if (this.module != config.previousModule) { + if ( config.previousModule ) { + runLoggingCallbacks('moduleDone', QUnit, { + name: config.previousModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + } ); + } + config.previousModule = this.module; + config.moduleStats = { all: 0, bad: 0 }; + runLoggingCallbacks( 'moduleStart', QUnit, { + name: this.module + } ); + } + + config.current = this; + this.testEnvironment = extend({ + setup: function() {}, + teardown: function() {} + }, this.moduleTestEnvironment); + if (this.testEnvironmentArg) { + extend(this.testEnvironment, this.testEnvironmentArg); + } + + runLoggingCallbacks( 'testStart', QUnit, { + name: this.testName, + module: this.module + }); + + // allow utility functions to access the current test environment + // TODO why?? + QUnit.current_testEnvironment = this.testEnvironment; + + try { + if ( !config.pollution ) { + saveGlobal(); + } + + this.testEnvironment.setup.call(this.testEnvironment); + } catch(e) { + QUnit.ok( false, "Setup failed on " + this.testName + ": " + e.message ); + } + }, + run: function() { + config.current = this; + if ( this.async ) { + QUnit.stop(); + } + + if ( config.notrycatch ) { + this.callback.call(this.testEnvironment); + return; + } + try { + this.callback.call(this.testEnvironment); + } catch(e) { + fail("Test " + this.testName + " died, exception and test follows", e, this.callback); + QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) ); + // else next test will carry the responsibility + saveGlobal(); + + // Restart the tests if they're blocking + if ( config.blocking ) { + QUnit.start(); + } + } + }, + teardown: function() { + config.current = this; + try { + this.testEnvironment.teardown.call(this.testEnvironment); + checkPollution(); + } catch(e) { + QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message ); + } + }, + finish: function() { + config.current = this; + if ( this.expected != null && this.expected != this.assertions.length ) { + QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" ); + } + + var good = 0, bad = 0, + tests = id("qunit-tests"); + + config.stats.all += this.assertions.length; + config.moduleStats.all += this.assertions.length; + + if ( tests ) { + var ol = document.createElement("ol"); + + for ( var i = 0; i < this.assertions.length; i++ ) { + var assertion = this.assertions[i]; + + var li = document.createElement("li"); + li.className = assertion.result ? "pass" : "fail"; + li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed"); + ol.appendChild( li ); + + if ( assertion.result ) { + good++; + } else { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + + // store result when possible + if ( QUnit.config.reorder && defined.sessionStorage ) { + if (bad) { + sessionStorage.setItem("qunit-" + this.module + "-" + this.testName, bad); + } else { + sessionStorage.removeItem("qunit-" + this.module + "-" + this.testName); + } + } + + if (bad == 0) { + ol.style.display = "none"; + } + + var b = document.createElement("strong"); + b.innerHTML = this.name + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; + + var a = document.createElement("a"); + a.innerHTML = "Rerun"; + a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); + + addEvent(b, "click", function() { + var next = b.nextSibling.nextSibling, + display = next.style.display; + next.style.display = display === "none" ? "block" : "none"; + }); + + addEvent(b, "dblclick", function(e) { + var target = e && e.target ? e.target : window.event.srcElement; + if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { + target = target.parentNode; + } + if ( window.location && target.nodeName.toLowerCase() === "strong" ) { + window.location = QUnit.url({ filter: getText([target]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); + } + }); + + var li = id(this.id); + li.className = bad ? "fail" : "pass"; + li.removeChild( li.firstChild ); + li.appendChild( b ); + li.appendChild( a ); + li.appendChild( ol ); + + } else { + for ( var i = 0; i < this.assertions.length; i++ ) { + if ( !this.assertions[i].result ) { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + } + + try { + QUnit.reset(); + } catch(e) { + fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset); + } + + runLoggingCallbacks( 'testDone', QUnit, { + name: this.testName, + module: this.module, + failed: bad, + passed: this.assertions.length - bad, + total: this.assertions.length + } ); + }, + + queue: function() { + var test = this; + synchronize(function() { + test.init(); + }); + function run() { + // each of these can by async + synchronize(function() { + test.setup(); + }); + synchronize(function() { + test.run(); + }); + synchronize(function() { + test.teardown(); + }); + synchronize(function() { + test.finish(); + }); + } + // defer when previous test run passed, if storage is available + var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.module + "-" + this.testName); + if (bad) { + run(); + } else { + synchronize(run, true); + }; + } + +}; + +var QUnit = { + + // call on start of module test to prepend name to all tests + module: function(name, testEnvironment) { + config.currentModule = name; + config.currentModuleTestEnviroment = testEnvironment; + }, + + asyncTest: function(testName, expected, callback) { + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + QUnit.test(testName, expected, callback, true); + }, + + test: function(testName, expected, callback, async) { + var name = '' + testName + '', testEnvironmentArg; + + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + // is 2nd argument a testEnvironment? + if ( expected && typeof expected === 'object') { + testEnvironmentArg = expected; + expected = null; + } + + if ( config.currentModule ) { + name = '' + config.currentModule + ": " + name; + } + + if ( !validTest(config.currentModule + ": " + testName) ) { + return; + } + + var test = new Test(name, testName, expected, testEnvironmentArg, async, callback); + test.module = config.currentModule; + test.moduleTestEnvironment = config.currentModuleTestEnviroment; + test.queue(); + }, + + /** + * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. + */ + expect: function(asserts) { + config.current.expected = asserts; + }, + + /** + * Asserts true. + * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); + */ + ok: function(a, msg) { + a = !!a; + var details = { + result: a, + message: msg + }; + msg = escapeInnerText(msg); + runLoggingCallbacks( 'log', QUnit, details ); + config.current.assertions.push({ + result: a, + message: msg + }); + }, + + /** + * Checks that the first two arguments are equal, with an optional message. + * Prints out both actual and expected values. + * + * Prefered to ok( actual == expected, message ) + * + * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." ); + * + * @param Object actual + * @param Object expected + * @param String message (optional) + */ + equal: function(actual, expected, message) { + QUnit.push(expected == actual, actual, expected, message); + }, + + notEqual: function(actual, expected, message) { + QUnit.push(expected != actual, actual, expected, message); + }, + + deepEqual: function(actual, expected, message) { + QUnit.push(QUnit.equiv(actual, expected), actual, expected, message); + }, + + notDeepEqual: function(actual, expected, message) { + QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message); + }, + + strictEqual: function(actual, expected, message) { + QUnit.push(expected === actual, actual, expected, message); + }, + + notStrictEqual: function(actual, expected, message) { + QUnit.push(expected !== actual, actual, expected, message); + }, + + raises: function(block, expected, message) { + var actual, ok = false; + + if (typeof expected === 'string') { + message = expected; + expected = null; + } + + try { + block(); + } catch (e) { + actual = e; + } + + if (actual) { + // we don't want to validate thrown error + if (!expected) { + ok = true; + // expected is a regexp + } else if (QUnit.objectType(expected) === "regexp") { + ok = expected.test(actual); + // expected is a constructor + } else if (actual instanceof expected) { + ok = true; + // expected is a validation function which returns true is validation passed + } else if (expected.call({}, actual) === true) { + ok = true; + } + } + + QUnit.ok(ok, message); + }, + + start: function(count) { + config.semaphore -= count || 1; + if (config.semaphore > 0) { + // don't start until equal number of stop-calls + return; + } + if (config.semaphore < 0) { + // ignore if start is called more often then stop + config.semaphore = 0; + } + // A slight delay, to avoid any current callbacks + if ( defined.setTimeout ) { + window.setTimeout(function() { + if (config.semaphore > 0) { + return; + } + if ( config.timeout ) { + clearTimeout(config.timeout); + } + + config.blocking = false; + process(true); + }, 13); + } else { + config.blocking = false; + process(true); + } + }, + + stop: function(count) { + config.semaphore += count || 1; + config.blocking = true; + + if ( config.testTimeout && defined.setTimeout ) { + clearTimeout(config.timeout); + config.timeout = window.setTimeout(function() { + QUnit.ok( false, "Test timed out" ); + config.semaphore = 1; + QUnit.start(); + }, config.testTimeout); + } + } +}; + +//We want access to the constructor's prototype +(function() { + function F(){}; + F.prototype = QUnit; + QUnit = new F(); + //Make F QUnit's constructor so that we can add to the prototype later + QUnit.constructor = F; +})(); + +// Backwards compatibility, deprecated +QUnit.equals = QUnit.equal; +QUnit.same = QUnit.deepEqual; + +// Maintain internal state +var config = { + // The queue of tests to run + queue: [], + + // block until document ready + blocking: true, + + // when enabled, show only failing tests + // gets persisted through sessionStorage and can be changed in UI via checkbox + hidepassed: false, + + // by default, run previously failed tests first + // very useful in combination with "Hide passed tests" checked + reorder: true, + + // by default, modify document.title when suite is done + altertitle: true, + + urlConfig: ['noglobals', 'notrycatch'], + + //logging callback queues + begin: [], + done: [], + log: [], + testStart: [], + testDone: [], + moduleStart: [], + moduleDone: [] +}; + +// Load paramaters +(function() { + var location = window.location || { search: "", protocol: "file:" }, + params = location.search.slice( 1 ).split( "&" ), + length = params.length, + urlParams = {}, + current; + + if ( params[ 0 ] ) { + for ( var i = 0; i < length; i++ ) { + current = params[ i ].split( "=" ); + current[ 0 ] = decodeURIComponent( current[ 0 ] ); + // allow just a key to turn on a flag, e.g., test.html?noglobals + current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; + urlParams[ current[ 0 ] ] = current[ 1 ]; + } + } + + QUnit.urlParams = urlParams; + config.filter = urlParams.filter; + + // Figure out if we're running the tests from a server or not + QUnit.isLocal = !!(location.protocol === 'file:'); +})(); + +// Expose the API as global variables, unless an 'exports' +// object exists, in that case we assume we're in CommonJS +if ( typeof exports === "undefined" || typeof require === "undefined" ) { + extend(window, QUnit); + window.QUnit = QUnit; +} else { + extend(exports, QUnit); + exports.QUnit = QUnit; +} + +// define these after exposing globals to keep them in these QUnit namespace only +extend(QUnit, { + config: config, + + // Initialize the configuration options + init: function() { + extend(config, { + stats: { all: 0, bad: 0 }, + moduleStats: { all: 0, bad: 0 }, + started: +new Date, + updateRate: 1000, + blocking: false, + autostart: true, + autorun: false, + filter: "", + queue: [], + semaphore: 0 + }); + + var tests = id( "qunit-tests" ), + banner = id( "qunit-banner" ), + result = id( "qunit-testresult" ); + + if ( tests ) { + tests.innerHTML = ""; + } + + if ( banner ) { + banner.className = ""; + } + + if ( result ) { + result.parentNode.removeChild( result ); + } + + if ( tests ) { + result = document.createElement( "p" ); + result.id = "qunit-testresult"; + result.className = "result"; + tests.parentNode.insertBefore( result, tests ); + result.innerHTML = 'Running...
 '; + } + }, + + /** + * Resets the test setup. Useful for tests that modify the DOM. + * + * If jQuery is available, uses jQuery's html(), otherwise just innerHTML. + */ + reset: function() { + if ( window.jQuery ) { + jQuery( "#qunit-fixture" ).html( config.fixture ); + } else { + var main = id( 'qunit-fixture' ); + if ( main ) { + main.innerHTML = config.fixture; + } + } + }, + + /** + * Trigger an event on an element. + * + * @example triggerEvent( document.body, "click" ); + * + * @param DOMElement elem + * @param String type + */ + triggerEvent: function( elem, type, event ) { + if ( document.createEvent ) { + event = document.createEvent("MouseEvents"); + event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, + 0, 0, 0, 0, 0, false, false, false, false, 0, null); + elem.dispatchEvent( event ); + + } else if ( elem.fireEvent ) { + elem.fireEvent("on"+type); + } + }, + + // Safe object type checking + is: function( type, obj ) { + return QUnit.objectType( obj ) == type; + }, + + objectType: function( obj ) { + if (typeof obj === "undefined") { + return "undefined"; + + // consider: typeof null === object + } + if (obj === null) { + return "null"; + } + + var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || ''; + + switch (type) { + case 'Number': + if (isNaN(obj)) { + return "nan"; + } else { + return "number"; + } + case 'String': + case 'Boolean': + case 'Array': + case 'Date': + case 'RegExp': + case 'Function': + return type.toLowerCase(); + } + if (typeof obj === "object") { + return "object"; + } + return undefined; + }, + + push: function(result, actual, expected, message) { + var details = { + result: result, + message: message, + actual: actual, + expected: expected + }; + + message = escapeInnerText(message) || (result ? "okay" : "failed"); + message = '' + message + ""; + expected = escapeInnerText(QUnit.jsDump.parse(expected)); + actual = escapeInnerText(QUnit.jsDump.parse(actual)); + var output = message + '
'; + if (actual != expected) { + output += ''; + output += ''; + } + if (!result) { + var source = sourceFromStacktrace(); + if (source) { + details.source = source; + output += ''; + } + } + output += "
Expected:
' + expected + '
Result:
' + actual + '
Diff:
' + QUnit.diff(expected, actual) +'
Source:
' + escapeInnerText(source) + '
"; + + runLoggingCallbacks( 'log', QUnit, details ); + + config.current.assertions.push({ + result: !!result, + message: output + }); + }, + + url: function( params ) { + params = extend( extend( {}, QUnit.urlParams ), params ); + var querystring = "?", + key; + for ( key in params ) { + if ( !hasOwn.call( params, key ) ) { + continue; + } + querystring += encodeURIComponent( key ) + "=" + + encodeURIComponent( params[ key ] ) + "&"; + } + return window.location.pathname + querystring.slice( 0, -1 ); + }, + + extend: extend, + id: id, + addEvent: addEvent +}); + +//QUnit.constructor is set to the empty F() above so that we can add to it's prototype later +//Doing this allows us to tell if the following methods have been overwritten on the actual +//QUnit object, which is a deprecated way of using the callbacks. +extend(QUnit.constructor.prototype, { + // Logging callbacks; all receive a single argument with the listed properties + // run test/logs.html for any related changes + begin: registerLoggingCallback('begin'), + // done: { failed, passed, total, runtime } + done: registerLoggingCallback('done'), + // log: { result, actual, expected, message } + log: registerLoggingCallback('log'), + // testStart: { name } + testStart: registerLoggingCallback('testStart'), + // testDone: { name, failed, passed, total } + testDone: registerLoggingCallback('testDone'), + // moduleStart: { name } + moduleStart: registerLoggingCallback('moduleStart'), + // moduleDone: { name, failed, passed, total } + moduleDone: registerLoggingCallback('moduleDone') +}); + +if ( typeof document === "undefined" || document.readyState === "complete" ) { + config.autorun = true; +} + +QUnit.load = function() { + runLoggingCallbacks( 'begin', QUnit, {} ); + + // Initialize the config, saving the execution queue + var oldconfig = extend({}, config); + QUnit.init(); + extend(config, oldconfig); + + config.blocking = false; + + var urlConfigHtml = '', len = config.urlConfig.length; + for ( var i = 0, val; i < len, val = config.urlConfig[i]; i++ ) { + config[val] = QUnit.urlParams[val]; + urlConfigHtml += ''; + } + + var userAgent = id("qunit-userAgent"); + if ( userAgent ) { + userAgent.innerHTML = navigator.userAgent; + } + var banner = id("qunit-header"); + if ( banner ) { + banner.innerHTML = ' ' + banner.innerHTML + ' ' + urlConfigHtml; + addEvent( banner, "change", function( event ) { + var params = {}; + params[ event.target.name ] = event.target.checked ? true : undefined; + window.location = QUnit.url( params ); + }); + } + + var toolbar = id("qunit-testrunner-toolbar"); + if ( toolbar ) { + var filter = document.createElement("input"); + filter.type = "checkbox"; + filter.id = "qunit-filter-pass"; + addEvent( filter, "click", function() { + var ol = document.getElementById("qunit-tests"); + if ( filter.checked ) { + ol.className = ol.className + " hidepass"; + } else { + var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; + ol.className = tmp.replace(/ hidepass /, " "); + } + if ( defined.sessionStorage ) { + if (filter.checked) { + sessionStorage.setItem("qunit-filter-passed-tests", "true"); + } else { + sessionStorage.removeItem("qunit-filter-passed-tests"); + } + } + }); + if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) { + filter.checked = true; + var ol = document.getElementById("qunit-tests"); + ol.className = ol.className + " hidepass"; + } + toolbar.appendChild( filter ); + + var label = document.createElement("label"); + label.setAttribute("for", "qunit-filter-pass"); + label.innerHTML = "Hide passed tests"; + toolbar.appendChild( label ); + } + + var main = id('qunit-fixture'); + if ( main ) { + config.fixture = main.innerHTML; + } + + if (config.autostart) { + QUnit.start(); + } +}; + +addEvent(window, "load", QUnit.load); + +// addEvent(window, "error") gives us a useless event object +window.onerror = function( message, file, line ) { + if ( QUnit.config.current ) { + ok( false, message + ", " + file + ":" + line ); + } else { + test( "global failure", function() { + ok( false, message + ", " + file + ":" + line ); + }); + } +}; + +function done() { + config.autorun = true; + + // Log the last module results + if ( config.currentModule ) { + runLoggingCallbacks( 'moduleDone', QUnit, { + name: config.currentModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + } ); + } + + var banner = id("qunit-banner"), + tests = id("qunit-tests"), + runtime = +new Date - config.started, + passed = config.stats.all - config.stats.bad, + html = [ + 'Tests completed in ', + runtime, + ' milliseconds.
', + '', + passed, + ' tests of ', + config.stats.all, + ' passed, ', + config.stats.bad, + ' failed.' + ].join(''); + + if ( banner ) { + banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass"); + } + + if ( tests ) { + id( "qunit-testresult" ).innerHTML = html; + } + + if ( config.altertitle && typeof document !== "undefined" && document.title ) { + // show ✖ for good, ✔ for bad suite result in title + // use escape sequences in case file gets loaded with non-utf-8-charset + document.title = [ + (config.stats.bad ? "\u2716" : "\u2714"), + document.title.replace(/^[\u2714\u2716] /i, "") + ].join(" "); + } + + runLoggingCallbacks( 'done', QUnit, { + failed: config.stats.bad, + passed: passed, + total: config.stats.all, + runtime: runtime + } ); +} + +function validTest( name ) { + var filter = config.filter, + run = false; + + if ( !filter ) { + return true; + } + + var not = filter.charAt( 0 ) === "!"; + if ( not ) { + filter = filter.slice( 1 ); + } + + if ( name.indexOf( filter ) !== -1 ) { + return !not; + } + + if ( not ) { + run = true; + } + + return run; +} + +// so far supports only Firefox, Chrome and Opera (buggy) +// could be extended in the future to use something like https://github.com/csnover/TraceKit +function sourceFromStacktrace() { + try { + throw new Error(); + } catch ( e ) { + if (e.stacktrace) { + // Opera + return e.stacktrace.split("\n")[6]; + } else if (e.stack) { + // Firefox, Chrome + return e.stack.split("\n")[4]; + } else if (e.sourceURL) { + // Safari, PhantomJS + // TODO sourceURL points at the 'throw new Error' line above, useless + //return e.sourceURL + ":" + e.line; + } + } +} + +function escapeInnerText(s) { + if (!s) { + return ""; + } + s = s + ""; + return s.replace(/[\&<>]/g, function(s) { + switch(s) { + case "&": return "&"; + case "<": return "<"; + case ">": return ">"; + default: return s; + } + }); +} + +function synchronize( callback, last ) { + config.queue.push( callback ); + + if ( config.autorun && !config.blocking ) { + process(last); + } +} + +function process( last ) { + var start = new Date().getTime(); + config.depth = config.depth ? config.depth + 1 : 1; + + while ( config.queue.length && !config.blocking ) { + if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { + config.queue.shift()(); + } else { + window.setTimeout( function(){ + process( last ); + }, 13 ); + break; + } + } + config.depth--; + if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { + done(); + } +} + +function saveGlobal() { + config.pollution = []; + + if ( config.noglobals ) { + for ( var key in window ) { + if ( !hasOwn.call( window, key ) ) { + continue; + } + config.pollution.push( key ); + } + } +} + +function checkPollution( name ) { + var old = config.pollution; + saveGlobal(); + + var newGlobals = diff( config.pollution, old ); + if ( newGlobals.length > 0 ) { + ok( false, "Introduced global variable(s): " + newGlobals.join(", ") ); + } + + var deletedGlobals = diff( old, config.pollution ); + if ( deletedGlobals.length > 0 ) { + ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") ); + } +} + +// returns a new Array with the elements that are in a but not in b +function diff( a, b ) { + var result = a.slice(); + for ( var i = 0; i < result.length; i++ ) { + for ( var j = 0; j < b.length; j++ ) { + if ( result[i] === b[j] ) { + result.splice(i, 1); + i--; + break; + } + } + } + return result; +} + +function fail(message, exception, callback) { + if ( typeof console !== "undefined" && console.error && console.warn ) { + console.error(message); + console.error(exception); + console.warn(callback.toString()); + + } else if ( window.opera && opera.postError ) { + opera.postError(message, exception, callback.toString); + } +} + +function extend(a, b) { + for ( var prop in b ) { + if ( b[prop] === undefined ) { + delete a[prop]; + + // Avoid "Member not found" error in IE8 caused by setting window.constructor + } else if ( prop !== "constructor" || a !== window ) { + a[prop] = b[prop]; + } + } + + return a; +} + +function addEvent(elem, type, fn) { + if ( elem.addEventListener ) { + elem.addEventListener( type, fn, false ); + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, fn ); + } else { + fn(); + } +} + +function id(name) { + return !!(typeof document !== "undefined" && document && document.getElementById) && + document.getElementById( name ); +} + +function registerLoggingCallback(key){ + return function(callback){ + config[key].push( callback ); + }; +} + +// Supports deprecated method of completely overwriting logging callbacks +function runLoggingCallbacks(key, scope, args) { + //debugger; + var callbacks; + if ( QUnit.hasOwnProperty(key) ) { + QUnit[key].call(scope, args); + } else { + callbacks = config[key]; + for( var i = 0; i < callbacks.length; i++ ) { + callbacks[i].call( scope, args ); + } + } +} + +// Test for equality any JavaScript type. +// Author: Philippe Rathé +QUnit.equiv = function () { + + var innerEquiv; // the real equiv function + var callers = []; // stack to decide between skip/abort functions + var parents = []; // stack to avoiding loops from circular referencing + + // Call the o related callback with the given arguments. + function bindCallbacks(o, callbacks, args) { + var prop = QUnit.objectType(o); + if (prop) { + if (QUnit.objectType(callbacks[prop]) === "function") { + return callbacks[prop].apply(callbacks, args); + } else { + return callbacks[prop]; // or undefined + } + } + } + + var getProto = Object.getPrototypeOf || function (obj) { + return obj.__proto__; + }; + + var callbacks = function () { + + // for string, boolean, number and null + function useStrictEquality(b, a) { + if (b instanceof a.constructor || a instanceof b.constructor) { + // to catch short annotaion VS 'new' annotation of a + // declaration + // e.g. var i = 1; + // var j = new Number(1); + return a == b; + } else { + return a === b; + } + } + + return { + "string" : useStrictEquality, + "boolean" : useStrictEquality, + "number" : useStrictEquality, + "null" : useStrictEquality, + "undefined" : useStrictEquality, + + "nan" : function(b) { + return isNaN(b); + }, + + "date" : function(b, a) { + return QUnit.objectType(b) === "date" + && a.valueOf() === b.valueOf(); + }, + + "regexp" : function(b, a) { + return QUnit.objectType(b) === "regexp" + && a.source === b.source && // the regex itself + a.global === b.global && // and its modifers + // (gmi) ... + a.ignoreCase === b.ignoreCase + && a.multiline === b.multiline; + }, + + // - skip when the property is a method of an instance (OOP) + // - abort otherwise, + // initial === would have catch identical references anyway + "function" : function() { + var caller = callers[callers.length - 1]; + return caller !== Object && typeof caller !== "undefined"; + }, + + "array" : function(b, a) { + var i, j, loop; + var len; + + // b could be an object literal here + if (!(QUnit.objectType(b) === "array")) { + return false; + } + + len = a.length; + if (len !== b.length) { // safe and faster + return false; + } + + // track reference to avoid circular references + parents.push(a); + for (i = 0; i < len; i++) { + loop = false; + for (j = 0; j < parents.length; j++) { + if (parents[j] === a[i]) { + loop = true;// dont rewalk array + } + } + if (!loop && !innerEquiv(a[i], b[i])) { + parents.pop(); + return false; + } + } + parents.pop(); + return true; + }, + + "object" : function(b, a) { + var i, j, loop; + var eq = true; // unless we can proove it + var aProperties = [], bProperties = []; // collection of + // strings + + // comparing constructors is more strict than using + // instanceof + if (a.constructor !== b.constructor) { + // Allow objects with no prototype to be equivalent to + // objects with Object as their constructor. + if (!((getProto(a) === null && getProto(b) === Object.prototype) || + (getProto(b) === null && getProto(a) === Object.prototype))) + { + return false; + } + } + + // stack constructor before traversing properties + callers.push(a.constructor); + // track reference to avoid circular references + parents.push(a); + + for (i in a) { // be strict: don't ensures hasOwnProperty + // and go deep + loop = false; + for (j = 0; j < parents.length; j++) { + if (parents[j] === a[i]) + loop = true; // don't go down the same path + // twice + } + aProperties.push(i); // collect a's properties + + if (!loop && !innerEquiv(a[i], b[i])) { + eq = false; + break; + } + } + + callers.pop(); // unstack, we are done + parents.pop(); + + for (i in b) { + bProperties.push(i); // collect b's properties + } + + // Ensures identical properties name + return eq + && innerEquiv(aProperties.sort(), bProperties + .sort()); + } + }; + }(); + + innerEquiv = function() { // can take multiple arguments + var args = Array.prototype.slice.apply(arguments); + if (args.length < 2) { + return true; // end transition + } + + return (function(a, b) { + if (a === b) { + return true; // catch the most you can + } else if (a === null || b === null || typeof a === "undefined" + || typeof b === "undefined" + || QUnit.objectType(a) !== QUnit.objectType(b)) { + return false; // don't lose time with error prone cases + } else { + return bindCallbacks(a, callbacks, [ b, a ]); + } + + // apply transition with (1..n) arguments + })(args[0], args[1]) + && arguments.callee.apply(this, args.splice(1, + args.length - 1)); + }; + + return innerEquiv; + +}(); + +/** + * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | + * http://flesler.blogspot.com Licensed under BSD + * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008 + * + * @projectDescription Advanced and extensible data dumping for Javascript. + * @version 1.0.0 + * @author Ariel Flesler + * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} + */ +QUnit.jsDump = (function() { + function quote( str ) { + return '"' + str.toString().replace(/"/g, '\\"') + '"'; + }; + function literal( o ) { + return o + ''; + }; + function join( pre, arr, post ) { + var s = jsDump.separator(), + base = jsDump.indent(), + inner = jsDump.indent(1); + if ( arr.join ) + arr = arr.join( ',' + s + inner ); + if ( !arr ) + return pre + post; + return [ pre, inner + arr, base + post ].join(s); + }; + function array( arr, stack ) { + var i = arr.length, ret = Array(i); + this.up(); + while ( i-- ) + ret[i] = this.parse( arr[i] , undefined , stack); + this.down(); + return join( '[', ret, ']' ); + }; + + var reName = /^function (\w+)/; + + var jsDump = { + parse:function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance + stack = stack || [ ]; + var parser = this.parsers[ type || this.typeOf(obj) ]; + type = typeof parser; + var inStack = inArray(obj, stack); + if (inStack != -1) { + return 'recursion('+(inStack - stack.length)+')'; + } + //else + if (type == 'function') { + stack.push(obj); + var res = parser.call( this, obj, stack ); + stack.pop(); + return res; + } + // else + return (type == 'string') ? parser : this.parsers.error; + }, + typeOf:function( obj ) { + var type; + if ( obj === null ) { + type = "null"; + } else if (typeof obj === "undefined") { + type = "undefined"; + } else if (QUnit.is("RegExp", obj)) { + type = "regexp"; + } else if (QUnit.is("Date", obj)) { + type = "date"; + } else if (QUnit.is("Function", obj)) { + type = "function"; + } else if (typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined") { + type = "window"; + } else if (obj.nodeType === 9) { + type = "document"; + } else if (obj.nodeType) { + type = "node"; + } else if ( + // native arrays + toString.call( obj ) === "[object Array]" || + // NodeList objects + ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) + ) { + type = "array"; + } else { + type = typeof obj; + } + return type; + }, + separator:function() { + return this.multiline ? this.HTML ? '
' : '\n' : this.HTML ? ' ' : ' '; + }, + indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing + if ( !this.multiline ) + return ''; + var chr = this.indentChar; + if ( this.HTML ) + chr = chr.replace(/\t/g,' ').replace(/ /g,' '); + return Array( this._depth_ + (extra||0) ).join(chr); + }, + up:function( a ) { + this._depth_ += a || 1; + }, + down:function( a ) { + this._depth_ -= a || 1; + }, + setParser:function( name, parser ) { + this.parsers[name] = parser; + }, + // The next 3 are exposed so you can use them + quote:quote, + literal:literal, + join:join, + // + _depth_: 1, + // This is the list of parsers, to modify them, use jsDump.setParser + parsers:{ + window: '[Window]', + document: '[Document]', + error:'[ERROR]', //when no parser is found, shouldn't happen + unknown: '[Unknown]', + 'null':'null', + 'undefined':'undefined', + 'function':function( fn ) { + var ret = 'function', + name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE + if ( name ) + ret += ' ' + name; + ret += '('; + + ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join(''); + return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' ); + }, + array: array, + nodelist: array, + arguments: array, + object:function( map, stack ) { + var ret = [ ]; + QUnit.jsDump.up(); + for ( var key in map ) { + var val = map[key]; + ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(val, undefined, stack)); + } + QUnit.jsDump.down(); + return join( '{', ret, '}' ); + }, + node:function( node ) { + var open = QUnit.jsDump.HTML ? '<' : '<', + close = QUnit.jsDump.HTML ? '>' : '>'; + + var tag = node.nodeName.toLowerCase(), + ret = open + tag; + + for ( var a in QUnit.jsDump.DOMAttrs ) { + var val = node[QUnit.jsDump.DOMAttrs[a]]; + if ( val ) + ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' ); + } + return ret + close + open + '/' + tag + close; + }, + functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function + var l = fn.length; + if ( !l ) return ''; + + var args = Array(l); + while ( l-- ) + args[l] = String.fromCharCode(97+l);//97 is 'a' + return ' ' + args.join(', ') + ' '; + }, + key:quote, //object calls it internally, the key part of an item in a map + functionCode:'[code]', //function calls it internally, it's the content of the function + attribute:quote, //node calls it internally, it's an html attribute value + string:quote, + date:quote, + regexp:literal, //regex + number:literal, + 'boolean':literal + }, + DOMAttrs:{//attributes to dump from nodes, name=>realName + id:'id', + name:'name', + 'class':'className' + }, + HTML:false,//if true, entities are escaped ( <, >, \t, space and \n ) + indentChar:' ',//indentation unit + multiline:true //if true, items in a collection, are separated by a \n, else just a space. + }; + + return jsDump; +})(); + +// from Sizzle.js +function getText( elems ) { + var ret = "", elem; + + for ( var i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += getText( elem.childNodes ); + } + } + + return ret; +}; + +//from jquery.js +function inArray( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; +} + +/* + * Javascript Diff Algorithm + * By John Resig (http://ejohn.org/) + * Modified by Chu Alan "sprite" + * + * Released under the MIT license. + * + * More Info: + * http://ejohn.org/projects/javascript-diff-algorithm/ + * + * Usage: QUnit.diff(expected, actual) + * + * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick brown fox jumped jumps over" + */ +QUnit.diff = (function() { + function diff(o, n) { + var ns = {}; + var os = {}; + + for (var i = 0; i < n.length; i++) { + if (ns[n[i]] == null) + ns[n[i]] = { + rows: [], + o: null + }; + ns[n[i]].rows.push(i); + } + + for (var i = 0; i < o.length; i++) { + if (os[o[i]] == null) + os[o[i]] = { + rows: [], + n: null + }; + os[o[i]].rows.push(i); + } + + for (var i in ns) { + if ( !hasOwn.call( ns, i ) ) { + continue; + } + if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) { + n[ns[i].rows[0]] = { + text: n[ns[i].rows[0]], + row: os[i].rows[0] + }; + o[os[i].rows[0]] = { + text: o[os[i].rows[0]], + row: ns[i].rows[0] + }; + } + } + + for (var i = 0; i < n.length - 1; i++) { + if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null && + n[i + 1] == o[n[i].row + 1]) { + n[i + 1] = { + text: n[i + 1], + row: n[i].row + 1 + }; + o[n[i].row + 1] = { + text: o[n[i].row + 1], + row: i + 1 + }; + } + } + + for (var i = n.length - 1; i > 0; i--) { + if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null && + n[i - 1] == o[n[i].row - 1]) { + n[i - 1] = { + text: n[i - 1], + row: n[i].row - 1 + }; + o[n[i].row - 1] = { + text: o[n[i].row - 1], + row: i - 1 + }; + } + } + + return { + o: o, + n: n + }; + } + + return function(o, n) { + o = o.replace(/\s+$/, ''); + n = n.replace(/\s+$/, ''); + var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/)); + + var str = ""; + + var oSpace = o.match(/\s+/g); + if (oSpace == null) { + oSpace = [" "]; + } + else { + oSpace.push(" "); + } + var nSpace = n.match(/\s+/g); + if (nSpace == null) { + nSpace = [" "]; + } + else { + nSpace.push(" "); + } + + if (out.n.length == 0) { + for (var i = 0; i < out.o.length; i++) { + str += '' + out.o[i] + oSpace[i] + ""; + } + } + else { + if (out.n[0].text == null) { + for (n = 0; n < out.o.length && out.o[n].text == null; n++) { + str += '' + out.o[n] + oSpace[n] + ""; + } + } + + for (var i = 0; i < out.n.length; i++) { + if (out.n[i].text == null) { + str += '' + out.n[i] + nSpace[i] + ""; + } + else { + var pre = ""; + + for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) { + pre += '' + out.o[n] + oSpace[n] + ""; + } + str += " " + out.n[i].text + nSpace[i] + pre; + } + } + } + + return str; + }; +})(); + +})(this); diff --git a/addons/web/static/lib/novajs/test/test.html b/addons/web/static/lib/novajs/test/test.html new file mode 100644 index 00000000000..4ae40b1f59e --- /dev/null +++ b/addons/web/static/lib/novajs/test/test.html @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + +

QUnit example

+

+
+

+
    +
    test markup, will be hidden
    + + \ No newline at end of file diff --git a/addons/web/static/lib/novajs/test/test.js b/addons/web/static/lib/novajs/test/test.js new file mode 100644 index 00000000000..45bfed69485 --- /dev/null +++ b/addons/web/static/lib/novajs/test/test.js @@ -0,0 +1,143 @@ + +module("Class"); + +test("base", function() { + ok(!!nova.Class, "Class does exist"); + ok(!!nova.Class.extend, "extend does exist"); + var Claz = nova.Class.extend({ + test: function() { + return "ok"; + } + }); + equal(new Claz().test(), "ok"); + var Claz2 = Claz.extend({ + test: function() { + return this._super() + "2"; + } + }); + equal(new Claz2().test(), "ok2"); +}); + +module("DestroyableMixin"); + +test("base", function() { + var Claz = nova.Class.extend(_.extend({}, nova.DestroyableMixin, {})); + var x = new Claz(); + equal(!!x.isDestroyed(), false); + x.destroy(); + equal(x.isDestroyed(), true); +}); + +module("ParentedMixin"); + +test("base", function() { + var Claz = nova.Class.extend(_.extend({}, nova.ParentedMixin, {})); + var x = new Claz(); + var y = new Claz(); + y.setParent(x); + equal(y.getParent(), x); + equal(x.getChildren()[0], y); + x.destroy(); + equal(y.isDestroyed(), true); +}); + +module("Events"); + +test("base", function() { + var x = new nova.internal.Events(); + var tmp = 0; + var fct = function() {tmp = 1;}; + x.on("test", fct); + equal(tmp, 0); + x.trigger("test"); + equal(tmp, 1); + tmp = 0; + x.off("test", fct); + x.trigger("test"); + equal(tmp, 0); +}); + +module("EventDispatcherMixin"); + +test("base", function() { + var Claz = nova.Class.extend(_.extend({}, nova.EventDispatcherMixin, {})); + var x = new Claz(); + var y = new Claz(); + var tmp = 0; + var fct = function() {tmp = 1;}; + x.on("test", y, fct); + equal(tmp, 0); + x.trigger("test"); + equal(tmp, 1); + tmp = 0; + x.off("test", y, fct); + x.trigger("test"); + equal(tmp, 0); + tmp = 0; + x.on("test", y, fct); + y.destroy(); + x.trigger("test"); + equal(tmp, 0); +}); + +module("GetterSetterMixin"); + +test("base", function() { + var Claz = nova.Class.extend(_.extend({}, nova.GetterSetterMixin, {})); + var x = new Claz(); + var y = new Claz(); + x.set({test: 1}); + equal(x.get("test"), 1); + var tmp = 0; + x.on("change:test", y, function(model, options) { + tmp = 1; + equal(options.oldValue, 1); + equal(options.newValue, 2); + equal(x.get("test"), 2); + equal(model, x); + }); + x.set({test: 2}); + equal(tmp, 1); +}); + +test("change event only when changed", function() { + var Claz = nova.Class.extend(_.extend({}, nova.GetterSetterMixin, {})); + var x = new Claz(); + var exec1 = false; + var exec2 = false; + x.on("change:test", null, function() {exec1 = true;}); + x.on("change", null, function() {exec2 = true;}); + x.set({"test": 3}); + equal(exec1, true); + equal(exec2, true); + exec1 = false; + exec2 = false; + x.set({"test": 3}); + equal(exec1, false); + equal(exec2, false); +}); + +module("Widget"); + +test("base", function() { + var Claz = nova.Widget.extend({ + renderElement: function() { + this.$element.attr("id", "testdiv"); + this.$element.html("test"); + } + }); + var x = new Claz(); + x.appendTo($("body")); + var $el = $("#testdiv"); + equal($el.length, 1); + equal($el.parents()[0], $("body")[0]); + equal($el.html(), "test"); + + var y = new Claz(x); + equal(y.getParent(), x); + + x.destroy(); + $el = $("#testdiv"); + equal($el.length, 0); +}); + diff --git a/addons/web/static/lib/novajs/test/underscore.js b/addons/web/static/lib/novajs/test/underscore.js new file mode 100644 index 00000000000..208d4cd890c --- /dev/null +++ b/addons/web/static/lib/novajs/test/underscore.js @@ -0,0 +1,999 @@ +// Underscore.js 1.3.1 +// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore is freely distributable under the MIT license. +// Portions of Underscore are inspired or borrowed from Prototype, +// Oliver Steele's Functional, and John Resig's Micro-Templating. +// For all details and documentation: +// http://documentcloud.github.com/underscore + +(function() { + + // Baseline setup + // -------------- + + // Establish the root object, `window` in the browser, or `global` on the server. + var root = this; + + // Save the previous value of the `_` variable. + var previousUnderscore = root._; + + // Establish the object that gets returned to break out of a loop iteration. + var breaker = {}; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; + + // Create quick reference variables for speed access to core prototypes. + var slice = ArrayProto.slice, + unshift = ArrayProto.unshift, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. + var + nativeForEach = ArrayProto.forEach, + nativeMap = ArrayProto.map, + nativeReduce = ArrayProto.reduce, + nativeReduceRight = ArrayProto.reduceRight, + nativeFilter = ArrayProto.filter, + nativeEvery = ArrayProto.every, + nativeSome = ArrayProto.some, + nativeIndexOf = ArrayProto.indexOf, + nativeLastIndexOf = ArrayProto.lastIndexOf, + nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeBind = FuncProto.bind; + + // Create a safe reference to the Underscore object for use below. + var _ = function(obj) { return new wrapper(obj); }; + + // Export the Underscore object for **Node.js**, with + // backwards-compatibility for the old `require()` API. If we're in + // the browser, add `_` as a global object via a string identifier, + // for Closure Compiler "advanced" mode. + if (typeof exports !== 'undefined') { + if (typeof module !== 'undefined' && module.exports) { + exports = module.exports = _; + } + exports._ = _; + } else { + root['_'] = _; + } + + // Current version. + _.VERSION = '1.3.1'; + + // Collection Functions + // -------------------- + + // The cornerstone, an `each` implementation, aka `forEach`. + // Handles objects with the built-in `forEach`, arrays, and raw objects. + // Delegates to **ECMAScript 5**'s native `forEach` if available. + var each = _.each = _.forEach = function(obj, iterator, context) { + if (obj == null) return; + if (nativeForEach && obj.forEach === nativeForEach) { + obj.forEach(iterator, context); + } else if (obj.length === +obj.length) { + for (var i = 0, l = obj.length; i < l; i++) { + if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return; + } + } else { + for (var key in obj) { + if (_.has(obj, key)) { + if (iterator.call(context, obj[key], key, obj) === breaker) return; + } + } + } + }; + + // Return the results of applying the iterator to each element. + // Delegates to **ECMAScript 5**'s native `map` if available. + _.map = _.collect = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); + each(obj, function(value, index, list) { + results[results.length] = iterator.call(context, value, index, list); + }); + if (obj.length === +obj.length) results.length = obj.length; + return results; + }; + + // **Reduce** builds up a single result from a list of values, aka `inject`, + // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. + _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { + var initial = arguments.length > 2; + if (obj == null) obj = []; + if (nativeReduce && obj.reduce === nativeReduce) { + if (context) iterator = _.bind(iterator, context); + return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); + } + each(obj, function(value, index, list) { + if (!initial) { + memo = value; + initial = true; + } else { + memo = iterator.call(context, memo, value, index, list); + } + }); + if (!initial) throw new TypeError('Reduce of empty array with no initial value'); + return memo; + }; + + // The right-associative version of reduce, also known as `foldr`. + // Delegates to **ECMAScript 5**'s native `reduceRight` if available. + _.reduceRight = _.foldr = function(obj, iterator, memo, context) { + var initial = arguments.length > 2; + if (obj == null) obj = []; + if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { + if (context) iterator = _.bind(iterator, context); + return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); + } + var reversed = _.toArray(obj).reverse(); + if (context && !initial) iterator = _.bind(iterator, context); + return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator); + }; + + // Return the first value which passes a truth test. Aliased as `detect`. + _.find = _.detect = function(obj, iterator, context) { + var result; + any(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) { + result = value; + return true; + } + }); + return result; + }; + + // Return all the elements that pass a truth test. + // Delegates to **ECMAScript 5**'s native `filter` if available. + // Aliased as `select`. + _.filter = _.select = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); + each(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) results[results.length] = value; + }); + return results; + }; + + // Return all the elements for which a truth test fails. + _.reject = function(obj, iterator, context) { + var results = []; + if (obj == null) return results; + each(obj, function(value, index, list) { + if (!iterator.call(context, value, index, list)) results[results.length] = value; + }); + return results; + }; + + // Determine whether all of the elements match a truth test. + // Delegates to **ECMAScript 5**'s native `every` if available. + // Aliased as `all`. + _.every = _.all = function(obj, iterator, context) { + var result = true; + if (obj == null) return result; + if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); + each(obj, function(value, index, list) { + if (!(result = result && iterator.call(context, value, index, list))) return breaker; + }); + return result; + }; + + // Determine if at least one element in the object matches a truth test. + // Delegates to **ECMAScript 5**'s native `some` if available. + // Aliased as `any`. + var any = _.some = _.any = function(obj, iterator, context) { + iterator || (iterator = _.identity); + var result = false; + if (obj == null) return result; + if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); + each(obj, function(value, index, list) { + if (result || (result = iterator.call(context, value, index, list))) return breaker; + }); + return !!result; + }; + + // Determine if a given value is included in the array or object using `===`. + // Aliased as `contains`. + _.include = _.contains = function(obj, target) { + var found = false; + if (obj == null) return found; + if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; + found = any(obj, function(value) { + return value === target; + }); + return found; + }; + + // Invoke a method (with arguments) on every item in a collection. + _.invoke = function(obj, method) { + var args = slice.call(arguments, 2); + return _.map(obj, function(value) { + return (_.isFunction(method) ? method || value : value[method]).apply(value, args); + }); + }; + + // Convenience version of a common use case of `map`: fetching a property. + _.pluck = function(obj, key) { + return _.map(obj, function(value){ return value[key]; }); + }; + + // Return the maximum element or (element-based computation). + _.max = function(obj, iterator, context) { + if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj); + if (!iterator && _.isEmpty(obj)) return -Infinity; + var result = {computed : -Infinity}; + each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + computed >= result.computed && (result = {value : value, computed : computed}); + }); + return result.value; + }; + + // Return the minimum element (or element-based computation). + _.min = function(obj, iterator, context) { + if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj); + if (!iterator && _.isEmpty(obj)) return Infinity; + var result = {computed : Infinity}; + each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + computed < result.computed && (result = {value : value, computed : computed}); + }); + return result.value; + }; + + // Shuffle an array. + _.shuffle = function(obj) { + var shuffled = [], rand; + each(obj, function(value, index, list) { + if (index == 0) { + shuffled[0] = value; + } else { + rand = Math.floor(Math.random() * (index + 1)); + shuffled[index] = shuffled[rand]; + shuffled[rand] = value; + } + }); + return shuffled; + }; + + // Sort the object's values by a criterion produced by an iterator. + _.sortBy = function(obj, iterator, context) { + return _.pluck(_.map(obj, function(value, index, list) { + return { + value : value, + criteria : iterator.call(context, value, index, list) + }; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }), 'value'); + }; + + // Groups the object's values by a criterion. Pass either a string attribute + // to group by, or a function that returns the criterion. + _.groupBy = function(obj, val) { + var result = {}; + var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; }; + each(obj, function(value, index) { + var key = iterator(value, index); + (result[key] || (result[key] = [])).push(value); + }); + return result; + }; + + // Use a comparator function to figure out at what index an object should + // be inserted so as to maintain order. Uses binary search. + _.sortedIndex = function(array, obj, iterator) { + iterator || (iterator = _.identity); + var low = 0, high = array.length; + while (low < high) { + var mid = (low + high) >> 1; + iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid; + } + return low; + }; + + // Safely convert anything iterable into a real, live array. + _.toArray = function(iterable) { + if (!iterable) return []; + if (iterable.toArray) return iterable.toArray(); + if (_.isArray(iterable)) return slice.call(iterable); + if (_.isArguments(iterable)) return slice.call(iterable); + return _.values(iterable); + }; + + // Return the number of elements in an object. + _.size = function(obj) { + return _.toArray(obj).length; + }; + + // Array Functions + // --------------- + + // Get the first element of an array. Passing **n** will return the first N + // values in the array. Aliased as `head`. The **guard** check allows it to work + // with `_.map`. + _.first = _.head = function(array, n, guard) { + return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; + }; + + // Returns everything but the last entry of the array. Especcialy useful on + // the arguments object. Passing **n** will return all the values in + // the array, excluding the last N. The **guard** check allows it to work with + // `_.map`. + _.initial = function(array, n, guard) { + return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); + }; + + // Get the last element of an array. Passing **n** will return the last N + // values in the array. The **guard** check allows it to work with `_.map`. + _.last = function(array, n, guard) { + if ((n != null) && !guard) { + return slice.call(array, Math.max(array.length - n, 0)); + } else { + return array[array.length - 1]; + } + }; + + // Returns everything but the first entry of the array. Aliased as `tail`. + // Especially useful on the arguments object. Passing an **index** will return + // the rest of the values in the array from that index onward. The **guard** + // check allows it to work with `_.map`. + _.rest = _.tail = function(array, index, guard) { + return slice.call(array, (index == null) || guard ? 1 : index); + }; + + // Trim out all falsy values from an array. + _.compact = function(array) { + return _.filter(array, function(value){ return !!value; }); + }; + + // Return a completely flattened version of an array. + _.flatten = function(array, shallow) { + return _.reduce(array, function(memo, value) { + if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value)); + memo[memo.length] = value; + return memo; + }, []); + }; + + // Return a version of the array that does not contain the specified value(s). + _.without = function(array) { + return _.difference(array, slice.call(arguments, 1)); + }; + + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + // Aliased as `unique`. + _.uniq = _.unique = function(array, isSorted, iterator) { + var initial = iterator ? _.map(array, iterator) : array; + var result = []; + _.reduce(initial, function(memo, el, i) { + if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) { + memo[memo.length] = el; + result[result.length] = array[i]; + } + return memo; + }, []); + return result; + }; + + // Produce an array that contains the union: each distinct element from all of + // the passed-in arrays. + _.union = function() { + return _.uniq(_.flatten(arguments, true)); + }; + + // Produce an array that contains every item shared between all the + // passed-in arrays. (Aliased as "intersect" for back-compat.) + _.intersection = _.intersect = function(array) { + var rest = slice.call(arguments, 1); + return _.filter(_.uniq(array), function(item) { + return _.every(rest, function(other) { + return _.indexOf(other, item) >= 0; + }); + }); + }; + + // Take the difference between one array and a number of other arrays. + // Only the elements present in just the first array will remain. + _.difference = function(array) { + var rest = _.flatten(slice.call(arguments, 1)); + return _.filter(array, function(value){ return !_.include(rest, value); }); + }; + + // Zip together multiple lists into a single array -- elements that share + // an index go together. + _.zip = function() { + var args = slice.call(arguments); + var length = _.max(_.pluck(args, 'length')); + var results = new Array(length); + for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i); + return results; + }; + + // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), + // we need this function. Return the position of the first occurrence of an + // item in an array, or -1 if the item is not included in the array. + // Delegates to **ECMAScript 5**'s native `indexOf` if available. + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + _.indexOf = function(array, item, isSorted) { + if (array == null) return -1; + var i, l; + if (isSorted) { + i = _.sortedIndex(array, item); + return array[i] === item ? i : -1; + } + if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item); + for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i; + return -1; + }; + + // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. + _.lastIndexOf = function(array, item) { + if (array == null) return -1; + if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item); + var i = array.length; + while (i--) if (i in array && array[i] === item) return i; + return -1; + }; + + // Generate an integer Array containing an arithmetic progression. A port of + // the native Python `range()` function. See + // [the Python documentation](http://docs.python.org/library/functions.html#range). + _.range = function(start, stop, step) { + if (arguments.length <= 1) { + stop = start || 0; + start = 0; + } + step = arguments[2] || 1; + + var len = Math.max(Math.ceil((stop - start) / step), 0); + var idx = 0; + var range = new Array(len); + + while(idx < len) { + range[idx++] = start; + start += step; + } + + return range; + }; + + // Function (ahem) Functions + // ------------------ + + // Reusable constructor function for prototype setting. + var ctor = function(){}; + + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). Binding with arguments is also known as `curry`. + // Delegates to **ECMAScript 5**'s native `Function.bind` if available. + // We check for `func.bind` first, to fail fast when `func` is undefined. + _.bind = function bind(func, context) { + var bound, args; + if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + if (!_.isFunction(func)) throw new TypeError; + args = slice.call(arguments, 2); + return bound = function() { + if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); + ctor.prototype = func.prototype; + var self = new ctor; + var result = func.apply(self, args.concat(slice.call(arguments))); + if (Object(result) === result) return result; + return self; + }; + }; + + // Bind all of an object's methods to that object. Useful for ensuring that + // all callbacks defined on an object belong to it. + _.bindAll = function(obj) { + var funcs = slice.call(arguments, 1); + if (funcs.length == 0) funcs = _.functions(obj); + each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); + return obj; + }; + + // Memoize an expensive function by storing its results. + _.memoize = function(func, hasher) { + var memo = {}; + hasher || (hasher = _.identity); + return function() { + var key = hasher.apply(this, arguments); + return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); + }; + }; + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + _.delay = function(func, wait) { + var args = slice.call(arguments, 2); + return setTimeout(function(){ return func.apply(func, args); }, wait); + }; + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + _.defer = function(func) { + return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); + }; + + // Returns a function, that, when invoked, will only be triggered at most once + // during a given window of time. + _.throttle = function(func, wait) { + var context, args, timeout, throttling, more; + var whenDone = _.debounce(function(){ more = throttling = false; }, wait); + return function() { + context = this; args = arguments; + var later = function() { + timeout = null; + if (more) func.apply(context, args); + whenDone(); + }; + if (!timeout) timeout = setTimeout(later, wait); + if (throttling) { + more = true; + } else { + func.apply(context, args); + } + whenDone(); + throttling = true; + }; + }; + + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. + _.debounce = function(func, wait) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + func.apply(context, args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }; + + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + _.once = function(func) { + var ran = false, memo; + return function() { + if (ran) return memo; + ran = true; + return memo = func.apply(this, arguments); + }; + }; + + // Returns the first function passed as an argument to the second, + // allowing you to adjust arguments, run code before and after, and + // conditionally execute the original function. + _.wrap = function(func, wrapper) { + return function() { + var args = [func].concat(slice.call(arguments, 0)); + return wrapper.apply(this, args); + }; + }; + + // Returns a function that is the composition of a list of functions, each + // consuming the return value of the function that follows. + _.compose = function() { + var funcs = arguments; + return function() { + var args = arguments; + for (var i = funcs.length - 1; i >= 0; i--) { + args = [funcs[i].apply(this, args)]; + } + return args[0]; + }; + }; + + // Returns a function that will only be executed after being called N times. + _.after = function(times, func) { + if (times <= 0) return func(); + return function() { + if (--times < 1) { return func.apply(this, arguments); } + }; + }; + + // Object Functions + // ---------------- + + // Retrieve the names of an object's properties. + // Delegates to **ECMAScript 5**'s native `Object.keys` + _.keys = nativeKeys || function(obj) { + if (obj !== Object(obj)) throw new TypeError('Invalid object'); + var keys = []; + for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; + return keys; + }; + + // Retrieve the values of an object's properties. + _.values = function(obj) { + return _.map(obj, _.identity); + }; + + // Return a sorted list of the function names available on the object. + // Aliased as `methods` + _.functions = _.methods = function(obj) { + var names = []; + for (var key in obj) { + if (_.isFunction(obj[key])) names.push(key); + } + return names.sort(); + }; + + // Extend a given object with all the properties in passed-in object(s). + _.extend = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + obj[prop] = source[prop]; + } + }); + return obj; + }; + + // Fill in a given object with default properties. + _.defaults = function(obj) { + each(slice.call(arguments, 1), function(source) { + for (var prop in source) { + if (obj[prop] == null) obj[prop] = source[prop]; + } + }); + return obj; + }; + + // Create a (shallow-cloned) duplicate of an object. + _.clone = function(obj) { + if (!_.isObject(obj)) return obj; + return _.isArray(obj) ? obj.slice() : _.extend({}, obj); + }; + + // Invokes interceptor with the obj, and then returns obj. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. + _.tap = function(obj, interceptor) { + interceptor(obj); + return obj; + }; + + // Internal recursive comparison function. + function eq(a, b, stack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal. + if (a === b) return a !== 0 || 1 / a == 1 / b; + // A strict comparison is necessary because `null == undefined`. + if (a == null || b == null) return a === b; + // Unwrap any wrapped objects. + if (a._chain) a = a._wrapped; + if (b._chain) b = b._wrapped; + // Invoke a custom `isEqual` method if one is provided. + if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b); + if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a); + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className != toString.call(b)) return false; + switch (className) { + // Strings, numbers, dates, and booleans are compared by value. + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + return a == String(b); + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for + // other numeric values. + return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + return +a == +b; + // RegExps are compared by their source patterns and flags. + case '[object RegExp]': + return a.source == b.source && + a.global == b.global && + a.multiline == b.multiline && + a.ignoreCase == b.ignoreCase; + } + if (typeof a != 'object' || typeof b != 'object') return false; + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. + var length = stack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (stack[length] == a) return true; + } + // Add the first object to the stack of traversed objects. + stack.push(a); + var size = 0, result = true; + // Recursively compare objects and arrays. + if (className == '[object Array]') { + // Compare array lengths to determine if a deep comparison is necessary. + size = a.length; + result = size == b.length; + if (result) { + // Deep compare the contents, ignoring non-numeric properties. + while (size--) { + // Ensure commutative equality for sparse arrays. + if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break; + } + } + } else { + // Objects with different constructors are not equivalent. + if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false; + // Deep compare objects. + for (var key in a) { + if (_.has(a, key)) { + // Count the expected number of properties. + size++; + // Deep compare each member. + if (!(result = _.has(b, key) && eq(a[key], b[key], stack))) break; + } + } + // Ensure that both objects contain the same number of properties. + if (result) { + for (key in b) { + if (_.has(b, key) && !(size--)) break; + } + result = !size; + } + } + // Remove the first object from the stack of traversed objects. + stack.pop(); + return result; + } + + // Perform a deep comparison to check if two objects are equal. + _.isEqual = function(a, b) { + return eq(a, b, []); + }; + + // Is a given array, string, or object empty? + // An "empty" object has no enumerable own-properties. + _.isEmpty = function(obj) { + if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; + for (var key in obj) if (_.has(obj, key)) return false; + return true; + }; + + // Is a given value a DOM element? + _.isElement = function(obj) { + return !!(obj && obj.nodeType == 1); + }; + + // Is a given value an array? + // Delegates to ECMA5's native Array.isArray + _.isArray = nativeIsArray || function(obj) { + return toString.call(obj) == '[object Array]'; + }; + + // Is a given variable an object? + _.isObject = function(obj) { + return obj === Object(obj); + }; + + // Is a given variable an arguments object? + _.isArguments = function(obj) { + return toString.call(obj) == '[object Arguments]'; + }; + if (!_.isArguments(arguments)) { + _.isArguments = function(obj) { + return !!(obj && _.has(obj, 'callee')); + }; + } + + // Is a given value a function? + _.isFunction = function(obj) { + return toString.call(obj) == '[object Function]'; + }; + + // Is a given value a string? + _.isString = function(obj) { + return toString.call(obj) == '[object String]'; + }; + + // Is a given value a number? + _.isNumber = function(obj) { + return toString.call(obj) == '[object Number]'; + }; + + // Is the given value `NaN`? + _.isNaN = function(obj) { + // `NaN` is the only value for which `===` is not reflexive. + return obj !== obj; + }; + + // Is a given value a boolean? + _.isBoolean = function(obj) { + return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; + }; + + // Is a given value a date? + _.isDate = function(obj) { + return toString.call(obj) == '[object Date]'; + }; + + // Is the given value a regular expression? + _.isRegExp = function(obj) { + return toString.call(obj) == '[object RegExp]'; + }; + + // Is a given value equal to null? + _.isNull = function(obj) { + return obj === null; + }; + + // Is a given variable undefined? + _.isUndefined = function(obj) { + return obj === void 0; + }; + + // Has own property? + _.has = function(obj, key) { + return hasOwnProperty.call(obj, key); + }; + + // Utility Functions + // ----------------- + + // Run Underscore.js in *noConflict* mode, returning the `_` variable to its + // previous owner. Returns a reference to the Underscore object. + _.noConflict = function() { + root._ = previousUnderscore; + return this; + }; + + // Keep the identity function around for default iterators. + _.identity = function(value) { + return value; + }; + + // Run a function **n** times. + _.times = function (n, iterator, context) { + for (var i = 0; i < n; i++) iterator.call(context, i); + }; + + // Escape a string for HTML interpolation. + _.escape = function(string) { + return (''+string).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g,'/'); + }; + + // Add your own custom functions to the Underscore object, ensuring that + // they're correctly added to the OOP wrapper as well. + _.mixin = function(obj) { + each(_.functions(obj), function(name){ + addToWrapper(name, _[name] = obj[name]); + }); + }; + + // Generate a unique integer id (unique within the entire client session). + // Useful for temporary DOM ids. + var idCounter = 0; + _.uniqueId = function(prefix) { + var id = idCounter++; + return prefix ? prefix + id : id; + }; + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /.^/; + + // Within an interpolation, evaluation, or escaping, remove HTML escaping + // that had been previously added. + var unescape = function(code) { + return code.replace(/\\\\/g, '\\').replace(/\\'/g, "'"); + }; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(str, data) { + var c = _.templateSettings; + var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' + + 'with(obj||{}){__p.push(\'' + + str.replace(/\\/g, '\\\\') + .replace(/'/g, "\\'") + .replace(c.escape || noMatch, function(match, code) { + return "',_.escape(" + unescape(code) + "),'"; + }) + .replace(c.interpolate || noMatch, function(match, code) { + return "'," + unescape(code) + ",'"; + }) + .replace(c.evaluate || noMatch, function(match, code) { + return "');" + unescape(code).replace(/[\r\n\t]/g, ' ') + ";__p.push('"; + }) + .replace(/\r/g, '\\r') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + + "');}return __p.join('');"; + var func = new Function('obj', '_', tmpl); + if (data) return func(data, _); + return function(data) { + return func.call(this, data, _); + }; + }; + + // Add a "chain" function, which will delegate to the wrapper. + _.chain = function(obj) { + return _(obj).chain(); + }; + + // The OOP Wrapper + // --------------- + + // If Underscore is called as a function, it returns a wrapped object that + // can be used OO-style. This wrapper holds altered versions of all the + // underscore functions. Wrapped objects may be chained. + var wrapper = function(obj) { this._wrapped = obj; }; + + // Expose `wrapper.prototype` as `_.prototype` + _.prototype = wrapper.prototype; + + // Helper function to continue chaining intermediate results. + var result = function(obj, chain) { + return chain ? _(obj).chain() : obj; + }; + + // A method to easily add functions to the OOP wrapper. + var addToWrapper = function(name, func) { + wrapper.prototype[name] = function() { + var args = slice.call(arguments); + unshift.call(args, this._wrapped); + return result(func.apply(_, args), this._chain); + }; + }; + + // Add all of the Underscore functions to the wrapper object. + _.mixin(_); + + // Add all mutator Array functions to the wrapper. + each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + wrapper.prototype[name] = function() { + var wrapped = this._wrapped; + method.apply(wrapped, arguments); + var length = wrapped.length; + if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0]; + return result(wrapped, this._chain); + }; + }); + + // Add all accessor Array functions to the wrapper. + each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + wrapper.prototype[name] = function() { + return result(method.apply(this._wrapped, arguments), this._chain); + }; + }); + + // Start chaining a wrapped Underscore object. + wrapper.prototype.chain = function() { + this._chain = true; + return this; + }; + + // Extracts the result from a wrapped and chained object. + wrapper.prototype.value = function() { + return this._wrapped; + }; + +}).call(this); diff --git a/addons/web/static/lib/py.js/.hg_archival.txt b/addons/web/static/lib/py.js/.hg_archival.txt new file mode 100644 index 00000000000..f5355e28a12 --- /dev/null +++ b/addons/web/static/lib/py.js/.hg_archival.txt @@ -0,0 +1,5 @@ +repo: 076b192d0d8ab2b92d1dbcfa3da055382f30eaea +node: 5adb2d9c89e53a6445e3799f9c4dc9110458c149 +branch: default +latesttag: 0.5 +latesttagdistance: 9 diff --git a/addons/web/static/lib/py.js/LICENSE b/addons/web/static/lib/py.js/LICENSE new file mode 100644 index 00000000000..01733ddac98 --- /dev/null +++ b/addons/web/static/lib/py.js/LICENSE @@ -0,0 +1,13 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2012 + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/addons/web/static/lib/py.js/README.rst b/addons/web/static/lib/py.js/README.rst new file mode 100644 index 00000000000..046db7153d1 --- /dev/null +++ b/addons/web/static/lib/py.js/README.rst @@ -0,0 +1,197 @@ +What +==== + +``py.js`` is a parser and evaluator of Python expressions, written in +pure javascript. + +``py.js`` is not intended to implement a full Python interpreter +(although it could be used for such an effort later on), its +specification document is the `Python 2.7 Expressions spec +`_ (along with the +lexical analysis part). + +Syntax +------ + +* Lambdas and ternaries should be parsed but are not implemented (in + the evaluator) +* Only floats are implemented, ``int`` literals are parsed as floats. +* Octal and hexadecimal literals are not implemented +* Srings are backed by JavaScript strings and probably behave like + ``unicode`` more than like ``str`` +* Slices don't work + +Builtins +-------- + +``py.js`` currently implements the following builtins: + +``type`` + Restricted to creating new types, can't be used to get an object's + type (yet) + +``None`` + +``True`` + +``False`` + +``NotImplemented`` + Returned from rich comparison methods when the comparison is not + implemented for this combination of operands. In ``py.js``, this + is also the default implementation for all rich comparison methods. + +``issubclass`` + +``object`` + +``bool`` + Does not inherit from ``int``, since ``int`` is not currently + implemented. + +``float`` + +``str`` + +``tuple`` + Constructor/coercer is not implemented, only handles literals + +``list`` + Same as tuple (``list`` is currently an alias for ``tuple``) + +``dict`` + Implements just about nothing + +Note that most methods are probably missing from all of these. + +Data model protocols +-------------------- + +``py.js`` currently implements the following protocols (or +sub-protocols) of the `Python 2.7 data model +`_: + +Rich comparisons + Roughly complete implementation but for two limits: ``__eq__`` and + ``__ne__`` can't return ``NotImplemented`` (well they can but it's + not going to work right), and the behavior is undefined if a + rich-comparison operation does not return a ``py.bool``. + + Also, a ``NotImplemented`` result does not try the reverse + operation, not sure if it's supposed to. It directly falls back to + comparing type names. + +Boolean conversion + Implementing ``__nonzero__`` should work. + +Customizing attribute access + Protocols for getting and setting attributes (including new-style + extension) fully implemented but for ``__delattr__`` (since + ``del`` is a statement) + +Descriptor protocol + As with attributes, ``__delete__`` is not implemented. + +Callable objects + +Collections Abstract Base Classes + Container is the only implemented ABC protocol (ABCs themselves + are not currently implemented) (well technically Callable and + Hashable are kind-of implemented as well) + +Numeric type emulation + Operators are implemented (but not tested), ``abs``, ``divmod`` + and ``pow`` builtins are not implemented yet. Neither are ``oct`` + and ``hex`` but I'm not sure we care (I'm not sure we care about + ``pow`` or even ``divmod`` either, for that matter) + +Utilities +--------- + +``py.js`` also provides (and exposes) a few utilities for "userland" +implementation: + +``def`` + Wraps a native javascript function into a ``py.js`` function, so + that it can be called from native expressions. + + Does not ensure the return types are type-compatible with + ``py.js`` types. + + When accessing instance methods, ``py.js`` automatically wraps + these in a variant of ``py.def`` automatically, to behave as + Python's (bound) methods. + +Why +=== + +Originally, to learn about Pratt parsers (which are very, very good at +parsing expressions with lots of infix or mixfix symbols). The +evaluator part came because "why not" and because I work on a product +with the "feature" of transmitting Python expressions (over the wire) +which the client is supposed to evaluate. + +How +=== + +At this point, only three steps exist in ``py.js``: tokenizing, +parsing and evaluation. It is possible that a compilation step be +added later (for performance reasons). + +To evaluate a Python expression, the caller merely needs to call +`py.eval`_. `py.eval`_ takes a mandatory Python +expression to evaluate (as a string) and an optional context, for the +substitution of the free variables in the expression:: + + > py.eval("type in ('a', 'b', 'c') and foo", {type: 'c', foo: true}); + true + +This is great for one-shot evaluation of expressions. If the +expression will need to be repeatedly evaluated with the same +parameters, the various parsing and evaluation steps can be performed +separately: `py.eval`_ is really a shortcut for sequentially calling +`py.tokenize`_, `py.parse`_ and `py.evaluate`_. + +API +=== + +.. _py.eval: + +``py.eval(expr[, context])`` + "Do everything" function, to use for one-shot evaluation of a + Python expression: it will internally handle the tokenizing, + parsing and actual evaluation of the Python expression without + having to perform these separately. + + ``expr`` + Python expression to evaluate + ``context`` + context dictionary holding the substitutions for the free + variables in the expression + +.. _py.tokenize: + +``py.tokenize(expr)`` + ``expr`` + Python expression to tokenize + +.. _py.parse: + +``py.parse(tokens)`` + Parses a token stream and returns an abstract syntax tree of the + expression (if the token stream represents a valid Python + expression). + + A parse tree is stateless and can be memoized and used multiple + times in separate evaluations. + + ``tokens`` + stream of tokens returned by `py.tokenize`_ + +.. _py.evaluate: + +``py.evaluate(ast[, context])`` + ``ast`` + The output of `py.parse`_ + ``context`` + The evaluation context for the Python expression. diff --git a/addons/web/static/lib/py.js/TODO.rst b/addons/web/static/lib/py.js/TODO.rst new file mode 100644 index 00000000000..a1309bd3fc5 --- /dev/null +++ b/addons/web/static/lib/py.js/TODO.rst @@ -0,0 +1,47 @@ +* Parser + since parsing expressions, try with a pratt parser + http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/ + http://effbot.org/zone/simple-top-down-parsing.htm + +Evaluator +--------- + +* Builtins should be built-in, there should be no need to add e.g. ``py.bool`` to the evaluation context (?) +* Stop busyworking trivial binary operator +* Make it *trivial* to build Python type-wrappers +* Implement Python's `data model protocols + `_ + for *all* supported operations, optimizations can come later +* Automatically type-wrap everything (for now anyway) + +Base type requirements: +*********************** + +* int +* float +* --str-- unicode +* bool +* dict +* tuple +* list +* ?module +* ?object +* datetime.time +* datetime.timedelta +* NotImplementedType + +Base methods requirement +************************ + +* ``__getattr__`` +* ``dict.get`` +* ``__len__`` + +In datamodel, not implemented in any type, untested +*************************************************** + +* a[b] + +* a + b, a - b, a * b, ... + +* +a, ~a diff --git a/addons/web/static/lib/py.js/lib/py.js b/addons/web/static/lib/py.js/lib/py.js new file mode 100644 index 00000000000..3c0b13d0717 --- /dev/null +++ b/addons/web/static/lib/py.js/lib/py.js @@ -0,0 +1,905 @@ +var py = {}; +(function (py) { + var create = function (o, props) { + function F() {} + F.prototype = o; + var inst = new F; + if (props) { + for(var name in props) { + if(!props.hasOwnProperty(name)) { continue; } + inst[name] = props[name]; + } + } + return inst; + }; + + var symbols = {}; + var comparators = {}; + var Base = { + nud: function () { throw new Error(this.id + " undefined as prefix"); }, + led: function (led) { throw new Error(this.id + " undefined as infix"); }, + toString: function () { + if (this.id === '(constant)' || this.id === '(number)' || this.id === '(name)' || this.id === '(string)') { + return [this.id.slice(0, this.id.length-1), ' ', this.value, ')'].join(''); + } else if (this.id === '(end)') { + return '(end)'; + } else if (this.id === '(comparator)' ) { + var repr = ['(comparator', this.expressions[0]]; + for (var i=0;i s.lbp) { + s.lbp = bp; + } + return s; + } + return symbols[id] = create(Base, { + id: id, + lbp: bp + }); + } + function constant(id) { + var s = symbol(id); + s.id = '(constant)'; + s.value = id; + s.nud = function () { + return this; + }; + } + function prefix(id, bp, nud) { + symbol(id).nud = nud || function () { + this.first = expression(bp); + return this + } + } + function infix(id, bp, led) { + symbol(id, bp).led = led || function (left) { + this.first = left; + this.second = expression(bp); + return this; + } + } + function infixr(id, bp) { + symbol(id, bp).led = function (left) { + this.first = left; + this.second = expression(bp - 1); + return this; + } + } + function comparator(id) { + comparators[id] = true; + var bp = 60; + infix(id, bp, function (left) { + this.id = '(comparator)'; + this.operators = [id]; + this.expressions = [left, expression(bp)]; + while (token.id in comparators) { + this.operators.push(token.id); + advance(); + this.expressions.push( + expression(bp)); + } + return this; + }); + } + + constant('None'); constant('False'); constant('True'); + + symbol('(number)').nud = function () { return this; }; + symbol('(name)').nud = function () { return this; }; + symbol('(string)').nud = function () { return this; }; + symbol('(end)'); + + symbol(':'); symbol(')'); symbol(']'); symbol('}'); symbol(','); + symbol('else'); + + infix('=', 10, function (left) { + if (left.id !== '(name)') { + throw new Error("Expected keyword argument name, got " + token.id); + } + this.first = left; + this.second = expression(); + return this; + }); + + symbol('lambda', 20).nud = function () { + this.first = []; + if (token.id !== ':') { + for(;;) { + if (token.id !== '(name)') { + throw new Error('Excepted an argument name'); + } + this.first.push(token); + advance(); + if (token.id !== ',') { + break; + } + advance(','); + } + } + advance(':'); + this.second = expression(); + return this; + }; + infix('if', 20, function (left) { + this.first = left; + this.second = expression(); + advance('else'); + this.third = expression(); + return this; + }); + + infixr('or', 30); infixr('and', 40); prefix('not', 50); + + comparator('in'); comparator('not in'); + comparator('is'); comparator('is not'); + comparator('<'); comparator('<='); + comparator('>'); comparator('>='); + comparator('<>'); comparator('!='); comparator('=='); + + infix('|', 70); infix('^', 80), infix('&', 90); + + infix('<<', 100); infix('>>', 100); + + infix('+', 110); infix('-', 110); + + infix('*', 120); infix('/', 120); + infix('//', 120), infix('%', 120); + + prefix('-', 130); prefix('+', 130); prefix('~', 130); + + infixr('**', 140); + + infix('.', 150, function (left) { + if (token.id !== '(name)') { + throw new Error('Expected attribute name, got ' + token.id); + } + this.first = left; + this.second = token; + advance(); + return this; + }); + symbol('(', 150).nud = function () { + this.first = []; + var comma = false; + if (token.id !== ')') { + while (true) { + if (token.id === ')') { + break; + } + this.first.push(expression()); + if (token.id !== ',') { + break; + } + comma = true; + advance(','); + } + } + advance(')'); + if (!this.first.length || comma) { + return this; + } else { + return this.first[0]; + } + }; + symbol('(').led = function (left) { + this.first = left; + this.second = []; + if (token.id !== ")") { + for(;;) { + this.second.push(expression()); + if (token.id !== ',') { + break; + } + advance(','); + } + } + advance(")"); + return this; + + }; + infix('[', 150, function (left) { + this.first = left; + this.second = expression(); + advance("]"); + return this; + }); + symbol('[').nud = function () { + this.first = []; + if (token.id !== ']') { + for (;;) { + if (token.id === ']') { + break; + } + this.first.push(expression()); + if (token.id !== ',') { + break; + } + advance(','); + } + } + advance(']'); + return this; + }; + + symbol('{').nud = function () { + this.first = []; + if (token.id !== '}') { + for(;;) { + if (token.id === '}') { + break; + } + var key = expression(); + advance(':'); + var value = expression(); + this.first.push([key, value]); + if (token.id !== ',') { + break; + } + advance(','); + } + } + advance('}'); + return this; + }; + + py.tokenize = (function () { + function group() { return '(' + Array.prototype.join.call(arguments, '|') + ')'; } + + var Whitespace = '[ \\f\\t]*'; + + var Name = '[a-zA-Z_]\\w*'; + + var DecNumber = '\\d+'; + var IntNumber = DecNumber; + var PointFloat = group('\\d+\\.\\d*', '\\.\\d+'); + var FloatNumber = PointFloat; + var Number = group(FloatNumber, IntNumber); + + var Operator = group("\\*\\*=?", ">>=?", "<<=?", "<>", "!=", + "//=?", "[+\\-*/%&|^=<>]=?", "~"); + var Bracket = '[\\[\\]\\(\\)\\{\\}]'; + var Special = '[:;.,`@]'; + var Funny = group(Operator, Bracket, Special); + + var ContStr = group("'[^']*'", '"[^"]*"'); + + var PseudoToken = Whitespace + group(Number, Funny, ContStr, Name); + + return function tokenize(s) { + var max=s.length, tokens = []; + // /g flag makes repeated exec() have memory + var pseudoprog = new RegExp(PseudoToken, 'g'); + + while(pseudoprog.lastIndex < max) { + var pseudomatch = pseudoprog.exec(s); + if (!pseudomatch) { + // if match failed on trailing whitespace, end tokenizing + if (/^\s+$/.test(s.slice(end))) { + break; + } + throw new Error('Failed to tokenize <<' + s + + '>> at index ' + (end || 0) + + '; parsed so far: ' + tokens); + } + + var start = pseudomatch.index, end = pseudoprog.lastIndex; + // strip leading space caught by Whitespace + var token = s.slice(start, end).replace(new RegExp('^' + Whitespace), ''); + var initial = token[0]; + + if (/\d/.test(initial) || (initial === '.' && token !== '.')) { + tokens.push(create(symbols['(number)'], { + value: parseFloat(token) + })); + } else if (/'|"/.test(initial)) { + tokens.push(create(symbols['(string)'], { + value: token.slice(1, -1) + })); + } else if (token in symbols) { + var symbol; + // transform 'not in' and 'is not' in a single token + if (token === 'in' && tokens[tokens.length-1].id === 'not') { + symbol = symbols['not in']; + tokens.pop(); + } else if (token === 'not' && tokens[tokens.length-1].id === 'is') { + symbol = symbols['is not']; + tokens.pop(); + } else { + symbol = symbols[token]; + } + tokens.push(create(symbol)); + } else if (/[_a-zA-Z]/.test(initial)) { + tokens.push(create(symbols['(name)'], { + value: token + })); + } else { + throw new Error("Tokenizing failure of <<" + s + ">> at index " + start + + " for token [[" + token + "]]" + + "; parsed so far: " + tokens); + + } + } + tokens.push(create(symbols['(end)'])); + return tokens; + } + })(); + + var token, next; + function expression(rbp) { + rbp = rbp || 0; + var t = token; + token = next(); + var left = t.nud(); + while (rbp < token.lbp) { + t = token; + token = next(); + left = t.led(left); + } + return left; + } + function advance(id) { + if (id && token.id !== id) { + throw new Error( + 'Expected "' + id + '", got "' + token.id + '"'); + } + token = next(); + } + + function PY_ensurepy(val, name) { + switch (val) { + case undefined: + throw new Error("NameError: name '" + name + "' is not defined"); + case null: + return py.None; + case true: + return py.True; + case false: + return py.False; + } + + if (val instanceof py.object + || val === py.object + || py.issubclass.__call__([val, py.object]) === py.True) { + return val; + } + + switch (typeof val) { + case 'number': + return new py.float(val); + case 'string': + return new py.str(val); + case 'function': + return new py.def(val); + } + + throw new Error("Could not convert " + val + " to a pyval"); + } + // Builtins + py.type = function type(constructor, base, dict) { + var proto; + if (!base) { + base = py.object; + } + proto = constructor.prototype = create(base.prototype); + proto.constructor = constructor; + if (dict) { + for(var k in dict) { + if (!dict.hasOwnProperty(k)) { continue; } + proto[k] = dict[k]; + } + } + constructor.__call__ = function () { + // create equivalent type with same prototype + var instance = create(proto); + // call actual constructor + var res = constructor.apply(instance, arguments); + // return result of constructor if any, otherwise instance + return res || instance; + }; + return constructor; + }; + + var hash_counter = 0; + py.object = py.type(function object() {}, {}, { + // Basic customization + __hash__: function () { + if (this._hash) { + return this._hash; + } + return this._hash = hash_counter++; + }, + __eq__: function (other) { + return (this === other) ? py.True : py.False; + }, + __ne__: function (other) { + if (this.__eq__(other) === py.True) { + return py.False; + } else { + return py.True; + } + }, + __lt__: function () { return py.NotImplemented; }, + __le__: function () { return py.NotImplemented; }, + __ge__: function () { return py.NotImplemented; }, + __gt__: function () { return py.NotImplemented; }, + __str__: function () { + return this.__unicode__(); + }, + __unicode__: function () { + // TODO: return python string + return ''; + }, + __nonzero__: function () { + return py.True; + }, + // Attribute access + __getattribute__: function (name) { + if (name in this) { + var val = this[name]; + if ('__get__' in val) { + // TODO: second argument should be class + return val.__get__(this); + } + if (typeof val === 'function' && !this.hasOwnProperty(name)) { + // val is a method from the class + return new PY_instancemethod(val, this); + } + return PY_ensurepy(val); + } + if ('__getattr__' in this) { + return this.__getattr__(name); + } + throw new Error("AttributeError: object has no attribute '" + name +"'"); + }, + __setattr__: function (name, value) { + if (name in this && '__set__' in this[name]) { + this[name].__set__(this, value); + } + this[name] = value; + }, + // no delattr, because no 'del' statement + + // Conversion + toJSON: function () { + throw new Error(this.constructor.name + ' can not be converted to JSON'); + } + }); + var NoneType = py.type(function NoneType() {}, py.object, { + __nonzero__: function () { return py.False; }, + toJSON: function () { return null; } + }); + py.None = new NoneType(); + var NotImplementedType = py.type(function NotImplementedType(){}); + py.NotImplemented = new NotImplementedType(); + var booleans_initialized = false; + py.bool = py.type(function bool(value) { + value = (value instanceof Array) ? value[0] : value; + // The only actual instance of py.bool should be py.True + // and py.False. Return the new instance of py.bool if we + // are initializing py.True and py.False, otherwise always + // return either py.True or py.False. + if (!booleans_initialized) { + return; + } + if (value === undefined) { return py.False; } + return value.__nonzero__() === py.True ? py.True : py.False; + }, py.object, { + __nonzero__: function () { return this; }, + toJSON: function () { return this === py.True; } + }); + py.True = new py.bool(); + py.False = new py.bool(); + booleans_initialized = true; + py.float = py.type(function float(value) { + value = (value instanceof Array) ? value[0] : value; + if (value === undefined) { this._value = 0; return; } + if (value instanceof py.float) { return value; } + if (typeof value === 'number' || value instanceof Number) { + this._value = value; + return; + } + if (typeof value === 'string' || value instanceof String) { + this._value = parseFloat(value); + return; + } + if (value instanceof py.object && '__float__' in value) { + var res = value.__float__(); + if (res instanceof py.float) { + return res; + } + throw new Error('TypeError: __float__ returned non-float (type ' + + res.constructor.name + ')'); + } + throw new Error('TypeError: float() argument must be a string or a number'); + }, py.object, { + __eq__: function (other) { + return this._value === other._value ? py.True : py.False; + }, + __lt__: function (other) { + if (!(other instanceof py.float)) { return py.NotImplemented; } + return this._value < other._value ? py.True : py.False; + }, + __le__: function (other) { + if (!(other instanceof py.float)) { return py.NotImplemented; } + return this._value <= other._value ? py.True : py.False; + }, + __gt__: function (other) { + if (!(other instanceof py.float)) { return py.NotImplemented; } + return this._value > other._value ? py.True : py.False; + }, + __ge__: function (other) { + if (!(other instanceof py.float)) { return py.NotImplemented; } + return this._value >= other._value ? py.True : py.False; + }, + __add__: function (other) { + if (!(other instanceof py.float)) { return py.NotImplemented; } + return new py.float(this._value + other._value); + }, + __neg__: function () { + return new py.float(-this._value); + }, + __sub__: function (other) { + if (!(other instanceof py.float)) { return py.NotImplemented; } + return new py.float(this._value - other._value); + }, + __mul__: function (other) { + if (!(other instanceof py.float)) { return py.NotImplemented; } + return new py.float(this._value * other._value); + }, + __div__: function (other) { + if (!(other instanceof py.float)) { return py.NotImplemented; } + return new py.float(this._value / other._value); + }, + __nonzero__: function () { + return this._value ? py.True : py.False; + }, + toJSON: function () { + return this._value; + } + }); + py.str = py.type(function str(s) { + s = (s instanceof Array) ? s[0] : s; + if (s === undefined) { this._value = ''; return; } + if (s instanceof py.str) { return s; } + if (typeof s === 'string' || s instanceof String) { + this._value = s; + return; + } + var v = s.__str__(); + if (v instanceof py.str) { return v; } + throw new Error('TypeError: __str__ returned non-string (type ' + + v.constructor.name + ')'); + }, py.object, { + __eq__: function (other) { + if (other instanceof py.str && this._value === other._value) { + return py.True; + } + return py.False; + }, + __lt__: function (other) { + if (!(other instanceof py.str)) { return py.NotImplemented; } + return this._value < other._value ? py.True : py.False; + }, + __le__: function (other) { + if (!(other instanceof py.str)) { return py.NotImplemented; } + return this._value <= other._value ? py.True : py.False; + }, + __gt__: function (other) { + if (!(other instanceof py.str)) { return py.NotImplemented; } + return this._value > other._value ? py.True : py.False; + }, + __ge__: function (other) { + if (!(other instanceof py.str)) { return py.NotImplemented; } + return this._value >= other._value ? py.True : py.False; + }, + __add__: function (other) { + if (!(other instanceof py.str)) { return py.NotImplemented; } + return new py.str(this._value + other._value); + }, + __nonzero__: function () { + return this._value.length ? py.True : py.False; + }, + __contains__: function (s) { + return (this._value.indexOf(s._value) !== -1) ? py.True : py.False; + }, + toJSON: function () { + return this._value; + } + }); + py.tuple = py.type(function tuple() {}, null, { + __contains__: function (value) { + for(var i=0, len=this.values.length; i': ['gt', 'lt', function (a, b) {return a.constructor.name > b.constructor.name;}], + '>=': ['ge', 'le', function (a, b) {return a.constructor.name >= b.constructor.name;}], + + '+': ['add', 'radd'], + '-': ['sub', 'rsub'], + '*': ['mul', 'rmul'], + '/': ['div', 'rdiv'], + '//': ['floordiv', 'rfloordiv'], + '%': ['mod', 'rmod'], + '**': ['pow', 'rpow'], + '<<': ['lshift', 'rlshift'], + '>>': ['rshift', 'rrshift'], + '&': ['and', 'rand'], + '^': ['xor', 'rxor'], + '|': ['or', 'ror'] + }; + /** + * Implements operator fallback/reflection. + * + * First two arguments are the objects to apply the operator on, + * in their actual order (ltr). + * + * Third argument is the actual operator. + * + * If the operator methods raise exceptions, those exceptions are + * not intercepted. + */ + var PY_op = function (o1, o2, op) { + var r; + var methods = PY_operators[op]; + var forward = '__' + methods[0] + '__', reverse = '__' + methods[1] + '__'; + var otherwise = methods[2]; + + if (forward in o1 && (r = o1[forward](o2)) !== py.NotImplemented) { + return r; + } + if (reverse in o2 && (r = o2[reverse](o1)) !== py.NotImplemented) { + return r; + } + if (otherwise) { + return PY_ensurepy(otherwise(o1, o2)); + } + throw new Error( + "TypeError: unsupported operand type(s) for " + op + ": '" + + o1.constructor.name + "' and '" + + o2.constructor.name + "'"); + }; + + var PY_builtins = { + type: py.type, + + None: py.None, + True: py.True, + False: py.False, + NotImplemented: py.NotImplemented, + + object: py.object, + bool: py.bool, + float: py.float, + tuple: py.tuple, + list: py.list, + dict: py.dict, + issubclass: py.issubclass + }; + + py.parse = function (toks) { + var index = 0; + token = toks[0]; + next = function () { return toks[++index]; }; + return expression(); + }; + var evaluate_operator = function (operator, a, b) { + var v; + switch (operator) { + case 'is': return a === b ? py.True : py.False; + case 'is not': return a !== b ? py.True : py.False; + case 'in': + return b.__contains__(a); + case 'not in': + return b.__contains__(a) === py.True ? py.False : py.True; + case '==': case '!=': + case '<': case '<=': + case '>': case '>=': + return PY_op(a, b, operator); + } + throw new Error('SyntaxError: unknown comparator [[' + operator + ']]'); + }; + py.evaluate = function (expr, context) { + context = context || {}; + switch (expr.id) { + case '(name)': + var val = context[expr.value]; + if (val === undefined && expr.value in PY_builtins) { + return PY_builtins[expr.value]; + } + return PY_ensurepy(val, expr.value); + case '(string)': + return new py.str(expr.value); + case '(number)': + return new py.float(expr.value); + case '(constant)': + switch (expr.value) { + case 'None': return py.None; + case 'False': return py.False; + case 'True': return py.True; + } + throw new Error("SyntaxError: unknown constant '" + expr.value + "'"); + case '(comparator)': + var result, left = py.evaluate(expr.expressions[0], context); + for(var i=0; i>': + case '&': case '^': case '|': + return PY_op( + py.evaluate(expr.first, context), + py.evaluate(expr.second, context), + expr.id); + + default: + throw new Error('SyntaxError: Unknown node [[' + expr.id + ']]'); + } + }; + py.eval = function (str, context) { + return py.evaluate( + py.parse( + py.tokenize( + str)), + context).toJSON(); + } +})(typeof exports === 'undefined' ? py : exports); diff --git a/addons/web/static/lib/py.js/test/parser.js b/addons/web/static/lib/py.js/test/parser.js new file mode 100644 index 00000000000..bbbd5d7663d --- /dev/null +++ b/addons/web/static/lib/py.js/test/parser.js @@ -0,0 +1,132 @@ +var py = require('../lib/py.js'), + expect = require('expect.js'); + +expect.Assertion.prototype.tokens = function (n) { + var length = this.obj.length; + this.assert(length === n + 1, + 'expected ' + this.obj + ' to have ' + n + ' tokens', + 'expected ' + this.obj + ' to not have ' + n + ' tokens'); + this.assert(this.obj[length-1].id === '(end)', + 'expected ' + this.obj + ' to have and end token', + 'expected ' + this.obj + ' to not have an end token'); +}; + +expect.Assertion.prototype.named = function (value) { + this.assert(this.obj.id === '(name)', + 'expected ' + this.obj + ' to be a name token', + 'expected ' + this.obj + ' not to be a name token'); + this.assert(this.obj.value === value, + 'expected ' + this.obj + ' to have tokenized ' + value, + 'expected ' + this.obj + ' not to have tokenized ' + value); +}; +expect.Assertion.prototype.constant = function (value) { + this.assert(this.obj.id === '(constant)', + 'expected ' + this.obj + ' to be a constant token', + 'expected ' + this.obj + ' not to be a constant token'); + this.assert(this.obj.value === value, + 'expected ' + this.obj + ' to have tokenized ' + value, + 'expected ' + this.obj + ' not to have tokenized ' + value); +}; +expect.Assertion.prototype.number = function (value) { + this.assert(this.obj.id === '(number)', + 'expected ' + this.obj + ' to be a number token', + 'expected ' + this.obj + ' not to be a number token'); + this.assert(this.obj.value === value, + 'expected ' + this.obj + ' to have tokenized ' + value, + 'expected ' + this.obj + ' not to have tokenized ' + value); +}; +expect.Assertion.prototype.string = function (value) { + this.assert(this.obj.id === '(string)', + 'expected ' + this.obj + ' to be a string token', + 'expected ' + this.obj + ' not to be a string token'); + this.assert(this.obj.value === value, + 'expected ' + this.obj + ' to have tokenized ' + value, + 'expected ' + this.obj + ' not to have tokenized ' + value); +}; + +describe('Tokenizer', function () { + describe('simple literals', function () { + it('tokenizes numbers', function () { + var toks = py.tokenize('1'); + expect(toks).to.have.tokens(1); + expect(toks[0]).to.be.number(1); + + var toks = py.tokenize('-1'); + expect(toks).to.have.tokens(2); + expect(toks[0].id).to.be('-'); + expect(toks[1]).to.be.number(1); + + var toks = py.tokenize('1.2'); + expect(toks).to.have.tokens(1); + expect(toks[0]).to.be.number(1.2); + + var toks = py.tokenize('.42'); + expect(toks).to.have.tokens(1); + expect(toks[0]).to.be.number(0.42); + }); + it('tokenizes strings', function () { + var toks = py.tokenize('"foo"'); + expect(toks).to.have.tokens(1); + expect(toks[0]).to.be.string('foo'); + + var toks = py.tokenize("'foo'"); + expect(toks).to.have.tokens(1); + expect(toks[0]).to.be.string('foo'); + }); + it('tokenizes bare names', function () { + var toks = py.tokenize('foo'); + expect(toks).to.have.tokens(1); + expect(toks[0].id).to.be('(name)'); + expect(toks[0].value).to.be('foo'); + }); + it('tokenizes constants', function () { + var toks = py.tokenize('None'); + expect(toks).to.have.tokens(1); + expect(toks[0]).to.be.constant('None'); + + var toks = py.tokenize('True'); + expect(toks).to.have.tokens(1); + expect(toks[0]).to.be.constant('True'); + + var toks = py.tokenize('False'); + expect(toks).to.have.tokens(1); + expect(toks[0]).to.be.constant('False'); + }); + it('does not fuck up on trailing spaces', function () { + var toks = py.tokenize('None '); + expect(toks).to.have.tokens(1); + expect(toks[0]).to.be.constant('None'); + }); + }); + describe('collections', function () { + it('tokenizes opening and closing symbols', function () { + var toks = py.tokenize('()'); + expect(toks).to.have.tokens(2); + expect(toks[0].id).to.be('('); + expect(toks[1].id).to.be(')'); + }); + }); + describe('functions', function () { + it('tokenizes kwargs', function () { + var toks = py.tokenize('foo(bar=3, qux=4)'); + expect(toks).to.have.tokens(10); + }); + }); +}); + +describe('Parser', function () { + describe('functions', function () { + var ast = py.parse(py.tokenize('foo(bar=3, qux=4)')); + expect(ast.id).to.be('('); + expect(ast.first).to.be.named('foo'); + + args = ast.second; + expect(args[0].id).to.be('='); + expect(args[0].first).to.be.named('bar'); + expect(args[0].second).to.be.number(3); + + expect(args[1].id).to.be('='); + expect(args[1].first).to.be.named('qux'); + expect(args[1].second).to.be.number(4); + }); +}); \ No newline at end of file diff --git a/addons/web/static/lib/py.js/test/test.js b/addons/web/static/lib/py.js/test/test.js new file mode 100644 index 00000000000..31fccc23240 --- /dev/null +++ b/addons/web/static/lib/py.js/test/test.js @@ -0,0 +1,379 @@ +var py = require('../lib/py.js'), + expect = require('expect.js'); + +var ev = function (str, context) { + return py.evaluate(py.parse(py.tokenize(str)), context); +}; + +describe('Literals', function () { + describe('Number', function () { + it('should have the right type', function () { + expect(ev('1')).to.be.a(py.float); + }); + it('should yield the corresponding JS value', function () { + expect(py.eval('1')).to.be(1); + expect(py.eval('42')).to.be(42); + expect(py.eval('9999')).to.be(9999); + }); + it('should correctly handle negative literals', function () { + expect(py.eval('-1')).to.be(-1); + expect(py.eval('-42')).to.be(-42); + expect(py.eval('-9999')).to.be(-9999); + }); + it('should correctly handle float literals', function () { + expect(py.eval('.42')).to.be(0.42); + expect(py.eval('1.2')).to.be(1.2); + }); + }); + describe('Booleans', function () { + it('should have the right type', function () { + expect(ev('False')).to.be.a(py.bool); + expect(ev('True')).to.be.a(py.bool); + }); + it('should yield the corresponding JS value', function () { + expect(py.eval('False')).to.be(false); + expect(py.eval('True')).to.be(true); + }); + }); + describe('None', function () { + it('should have the right type', function () { + expect(ev('None')).to.be.a(py.object) + }); + it('should yield a JS null', function () { + expect(py.eval('None')).to.be(null); + }); + }); + describe('String', function () { + it('should have the right type', function () { + expect(ev('"foo"')).to.be.a(py.str); + expect(ev("'foo'")).to.be.a(py.str); + }); + it('should yield the corresponding JS string', function () { + expect(py.eval('"somestring"')).to.be('somestring'); + expect(py.eval("'somestring'")).to.be('somestring'); + }); + }); + describe('Tuple', function () { + it('shoud have the right type', function () { + expect(ev('()')).to.be.a(py.tuple); + }); + it('should map to a JS array', function () { + expect(py.eval('()')).to.eql([]); + expect(py.eval('(1, 2, 3)')).to.eql([1, 2, 3]); + }); + }); + describe('List', function () { + it('shoud have the right type', function () { + expect(ev('[]')).to.be.a(py.list); + }); + it('should map to a JS array', function () { + expect(py.eval('[]')).to.eql([]); + expect(py.eval('[1, 2, 3]')).to.eql([1, 2, 3]); + }); + }); + describe('Dict', function () { + it('shoud have the right type', function () { + expect(ev('{}')).to.be.a(py.dict); + }); + it('should map to a JS object', function () { + expect(py.eval("{}")).to.eql({}); + expect(py.eval("{'foo': 1, 'bar': 2}")) + .to.eql({foo: 1, bar: 2}); + }); + }); +}); +describe('Free variables', function () { + it('should return its identity', function () { + expect(py.eval('foo', {foo: 1})).to.be(1); + expect(py.eval('foo', {foo: true})).to.be(true); + expect(py.eval('foo', {foo: false})).to.be(false); + expect(py.eval('foo', {foo: null})).to.be(null); + expect(py.eval('foo', {foo: 'bar'})).to.be('bar'); + }); +}); +describe('Comparisons', function () { + describe('equality', function () { + it('should work with literals', function () { + expect(py.eval('1 == 1')).to.be(true); + expect(py.eval('"foo" == "foo"')).to.be(true); + expect(py.eval('"foo" == "bar"')).to.be(false); + }); + it('should work with free variables', function () { + expect(py.eval('1 == a', {a: 1})).to.be(true); + expect(py.eval('foo == "bar"', {foo: 'bar'})).to.be(true); + expect(py.eval('foo == "bar"', {foo: 'qux'})).to.be(false); + }); + }); + describe('inequality', function () { + it('should work with literals', function () { + expect(py.eval('1 != 2')).to.be(true); + expect(py.eval('"foo" != "foo"')).to.be(false); + expect(py.eval('"foo" != "bar"')).to.be(true); + }); + it('should work with free variables', function () { + expect(py.eval('1 != a', {a: 42})).to.be(true); + expect(py.eval('foo != "bar"', {foo: 'bar'})).to.be(false); + expect(py.eval('foo != "bar"', {foo: 'qux'})).to.be(true); + expect(py.eval('foo != bar', {foo: 'qux', bar: 'quux'})) + .to.be(true); + }); + }); + describe('rich comparisons', function () { + it('should work with numbers', function () { + expect(py.eval('3 < 5')).to.be(true); + expect(py.eval('5 >= 3')).to.be(true); + expect(py.eval('3 >= 3')).to.be(true); + expect(py.eval('3 > 5')).to.be(false); + }); + it('should support comparison chains', function () { + expect(py.eval('1 < 3 < 5')).to.be(true); + expect(py.eval('5 > 3 > 1')).to.be(true); + expect(py.eval('1 < 3 > 2 == 2 > -2')).to.be(true); + }); + it('should compare strings', function () { + expect(py.eval('date >= current', + {date: '2010-06-08', current: '2010-06-05'})) + .to.be(true); + expect(py.eval('state == "cancel"', {state: 'cancel'})) + .to.be(true); + expect(py.eval('state == "cancel"', {state: 'open'})) + .to.be(false); + }); + }); + describe('missing eq/neq', function () { + it('should fall back on identity', function () { + var typ = new py.type(function MyType() {}); + expect(py.eval('MyType() == MyType()', {MyType: typ})).to.be(false); + }); + }); + describe('un-comparable types', function () { + it('should default to type-name ordering', function () { + var t1 = new py.type(function Type1() {}); + var t2 = new py.type(function Type2() {}); + expect(py.eval('T1() < T2()', {T1: t1, T2: t2})).to.be(true); + expect(py.eval('T1() > T2()', {T1: t1, T2: t2})).to.be(false); + }); + it('should handle native stuff', function () { + expect(py.eval('None < 42')).to.be(true); + expect(py.eval('42 > None')).to.be(true); + expect(py.eval('None > 42')).to.be(false); + + expect(py.eval('None < False')).to.be(true); + expect(py.eval('None < True')).to.be(true); + expect(py.eval('False > None')).to.be(true); + expect(py.eval('True > None')).to.be(true); + expect(py.eval('None > False')).to.be(false); + expect(py.eval('None > True')).to.be(false); + + expect(py.eval('False < ""')).to.be(true); + expect(py.eval('"" > False')).to.be(true); + expect(py.eval('False > ""')).to.be(false); + }); + }); +}); +describe('Boolean operators', function () { + it('should work', function () { + expect(py.eval("foo == 'foo' or foo == 'bar'", + {foo: 'bar'})) + .to.be(true);; + expect(py.eval("foo == 'foo' and bar == 'bar'", + {foo: 'foo', bar: 'bar'})) + .to.be(true);; + }); + it('should be lazy', function () { + // second clause should nameerror if evaluated + expect(py.eval("foo == 'foo' or bar == 'bar'", + {foo: 'foo'})) + .to.be(true);; + expect(py.eval("foo == 'foo' and bar == 'bar'", + {foo: 'bar'})) + .to.be(false);; + }); + it('should return the actual object', function () { + expect(py.eval('"foo" or "bar"')).to.be('foo'); + expect(py.eval('None or "bar"')).to.be('bar'); + expect(py.eval('False or None')).to.be(null); + expect(py.eval('0 or 1')).to.be(1); + }); +}); +describe('Containment', function () { + describe('in sequences', function () { + it('should match collection items', function () { + expect(py.eval("'bar' in ('foo', 'bar')")) + .to.be(true); + expect(py.eval('1 in (1, 2, 3, 4)')) + .to.be(true);; + expect(py.eval('1 in (2, 3, 4)')) + .to.be(false);; + expect(py.eval('"url" in ("url",)')) + .to.be(true); + expect(py.eval('"foo" in ["foo", "bar"]')) + .to.be(true); + }); + it('should not be recursive', function () { + expect(py.eval('"ur" in ("url",)')) + .to.be(false);; + }); + it('should be negatable', function () { + expect(py.eval('1 not in (2, 3, 4)')).to.be(true); + expect(py.eval('"ur" not in ("url",)')).to.be(true); + expect(py.eval('-2 not in (1, 2, 3)')).to.be(true); + }); + }); + describe('in dict', function () { + // TODO + }); + describe('in strings', function () { + it('should match the whole string', function () { + expect(py.eval('"view" in "view"')).to.be(true); + expect(py.eval('"bob" in "view"')).to.be(false); + }); + it('should match substrings', function () { + expect(py.eval('"ur" in "url"')).to.be(true); + }); + }); +}); +describe('Conversions', function () { + describe('to bool', function () { + describe('strings', function () { + it('should be true if non-empty', function () { + expect(py.eval('bool(date_deadline)', + {date_deadline: '2008'})) + .to.be(true); + }); + it('should be false if empty', function () { + expect(py.eval('bool(s)', {s: ''})) .to.be(false); + }); + }); + }); +}); +describe('Attribute access', function () { + it("should return the attribute's value", function () { + var o = new py.object(); + o.bar = py.True; + expect(py.eval('foo.bar', {foo: o})).to.be(true); + o.bar = py.False; + expect(py.eval('foo.bar', {foo: o})).to.be(false); + }); + it("should work with functions", function () { + var o = new py.object(); + o.bar = new py.def(function () { + return new py.str("ok"); + }); + expect(py.eval('foo.bar()', {foo: o})).to.be('ok'); + }); + it('should not convert function attributes into methods', function () { + var o = new py.object(); + o.bar = new py.type(function bar() {}); + o.bar.__getattribute__ = function () { + return o.bar.baz; + } + o.bar.baz = py.True; + expect(py.eval('foo.bar.baz', {foo: o})).to.be(true); + }); + it('should work on instance attributes', function () { + var typ = py.type(function MyType() { + this.attr = new py.float(3); + }, py.object, {}); + expect(py.eval('MyType().attr', {MyType: typ})).to.be(3); + }); + it('should work on class attributes', function () { + var typ = py.type(function MyType() {}, py.object, { + attr: new py.float(3) + }); + expect(py.eval('MyType().attr', {MyType: typ})).to.be(3); + }); + it('should work with methods', function () { + var typ = py.type(function MyType() { + this.attr = new py.float(3); + }, py.object, { + some_method: function () { return new py.str('ok'); }, + get_attr: function () { return this.attr; } + }); + expect(py.eval('MyType().some_method()', {MyType: typ})).to.be('ok'); + expect(py.eval('MyType().get_attr()', {MyType: typ})).to.be(3); + }); +}); +describe('Callables', function () { + it('should wrap JS functions', function () { + expect(py.eval('foo()', {foo: function foo() { return new py.float(3); }})) + .to.be(3); + }); + it('should work on custom types', function () { + var typ = py.type(function MyType() {}, py.object, { + toJSON: function () { return true; } + }); + expect(py.eval('MyType()', {MyType: typ})).to.be(true); + }); + it('should accept kwargs', function () { + expect(py.eval('foo(ok=True)', { + foo: function foo() { return py.True; } + })).to.be(true); + }); + it('should be able to get its kwargs', function () { + expect(py.eval('foo(ok=True)', { + foo: function foo(args, kwargs) { return kwargs.ok; } + })).to.be(true); + }); + it('should be able to have both args and kwargs', function () { + expect(py.eval('foo(1, 2, 3, ok=True, nok=False)', { + foo: function (args, kwargs) { + expect(args).to.have.length(3); + expect(args[0].toJSON()).to.be(1); + expect(kwargs).to.only.have.keys('ok', 'nok') + expect(kwargs.nok.toJSON()).to.be(false); + return kwargs.ok; + } + })).to.be(true); + }); +}); +describe('issubclass', function () { + it('should say a type is its own subclass', function () { + expect(py.issubclass.__call__([py.dict, py.dict]).toJSON()) + .to.be(true); + expect(py.eval('issubclass(dict, dict)')) + .to.be(true); + }); + it('should work with subtypes', function () { + expect(py.issubclass.__call__([py.bool, py.object]).toJSON()) + .to.be(true); + }); +}); +describe('builtins', function () { + it('should aways be available', function () { + expect(py.eval('bool("foo")')).to.be(true); + }); +}); + +describe('numerical protocols', function () { + describe('True numbers (float)', function () { + describe('Basic arithmetic', function () { + it('can be added', function () { + expect(py.eval('1 + 1')).to.be(2); + expect(py.eval('1.5 + 2')).to.be(3.5); + expect(py.eval('1 + -1')).to.be(0); + }); + it('can be subtracted', function () { + expect(py.eval('1 - 1')).to.be(0); + expect(py.eval('1.5 - 2')).to.be(-0.5); + expect(py.eval('2 - 1.5')).to.be(0.5); + }); + it('can be multiplied', function () { + expect(py.eval('1 * 3')).to.be(3); + expect(py.eval('0 * 5')).to.be(0); + expect(py.eval('42 * -2')).to.be(-84); + }); + it('can be divided', function () { + expect(py.eval('1 / 2')).to.be(0.5); + expect(py.eval('2 / 1')).to.be(2); + }); + }); + }); + describe('Strings', function () { + describe('Basic arithmetics operators', function () { + it('can be added (concatenation)', function () { + expect(py.eval('"foo" + "bar"')).to.be('foobar'); + }); + }); + }); +}); \ No newline at end of file diff --git a/addons/web/static/lib/py.parse/.hg_archival.txt b/addons/web/static/lib/py.parse/.hg_archival.txt deleted file mode 100644 index 43d5d80a9e4..00000000000 --- a/addons/web/static/lib/py.parse/.hg_archival.txt +++ /dev/null @@ -1,5 +0,0 @@ -repo: 076b192d0d8ab2b92d1dbcfa3da055382f30eaea -node: 87fb1b67d6a13f10a1a328104ee4d4b2c36801ec -branch: default -latesttag: 0.2 -latesttagdistance: 1 diff --git a/addons/web/static/lib/py.parse/README b/addons/web/static/lib/py.parse/README deleted file mode 100644 index 453f001ee15..00000000000 --- a/addons/web/static/lib/py.parse/README +++ /dev/null @@ -1 +0,0 @@ -Parser and evaluator of Python expressions diff --git a/addons/web/static/lib/py.parse/TODO.rst b/addons/web/static/lib/py.parse/TODO.rst deleted file mode 100644 index 3638b681ddc..00000000000 --- a/addons/web/static/lib/py.parse/TODO.rst +++ /dev/null @@ -1,14 +0,0 @@ -* Parser - since parsing expressions, try with a pratt parser - http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/ - http://effbot.org/zone/simple-top-down-parsing.htm - -Evaluator ---------- - -* Stop busyworking trivial binary operator -* Make it *trivial* to build Python type-wrappers -* Implement Python's `data model - protocols`_ - for *all* supported operations, optimizations can come later -* Automatically type-wrap everything (for now anyway) diff --git a/addons/web/static/lib/py.parse/lib/py.js b/addons/web/static/lib/py.parse/lib/py.js deleted file mode 100644 index 19f95a870bb..00000000000 --- a/addons/web/static/lib/py.parse/lib/py.js +++ /dev/null @@ -1,546 +0,0 @@ -var py = {}; -(function (exports) { - var NUMBER = /^\d$/, - NAME_FIRST = /^[a-zA-Z_]$/, - NAME = /^[a-zA-Z0-9_]$/; - - var create = function (o, props) { - function F() {} - F.prototype = o; - var inst = new F; - for(var name in props) { - if(!props.hasOwnProperty(name)) { continue; } - inst[name] = props[name]; - } - return inst; - }; - - var symbols = {}; - var comparators = {}; - var Base = { - nud: function () { throw new Error(this.id + " undefined as prefix"); }, - led: function (led) { throw new Error(this.id + " undefined as infix"); }, - toString: function () { - if (this.id === '(constant)' || this.id === '(number)' || this.id === '(name)' || this.id === '(string)') { - return [this.id.slice(0, this.id.length-1), ' ', this.value, ')'].join(''); - } else if (this.id === '(end)') { - return '(end)'; - } else if (this.id === '(comparator)' ) { - var repr = ['(comparator', this.expressions[0]]; - for (var i=0;i s.lbp) { - s.lbp = bp; - } - return s; - } - return symbols[id] = create(Base, { - id: id, - lbp: bp - }); - } - function constant(id) { - symbol(id).nud = function () { - this.id = "(constant)"; - this.value = id; - return this; - }; - } - function prefix(id, bp, nud) { - symbol(id).nud = nud || function () { - this.first = expression(bp); - return this - } - } - function infix(id, bp, led) { - symbol(id, bp).led = led || function (left) { - this.first = left; - this.second = expression(bp); - return this; - } - } - function infixr(id, bp) { - symbol(id, bp).led = function (left) { - this.first = left; - this.second = expression(bp - 1); - return this; - } - } - function comparator(id) { - comparators[id] = true; - var bp = 60; - infix(id, bp, function (left) { - this.id = '(comparator)'; - this.operators = [id]; - this.expressions = [left, expression(bp)]; - while (token.id in comparators) { - this.operators.push(token.id); - advance(); - this.expressions.push( - expression(bp)); - } - return this; - }); - } - - constant('None'); constant('False'); constant('True'); - - symbol('(number)').nud = function () { return this; }; - symbol('(name)').nud = function () { return this; }; - symbol('(string)').nud = function () { return this; }; - symbol('(end)'); - - symbol(':'); symbol(')'); symbol(']'); symbol('}'); symbol(','); - symbol('else'); - - symbol('lambda', 20).nud = function () { - this.first = []; - if (token.id !== ':') { - for(;;) { - if (token.id !== '(name)') { - throw new Error('Excepted an argument name'); - } - this.first.push(token); - advance(); - if (token.id !== ',') { - break; - } - advance(','); - } - } - advance(':'); - this.second = expression(); - return this; - }; - infix('if', 20, function (left) { - this.first = left; - this.second = expression(); - advance('else'); - this.third = expression(); - return this; - }); - - infixr('or', 30); infixr('and', 40); prefix('not', 50); - - comparator('in'); comparator('not in'); - comparator('is'); comparator('is not'); - comparator('<'); comparator('<='); - comparator('>'); comparator('>='); - comparator('<>'); comparator('!='); comparator('=='); - - infix('|', 70); infix('^', 80), infix('&', 90); - - infix('<<', 100); infix('>>', 100); - - infix('+', 110); infix('-', 110); - - infix('*', 120); infix('/', 120); - infix('//', 120), infix('%', 120); - - prefix('-', 130); prefix('+', 130); prefix('~', 130); - - infixr('**', 140); - - infix('.', 150, function (left) { - if (token.id !== '(name)') { - throw new Error('Expected attribute name, got ', token.id); - } - this.first = left; - this.second = token; - advance(); - return this; - }); - symbol('(', 150).nud = function () { - this.first = []; - var comma = false; - if (token.id !== ')') { - while (true) { - if (token.id === ')') { - break; - } - this.first.push(expression()); - if (token.id !== ',') { - break; - } - comma = true; - advance(','); - } - } - advance(')'); - if (!this.first.length || comma) { - return this; - } else { - return this.first[0]; - } - }; - symbol('(').led = function (left) { - this.first = left; - this.second = []; - if (token.id !== ")") { - for(;;) { - this.second.push(expression()); - if (token.id !== ',') { - break; - } - advance(','); - } - } - advance(")"); - return this; - - }; - infix('[', 150, function (left) { - this.first = left; - this.second = expression(); - advance("]"); - return this; - }); - symbol('[').nud = function () { - this.first = []; - if (token.id !== ']') { - for (;;) { - if (token.id === ']') { - break; - } - this.first.push(expression()); - if (token.id !== ',') { - break; - } - advance(','); - } - } - advance(']'); - return this; - }; - - symbol('{').nud = function () { - this.first = []; - if (token.id !== '}') { - for(;;) { - if (token.id === '}') { - break; - } - var key = expression(); - advance(':'); - var value = expression(); - this.first.push([key, value]); - if (token.id !== ',') { - break; - } - advance(','); - } - } - advance('}'); - return this; - }; - - var longops = { - '*': ['*'], - '<': ['<', '=', '>'], - '>': ['=', '>'], - '!': ['='], - '=': ['='], - '/': ['/'] - }; - function Tokenizer() { - this.states = ['initial']; - this.tokens = []; - } - Tokenizer.prototype = { - builder: function (empty) { - var key = this.states[0] + '_builder'; - if (empty) { - var value = this[key]; - delete this[key]; - return value; - } else { - return this[key] = this[key] || []; - } - }, - simple: function (type) { - this.tokens.push({type: type}); - }, - push: function (new_state) { - this.states.push(new_state); - }, - pop: function () { - this.states.pop(); - }, - - feed: function (str, index) { - var s = this.states; - return this[s[s.length - 1]](str, index); - }, - - initial: function (str, index) { - var character = str[index]; - - if (character in longops) { - var follow = longops[character]; - for(var i=0, len=follow.length; i> at index " + index - + ", character [[" + character + "]]" - + "; parsed so far: " + this.tokens); - }, - string: function (str, index) { - var character = str[index]; - if (character === '"' || character === "'") { - this.tokens.push(create(symbols['(string)'], { - value: this.builder(true).join('') - })); - this.pop(); - return index + 1; - } - this.builder().push(character); - return index + 1; - }, - number: function (str, index) { - var character = str[index]; - if (!(character == '.' || NUMBER.test(character))) { - this.tokens.push(create(symbols['(number)'], { - value: parseFloat(this.builder(true).join('')) - })); - this.pop(); - return index; - } - this.builder().push(character); - return index + 1; - }, - name: function (str, index) { - var character = str[index]; - if (!NAME.test(character)) { - var name = this.builder(true).join(''); - var symbol = symbols[name]; - if (symbol) { - if (name === 'in' && this.tokens[this.tokens.length-1].id === 'not') { - symbol = symbols['not in']; - this.tokens.pop(); - } else if (name === 'not' && this.tokens[this.tokens.length-1].id === 'is') { - symbol = symbols['is not']; - this.tokens.pop(); - } - this.tokens.push(create(symbol)); - } else { - this.tokens.push(create(symbols['(name)'], { - value: name - })); - } - this.pop(); - return index; - } - this.builder().push(character); - return index + 1; - } - }; - - exports.tokenize = function tokenize(str) { - var index = 0, - tokenizer = new Tokenizer(str); - str += '\0'; - - do { - index = tokenizer.feed(str, index); - } while (index !== str.length); - return tokenizer.tokens; - }; - - var token, next; - function expression(rbp) { - rbp = rbp || 0; - var t = token; - token = next(); - var left = t.nud(); - while (rbp < token.lbp) { - t = token; - token = next(); - left = t.led(left); - } - return left; - } - function advance(id) { - if (id && token.id !== id) { - throw new Error( - 'Expected "' + id + '", got "' + token.id + '"'); - } - token = next(); - } - - exports.object = create({}, {}); - exports.bool = function (arg) { return !!arg; }; - exports.tuple = create(exports.object, { - __contains__: function (value) { - for(var i=0, len=this.values.length; i': return a > b; - case '>=': return a >= b; - case 'in': - if (typeof b === 'string') { - return b.indexOf(a) !== -1; - } - return b.__contains__(a); - case 'not in': - if (typeof b === 'string') { - return b.indexOf(a) === -1; - } - return !b.__contains__(a); - } - throw new Error('SyntaxError: unknown comparator [[' + operator + ']]'); - }; - exports.evaluate = function (expr, context) { - switch (expr.id) { - case '(name)': - var val = context[expr.value]; - if (val === undefined) { - throw new Error("NameError: name '" + expr.value + "' is not defined"); - } - return val; - case '(string)': - case '(number)': - return expr.value; - case '(constant)': - if (expr.value === 'None') - return null; - else if (expr.value === 'False') - return false; - else if (expr.value === 'True') - return true; - throw new Error("SyntaxError: unknown constant '" + expr.value + "'"); - case '(comparator)': - var result, left = exports.evaluate(expr.expressions[0], context); - for(var i=0; i= 3')); -assert.ok(py.eval('3 >= 3')); -assert.ok(!py.eval('5 < 3')); -assert.ok(py.eval('1 < 3 < 5')); -assert.ok(py.eval('5 > 3 > 1')); -assert.ok(py.eval('1 < 3 > 2 == 2 > -2 not in (0, 1, 2)')); -// string rich comparisons -assert.ok(py.eval( - 'date >= current', {date: '2010-06-08', current: '2010-06-05'})); - -// Boolean operators -assert.ok(py.eval( - "foo == 'foo' or foo == 'bar'", {foo: 'bar'})); -assert.ok(py.eval( - "foo == 'foo' and bar == 'bar'", {foo: 'foo', bar: 'bar'})); -// - lazyness, second clauses NameError if not short-circuited -assert.ok(py.eval( - "foo == 'foo' or bar == 'bar'", {foo: 'foo'})); -assert.ok(!py.eval( - "foo == 'foo' and bar == 'bar'", {foo: 'bar'})); - -// contains (in) -assert.ok(py.eval( - "foo in ('foo', 'bar')", {foo: 'bar'})); -assert.ok(py.eval('1 in (1, 2, 3, 4)')); -assert.ok(!py.eval('1 in (2, 3, 4)')); -assert.ok(py.eval('type in ("url",)', {type: 'url'})); -assert.ok(!py.eval('type in ("url",)', {type: 'ur'})); -assert.ok(py.eval('1 not in (2, 3, 4)')); -assert.ok(py.eval('type not in ("url",)', {type: 'ur'})); - -assert.ok(py.eval( - "foo in ['foo', 'bar']", {foo: 'bar'})); -// string contains -assert.ok(py.eval('type in "view"', {type: 'view'})); -assert.ok(!py.eval('type in "view"', {type: 'bob'})); -assert.ok(py.eval('type in "url"', {type: 'ur'})); - -// Literals -assert.strictEqual(py.eval('False'), false); -assert.strictEqual(py.eval('True'), true); -assert.strictEqual(py.eval('None'), null); -assert.ok(py.eval('foo == False', {foo: false})); -assert.ok(!py.eval('foo == False', {foo: true})); - -// conversions -assert.strictEqual( - py.eval('bool(date_deadline)', {bool: py.bool, date_deadline: '2008'}), - true); - -// getattr -assert.ok(py.eval('foo.bar', {foo: {bar: true}})); -assert.ok(!py.eval('foo.bar', {foo: {bar: false}})); - -// complex expressions -assert.ok(py.eval( - "state=='pending' and not(date_deadline and (date_deadline < current_date))", - {state: 'pending', date_deadline: false})); -assert.ok(py.eval( - "state=='pending' and not(date_deadline and (date_deadline < current_date))", - {state: 'pending', date_deadline: '2010-05-08', current_date: '2010-05-08'}));; diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index 2a27e61eb3d..dab8e6070af 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -1,2387 +1,283 @@ -body.openerp { - padding: 0; - margin: 0; - overflow-y: scroll; -} -.openerp { - padding: 0; - margin: 0; - height: 100%; - font-size: 80%; - font-family: Ubuntu, Helvetica, sans-serif; -} - -.openerp, .openerp textarea, .openerp input, .openerp select, .openerp option, -.openerp button, .openerp .ui-widget { - font-family: Ubuntu, Helvetica, sans-serif; - font-size:85%; -} - -.openerp .view-manager-main-content { - width: 100%; - padding: 0 8px 8px 8px; -} - -.openerp .oe_form_frame_cell .view-manager-main-content { - padding: 0; -} - -.oe_box { - border: 1px solid #aaf; - padding: 2px; - margin: 2px; -} - -#oe_header h2 { - margin: 2px 0; -} - -#oe_errors pre { - margin: 0; -} - -.openerp .oe-listview .oe-number { - text-align: right !important; -} -.oe-listview-header-columns { - background: #d1d1d1; /* Old browsers */ - background: -moz-linear-gradient(top, #ffffff 0%, #d1d1d1 100%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#d1d1d1)); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, #ffffff 0%,#d1d1d1 100%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, #ffffff 0%,#d1d1d1 100%); /* Opera11.10+ */ - background: -ms-linear-gradient(top, #ffffff 0%,#d1d1d1 100%); /* IE10+ */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#d1d1d1',GradientType=0 ); /* IE6-9 */ - background: linear-gradient(top, #ffffff 0%,#d1d1d1 100%); /* W3C */ -} - -.openerp .oe_hide { - display: none !important; -} - -/* STATES */ -.openerp .on_logged, -.openerp .db_options_row { - display: none; -} - -/* Loading */ -.loading { - cursor: wait; -} -.openerp .loading { - display: none; - z-index: 100; - position: fixed; - top: 0; - right: 50%; - padding: 4px 12px; - background: #A61300; - color: white; - text-align: center; - border: 1px solid #900; - border-top: none; - -moz-border-radius-bottomright: 8px; - -moz-border-radius-bottomleft: 8px; - border-bottom-right-radius: 8px; - border-bottom-left-radius: 8px; -} -.openerp .oe_notification { - z-index: 1050; - display: none; -} -.openerp .oe_notification * { - color: white; -} - -/* Login page */ - -.login { - padding: 0; - margin: 0; - font-family: "Lucida Grande", Helvetica, Verdana, Arial; - background: url("/web/static/src/img/pattern.png") repeat; - color: #eee; - font-size: 14px; - height: 100%; -} - -.login ul, ol { - padding: 0; - margin: 0; -} - -.login li { - list-style-type: none; - padding-bottom: 4px; -} - -.login a { - color: #eee; - text-decoration: none; -} - -.login button { - float: right; - display: inline-block; - cursor: pointer; - padding: 6px 16px; - font-size: 13px; - font-family: "Lucida Grande", Helvetica, Verdana, Arial; - border: 1px solid #222222; - color: white; - margin: 0; - background: #600606; - background: -moz-linear-gradient(#b92020, #600606); - background: -webkit-gradient(linear, left top, left bottom, from(#b92020), to(#600606)); - background: -ms-linear-gradient(top, #b92020, #600606); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b92020', endColorstr='#600606',GradientType=0 ); - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - border-radius: 4px; - -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(155, 155, 155, 0.4) inset; - -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(155, 155, 155, 0.4) inset; - -o-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(155, 155, 155, 0.4) inset; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(155, 155, 155, 0.4) inset; -} - -.login input, .login select { - width: 252px; - font-size: 14px; - font-family: "Lucida Grande", Helvetica, Verdana, Arial; - border: 1px solid #999999; - background: whitesmoke; - -moz-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3); - -webkit-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3); - -box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3); - -moz-border-radius: 3px; - -webkit-border-radius: 3px; - border-radius: 3px; -} - -.login input { - margin-bottom: 9px; - padding: 5px 6px; -} - -.login select { - padding: 1px; -} - -.login .dbpane { - position: fixed; - top: 0; - right: 8px; - padding: 5px 10px; - color: #eee; - border: solid 1px #333; - background: #1e1e1e; - background: rgba(30,30,30,0.94); - -moz-border-radius: 0 0 8px 8px; - -webkit-border-radius: 0 0 8px 8px; - border-radius: 0 0 8px 8px; -} - -.login .bottom { +.openerp2 { + padding: 0; + margin: 0; + font-family: "Lucida Grande", Helvetica, Verdana, Arial, sans-serif; + color: #4c4c4c; + font-size: 13px; + background: white; + position: relative; } + .openerp2 a { + text-decoration: none; } + .openerp2 .oe_webclient { position: absolute; - top: 50%; - left: 0; - right: 0; + top: 0; bottom: 0; - text-shadow: 0 1px 1px #999999; - background: #600606; - background: -moz-linear-gradient(#b41616, #600606); - background: -webkit-gradient(linear, left top, left bottom, from(#b41616), to(#600606)); - background: -ms-linear-gradient(top, #b41616, #600606); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b41616', endColorstr='#600606',GradientType=0 ); -} - -.login .pane { - position: absolute; - top: 50%; - left: 50%; - margin: -160px -166px; - border: solid 1px #333333; - background: #1e1e1e; - background: rgba(30,30,30,0.94); - padding: 22px 32px; - text-align: left; - -moz-border-radius: 8px; - -webkit-border-radius: 8px; - border-radius: 8px; - -moz-box-shadow: 0 0 18px rgba(0, 0, 0, 0.9); - -webkit-box-shadow: 0 0 18px rgba(0, 0, 0, 0.9); - -box-shadow: 0 0 18px rgba(0, 0, 0, 0.9); -} - -.login .pane h2 { - margin-top: 0; - font-size: 18px; -} - -.login #logo { - position: absolute; - top: -70px; left: 0; + right: 0; } + .openerp2 .oe_webclient .oe_application { + position: absolute; + top: 32px; + bottom: 0; + left: 206px; + right: 0; } + .openerp2 .oe_content_full_screen .oe_application { + top: 0; + left: 0; } + .openerp2 .oe_content_full_screen .topbar, .openerp2 .oe_content_full_screen .leftbar { + display: none; } + .openerp2 .oe_topbar { width: 100%; - margin: 0 auto; - text-align: center; -} - -.login .footer { - position: absolute; - bottom: -40px; - left: 0; - width: 100%; - text-align: center; -} - -.login .footer a { - font-size: 13px; - margin: 0 8px; -} - -.login .footer a:hover { - text-decoration: underline; -} - -.login .openerp { - font-weight: bold; - font-family: serif; - font-size: 16px; -} - -.openerp .login { - text-align: center; -} - -.openerp .login .login_error_message { - display: none; - background-color: #b41616; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - border-radius: 4px; - -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.8); - -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.8); - -box-shadow: 0 1px 4px rgba(0, 0, 0, 0.8); - color: #eee; - font-size: 14px; - padding: 14px 18px; - margin-top: 15px; - text-align: center; -} - -.openerp .login.login_invalid .login_error_message { - display: inline-block; -} - - - -/* Database */ -.login .oe-database-manager { - display: none; - height: 100%; - width: 100%; - background-color: white; -} -.login.database_block .bottom, -.login.database_block .login_error_message, -.login.database_block .pane { - display: none; -} -.login.database_block .oe-database-manager { - display: block; -} - -.login .database { - float: left; - width: 202px; - height: 100%; - background: #666666; -} -.login .oe_db_options { - margin-left: 202px; - color: black; - padding-top: 20px; -} - -.login .database ul { - margin-top: 65px; -} - -ul.db_options li { - padding: 5px 0 10px 5px; - background: #949292; /* Old browsers */ - background: -moz-linear-gradient(top, #949292 30%, #6d6b6b 95%, #282828 100%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(30%,#949292), color-stop(95%,#6d6b6b), color-stop(100%,#282828)); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, #949292 30%,#6d6b6b 95%,#282828 100%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, #949292 30%,#6d6b6b 95%,#282828 100%); /* Opera11.10+ */ - background: -ms-linear-gradient(top, #949292 30%,#6d6b6b 95%,#282828 100%); /* IE10+ */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#282828',GradientType=0 ); /* IE6-9 */ - background: linear-gradient(top, #949292 30%,#6d6b6b 95%,#282828 100%); /* W3C */ - /* for ie9 */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#5B5A5A',GradientType=0 ); /* IE6-9 */ - border: none; - /* overriding jquery ui */ - -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; - display: block; - font-weight: bold; - text-transform: uppercase; - margin: 1px; - color: #EEEEEE; - cursor: pointer; - width: 195px; - font-size: 12px; -} - -.db_option_table { - border: 1px solid #5A5858; - padding: 5px; - -moz-border-radius: 10px; -} - -table.db_option_table input.required { - background-color: #D2D2FF !important; -} - -.db_option_table label { - display: block; - text-align: right; -} - -.db_option_table input[type="text"], -.db_option_table input[type="password"], -.db_option_table input[type="file"], -.db_option_table select { - width: 300px; -} - -.option_string { - font-weight: bold; - color: #555; - width: 100%; - text-align: center; - padding: 10px 0; - font-size: large; -} - -label.error { - float: none; - color: red; - padding-left: .5em; - vertical-align: top; -} - -/* Main*/ -.openerp .main_table { - width: 100%; + height: 31px; + border-top: solid 1px #d3d3d3; + border-bottom: solid 1px black; + background-color: #646060; + background-image: -webkit-gradient(linear, left top, left bottom, from(#646060), to(#262626)); + background-image: -webkit-linear-gradient(top, #646060, #262626); + background-image: -moz-linear-gradient(top, #646060, #262626); + background-image: -ms-linear-gradient(top, #646060, #262626); + background-image: -o-linear-gradient(top, #646060, #262626); + background-image: linear-gradient(to bottom, #646060, #262626); } + .openerp2 .oe_topbar .oe_systray { + float: right; } + .openerp2 .oe_topbar .oe_systray > div { + float: left; + padding: 0 4px 0 4px; } + .openerp2 .oe_topbar .oe_topbar_item li { + float: left; } + .openerp2 .oe_topbar .oe_topbar_item li a { + display: block; + padding: 5px 10px 7px; + line-height: 20px; + height: 20px; + color: #eeeeee; + vertical-align: top; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); } + .openerp2 .oe_topbar .oe_topbar_item li a:hover { + background: #303030; + color: white; + -moz-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset; + -webkit-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset; + -box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset; } + .openerp2 .oe_topbar .oe_topbar_item .oe_active { + background: #303030; + font-weight: bold; + color: white; + -moz-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset; + -webkit-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset; + -box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset; } + .openerp2 .oe_topbar .oe_topbar_avatar { + width: 24px; + height: 24px; + margin: -2px 2px 0 0; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; } + .openerp2 .oe_topbar .oe_topbar_avatar { + vertical-align: top; } + .openerp2 .oe_leftbar { + width: 205px; height: 100%; background: #f0eeee; -} -.openerp .oe-application { - height: 100%; -} -.openerp .oe-application-container { - width: 100%; - height: 100%; -} - -/* IE Hack - for IE < 9 - * Avoids footer to be placed statically at 100% cutting the middle of the views - * */ -.openerp .oe-application-container { - height: auto\9; - min-height: 100%\9; -} - -/* Menu */ -.openerp .menu { - height: 34px; - background: #cc4e45; /* Old browsers */ - background: -moz-linear-gradient(top, #cc4e45 0%, #b52d20 8%, #7a211a 100%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#cc4e45), color-stop(8%,#b52d20), color-stop(100%,#7a211a)); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* Opera11.10+ */ - background: -ms-linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* IE10+ */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#CC4E45', endColorstr='#7A211A',GradientType=0 ); /* IE6-9 */ - background: linear-gradient(top, #cc4e45 0%,#b52d20 8%,#7a211a 100%); /* W3C */ -} -.openerp .menu td { - text-align: center; - padding:0; -} -.openerp .menu a { - display:block; - min-width: 60px; - height: 20px; - margin: 3px 2px; - padding: 0 8px; - - background: #bd5e54; /* Old browsers */ - background: -moz-linear-gradient(top, #bd5e54 0%, #90322a 60%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#bd5e54), color-stop(60%,#90322a)); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* Opera11.10+ */ - background: -ms-linear-gradient(top, #bd5e54 0%,#90322a 60%); /* IE10+ */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#BD5E54', endColorstr='#90322A',GradientType=0 ); /* IE6-9 */ - background: linear-gradient(top, #bd5e54 0%,#90322a 60%); /* W3C */ - - border: 1px solid #5E1A14; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - - color: #eee; - text-shadow: #222 0 1px 0; - text-decoration: none; - text-transform: uppercase; - line-height: 20px; - font-weight: bold; - font-size: 75%; - - white-space: nowrap; -} -.openerp .menu a:hover, -.openerp .menu a:focus, -.openerp .menu a.active { - background: #c6c6c6; /* Old browsers */ - background: -moz-linear-gradient(top, #c6c6c6 0%, #5c5c5c 7%, #969595 86%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#c6c6c6), color-stop(7%,#5c5c5c), color-stop(86%,#969595)); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* Opera11.10+ */ - background: -ms-linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* IE10+ */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#C6C6C6', endColorstr='#969595',GradientType=0 ); /* IE6-9 */ - background: linear-gradient(top, #c6c6c6 0%,#5c5c5c 7%,#969595 86%); /* W3C */ - /* for ie */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#5c5c5c', endColorstr='#969595',GradientType=0 ); /* IE6-9 */ - color: #fff; -} -/* Secondary Menu */ -.openerp .secondary_menu .oe_toggle_secondary_menu { - position: absolute; - cursor: pointer; - border-left: 1px solid #282828; - border-bottom: 1px solid #282828; - width: 21px; - height: 21px; - z-index: 10; - background: transparent; - color: white; - text-shadow: 0 1px 0 #333; - text-align: center; - font-size: 18px; - line-height: 18px; - right: 0; -} -.openerp .secondary_menu.oe_folded .oe_toggle_secondary_menu { - position: static; - border-left: none; - border-bottom: 1px solid #282828; - width: 21px; - height: 21px; - background: #818181; -} -.openerp .secondary_menu.oe_folded .oe_toggle_secondary_menu span.oe_menu_fold { - display: none; -} -.openerp .secondary_menu.oe_unfolded .oe_toggle_secondary_menu span.oe_menu_unfold { - display: none; -} -.openerp .secondary_menu { - width: 200px; - min-width: 200px; - border-right: 1px solid #3C3C3C; - border-bottom: 1px solid #5A5858; - background: #5A5858; - vertical-align: top; - height: 100%; - display: block; - position: relative; - font-size:85%; -} -.openerp .secondary_menu.oe_folded { - width: 20px; - min-width: 20px; - position: static; -} -.openerp .secondary_menu.oe_folded .oe_secondary_menu.active { - position: absolute; - z-index: 100; - border: 4px solid #585858; - border-color: rgba(88, 88, 88, .5); - border-radius: 4px; - min-width: 200px; -} -.openerp .secondary_menu a { - display: block; - padding: 0 5px 2px 5px; - line-height: 20px; - text-decoration: none; - white-space: nowrap; - color: white; - text-shadow: 0 1px 0 #333; -} -.openerp .oe_secondary_submenu { - background: #5A5858; -} -.openerp .secondary_menu a.oe_secondary_menu_item { - background: #949292; /* Old browsers */ - background: -moz-linear-gradient(top, #949292 0%, #6d6b6b 87%, #282828 99%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#949292), color-stop(87%,#6d6b6b), color-stop(99%,#282828)); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* Opera11.10+ */ - background: -ms-linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* IE10+ */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#282828',GradientType=0 ); /* IE6-9 */ - background: linear-gradient(top, #949292 0%,#6d6b6b 87%,#282828 99%); /* W3C */ - /* for ie9 */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#5B5A5A',GradientType=0 ); /* IE6-9 */ - white-space: nowrap; - color: white; - text-shadow: 0 1px 0 #333; - -} -.openerp a.oe_secondary_submenu_item { - padding: 0 5px 2px 10px; -} -.openerp a.oe_secondary_submenu_item, -.openerp a.oe_secondary_menu_item { - overflow: hidden; - text-overflow: ellipsis; -} -.openerp a.oe_secondary_submenu_item:hover, -.openerp a.oe_secondary_submenu_item.leaf.active { - display: block; - background: #ffffff; /* Old browsers */ - background: -moz-linear-gradient(top, #ffffff 0%, #d8d8d8 11%, #afafaf 86%, #333333 91%, #5a5858 96%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(11%,#d8d8d8), color-stop(86%,#afafaf), color-stop(91%,#333333), color-stop(96%,#5a5858)); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* Opera11.10+ */ - background: -ms-linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* IE10+ */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#5A5858',GradientType=0 ); /* IE6-9 */ - background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* W3C */ - padding: 0 5px 2px 10px; - line-height: 20px; - color: #3f3d3d; - text-decoration: none; - text-shadow: #fff 0 1px 0; -} -.openerp a.oe_secondary_submenu_item.submenu.opened span:before { - content: "\25be"; -} -.openerp a.oe_secondary_submenu_item.submenu span:before { - content: "\25b8"; -} - -/* Header */ -.openerp .header { - height: 65px; - background: url("/web/static/src/img/header-background.png") repeat-x scroll left top transparent; - color: #FFFFFF; - letter-spacing: 0.5px; - text-shadow: 0 1px 0 #333333; -} -.openerp .company_logo_link { - display: block; - float: left; - height: 63px; - width: 200px; - border: 1px solid white; - border-right-color: black; - border-bottom-color: black; - background: #FFFFFF; - background: -moz-linear-gradient(top, #FFFFFF 0%, #CECECE 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#FFFFFF), color-stop(100%,#CECECE)); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#CECECE',GradientType=0 ); -} -.openerp .company_logo { - margin-top: 7px; - margin-left: 10px; - display: block; - background: url(/web/static/src/img/logo.png); - width:180px; - height:46px; -} -.openerp .header_title { - float: left; - font-size: 100%; - margin: 0; - padding: 4px 10px; - text-shadow: 0 1px 0 #111111; - font-weight:normal; - line-height:14px; -} -.openerp .header_title small { - color: #ccc; - font-size: 90%; - font-weight: normal; -} -.openerp .header_corner { - float: right; -} -.openerp .header_corner .block { - float: left; - height: 34px; - line-height: 34px; - /*background: url(../images/top-sep-a.png) no-repeat;*/ - border-left: 1px solid #6a6a6a; - background: #828282; - background: -moz-linear-gradient(top, #828282 0%, #4D4D4D 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#828282), color-stop(100%,#4D4D4D)); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#828282', endColorstr='#4D4D4D',GradientType=0 ); -} -.openerp .header_corner .block a { - display: block; - color: white; - text-decoration: none; - padding: 0 10px; -} -.openerp .header_corner .block a:hover { - background: #929292; - background: -moz-linear-gradient(top, #929292 0%, #4D4D4D 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#929292), color-stop(100%,#4D4D4D)); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#929292', endColorstr='#4D4D4D',GradientType=0 ); -} -.openerp .header_corner ul.block { - list-style: none; - height: 34px; - margin: 0; - padding: 0 0 0 2px; - line-height: 33px; -} -.openerp .header_corner ul.block li { - float: left; -} -.openerp .header_corner ul.block li a { - padding: 0 5px; - position: relative; - line-height: 32px; -} -.openerp .header_corner ul.block li a img { - vertical-align: middle; -} -.openerp .header_corner ul.block li a small { - position: absolute; - right: 0; - top: 5px; - padding: 1px 4px 2px; - background: rgba(0, 0, 0, 0.75); - border-radius: 7px; - -moz-border-radius: 7px; - -webkit-border-radius: 7px; - line-height: 1em; - font-weight: bold; -} - -.openerp .logout { - font-size:80%; -} - -/* Footer */ -.openerp div.oe_footer { - background: none repeat scroll 0 0 #CCCCCC; - overflow: hidden; - padding: 5px 0; - position: relative; - -moz-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.4); - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.4); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.4); -} -.openerp div.oe_footer p.oe_footer_powered { - left: 50%; - margin: 0; - padding: 0 15px; - color: #666666; - font-weight: bold; - font-size: 0.8em; - text-align: center; -} -.openerp div.oe_footer p.oe_footer_powered a { - text-decoration: none; - color: #666666; -} - - -/* Main Application */ -.openerp .oe-main-content { - padding: 0; - height: 100%; -} - -.openerp h2.oe_view_title { - font-size: 110%; - font-weight: normal; - margin: 2px 0; - color: #252424; - text-shadow: white 0 1px 0; -} -.openerp div[id^="notebook"] .oe_view_title { - font-size:85%; - padding-bottom:4px; -} - -/* View Manager */ -.openerp .oe_vm_switch { - float: right; -} -.openerp .oe-view-manager-header .oe_view_title { - font-size:150%; - padding:2px 0 0 0; -} - -/* SearchView */ -.openerp .oe_searchview_field > div { - position: relative; - white-space: nowrap; -} -.openerp .oe_searchview_field .oe_input_icon { - top: auto; - bottom: 3px; -} - -.openerp .filter_label, .openerp .filter_icon { - background: #F0F0F0; - border: 1px solid #999; - background: -moz-linear-gradient(top, #F0F0F0 0%, #C0C0C0 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#F0F0F0), color-stop(100%,#C0C0C0)); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#F0F0F0', endColorstr='#C0C0C0',GradientType=0 ); -} -.openerp .filter_label:hover, .openerp .filter_icon:hover { - background: #F0F0F0; - background: -moz-linear-gradient(top, #F0F0F0 0%, #A1A7CE 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#F0F0F0), color-stop(100%,#A1A7CE)); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#F0F0F0', endColorstr='#A1A7CE',GradientType=0 ); -} -.openerp .filter_label:active, .openerp .filter_icon:active { - background: #aaa; - background: -moz-linear-gradient(top, #999999 0%, #EEEEEE 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#999999), color-stop(100%,#EEEEEE)); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#999999', endColorstr='#EEEEEE',GradientType=0 ); -} -.openerp .filter_label.enabled, .openerp .filter_icon.enabled { - background: #aaa; - filter: none; - -moz-box-shadow: none; - -webkit-box-shadow: none; - -o-box-shadow: none; - box-shadow: none; -} -.openerp .filter_icon { - height: 22px; - padding: 1px 2px 0 2px; - margin: 0; - vertical-align: bottom; -} -.openerp .filter_label { - font-weight: bold; - text-transform: uppercase; - text-shadow: #EEE 0 1px 0; - color: #4C4C4C; - white-space: nowrap; - min-height: 40px; - min-width: 75px; - padding: 2px 4px; - margin: 0; -} -.openerp .filter_label_group { - padding-right: 0.4em; - white-space: nowrap; -} - -.openerp .filter_label_group button { - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; - border-right: none; -} -.openerp .filter_label_group button:first-child { - -webkit-border-top-left-radius: 7px; - -webkit-border-bottom-left-radius: 7px; - -moz-border-radius-topleft: 7px; - -moz-border-radius-bottomleft: 7px; - border-top-left-radius: 7px; - border-bottom-left-radius: 7px; - border-right: none; -} -.openerp .filter_label_group button:last-child { - -webkit-border-top-right-radius: 7px; - -webkit-border-bottom-right-radius: 7px; - -moz-border-radius-topright: 7px; - -moz-border-radius-bottomright: 7px; - border-top-right-radius: 7px; - border-bottom-right-radius: 7px; - border-right: 1px solid #999; -} -.openerp .filter_label_group button.filter_icon img { - padding: 1px 8px 0 8px; -} -.openerp .filter_label_group button.filter_icon:first-child { - border-left: solid 1px #999; - margin-left: -7px; - -webkit-border-top-left-radius: 0; - -webkit-border-bottom-left-radius: 0; - -moz-border-radius-topleft: 0; - -moz-border-radius-bottomleft: 0; - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - -.openerp .searchview_group_string { - display: block; - color: #7D7979; - font-weight: bold; - padding: 2px 0 2px 10px; - text-decoration: none; -} -.openerp .searchview_group_string:hover { - background-color: #ccc; -} -.openerp .searchview_group.folded .searchview_group_string { - background: url("/web/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("/web/static/src/img/ui/group-expanded.png") no-repeat scroll 0 50%; -} -.openerp .searchview_group.expanded .searchview_group_content { - display: block; - padding-bottom:3px; -} - -.openerp .searchview_group_content .oe_label, .openerp .searchview_group_content .oe_label_help { - font-weight: bold; - color: #4c4c4c; -} - -.openerp .oe-searchview-render-line .oe_label, .openerp .oe-searchview-render-line .oe_label_help { - font-weight: bold; - font-size: 80%; - white-space: nowrap; -} - -.openerp .searchview_extended_group { - padding: 3px; - margin: 2px; -} - -.openerp .searchview_extended_group .oe_adv_filters_and { - border-bottom: 1px solid #8E8E8E; - text-align: center; - margin-top: -10px; -} -.openerp .searchview_extended_group .oe_adv_filters_and span { - background: #F0EEEE; - position: relative; - top: 0.5em; - padding: 0 1em 0 1em; - color: #8E8E8E; -} - -.openerp .searchview_extended_group.last_group .oe_adv_filters_and { - display: none; -} - -.openerp .oe_search-view-buttons { - padding: 2px 0 10px 0; - vertical-align:middle; -} -.openerp .oe_search-view-filters-management { - float: right; -} -.openerp .oe_search-view-filters-management, .openerp .oe_search-view-custom-filter-btn { - float:right; -} - -.openerp .searchview_extended_add_proposition span { - font-size: 0.9em; - background: url(/web/static/src/img/icons/gtk-add.png) repeat-y; - padding-left: 18px; -} - -.openerp .searchview_extended_delete_group { - float:right; - display: none; -} - -.openerp .searchview_extended_delete_prop { - text-decoration: none; -} - -.openerp .searchview_extended_delete_group span, -.openerp .searchview_extended_delete_prop span { - font-size: 0.9em; - background: url(/web/static/src/img/icons/gtk-close.png) repeat-y; - padding-left: 18px; -} -/* List */ -.openerp table.oe-listview-content { - clear: right; - width: 100%; - border-spacing: 0; - border: 1px solid silver; -} - -.openerp .oe-listview thead table { - width: 100%; - border: none; -} -.openerp .oe-listview tr.odd { - background-color: #f3f3f3; -} -.openerp .oe-listview tbody tr:hover { - background-color: #ecebf2; -} -.openerp .oe-listview tbody tr:hover { - background-color: #eae9f0; -} -.openerp .oe-listview thead table tr, -.openerp .oe-listview thead table tr:hover { - background: none; -} - -.openerp .oe-listview > table > tbody > tr > td, -.openerp .oe-listview th { - vertical-align: middle; - text-align: left; - padding: 1px 2px; -} - -.openerp .oe-record-delete button, -.openerp button.oe-edit-row-save { - border: none; - height: 12px; - width: 12px; - background: url("/web/static/src/img/iconset-b-remove.png") no-repeat scroll center center transparent; - cursor: pointer; -} -.openerp button.oe-edit-row-save { - background-image: url('/web/static/src/img/icons/save-document.png'); -} - -/* Could use :not selectors if they were supported by MSIE8... */ -.openerp .oe-listview > table > tbody > tr > td { - border-left: 1px solid #dadada; /*currently commenting to test with no vertical lines in list view*/ -} -.openerp .oe-listview tbody td:first-child, -.openerp .oe-listview tbody td.oe-button, -.openerp .oe-listview tbody td.oe-button, -.openerp .oe-listview tbody th.oe-record-selector, -.openerp .oe-listview tbody td.oe-record-delete { - border-left: none; -} - -.openerp .oe-listview td.oe-record-delete { - text-align: right; -} -.openerp .oe-listview th.oe-sortable { - cursor: pointer; - font-size: 75%; - text-transform: uppercase; - padding: 0; - margin: 0; - padding-left: 3px; - color: #333; -} -.openerp .oe-listview th.oe-sortable .ui-icon { - height: 60%; - margin: -6px 0 0; - display: inline; - display: inline-block; - vertical-align: middle; -} - -.openerp .oe-listview > table > tbody > tr > td { - border-bottom: 1px solid #E3E3E3; -} - - -.openerp .oe-listview td.oe-actions { - border-bottom:none; -} - -.openerp .oe-listview .oe-record-selector, .openerp .oe-listview .oe-record-edit-link { - border-bottom: 1px solid #E3E3E3; -} -.openerp .oe-listview .oe-record-edit-link { - cursor: pointer; -} - -.openerp .oe-listview .oe-field-cell { - cursor: pointer; - margin-top: 0; - margin-bottom: 0; - padding-top: 3px; - padding-bottom: 3px; - font-size: 80%; -} -.openerp .oe-listview .oe-field-cell progress { - width: 100%; -} -.openerp .oe-listview .oe-field-cell.oe-button button, -.openerp .oe-listview .oe_form_button button { - margin: 0; - padding: 0; - border: none; - background: none; - width: 16px; - box-shadow: none; - -moz-box-shadow: none; - -webkit-box-shadow: none; -} -.openerp .oe-listview .oe-field-cell button:active { - opacity: 0.5; -} -.openerp .oe-listview .oe-field-cell button img { - cursor: pointer; -} -.openerp .oe-listview .oe-field-cell button img:hover { - opacity: 0.75; -} - -.openerp .oe-listview .oe-field-cell .oe-listview-button-disabled img { - opacity: 0.5; -} - -.openerp .oe-listview th.oe-actions { - text-align: left; - white-space: nowrap; -} -.openerp .oe-listview th.oe-list-pager { - text-align: right; - white-space: nowrap; -} -.openerp .oe-list-pager .oe-pager-state { - cursor: pointer; - font-size: 90%; - color: #555; -} - -.openerp .oe_button.oe_button_pager, -.openerp .oe-list-pager > span, -.openerp .oe_form_pager > span { - line-height: 17px; - height: 17px; - cursor: pointer; - color: gray; - font-weight: bold; - vertical-align: middle; -} -.openerp .oe_button.oe_button_pager, -.openerp .oe_button.oe_button_pager:disabled { - padding: 0 3px 0 3px; - margin: 0; - height: 17px; -} -.openerp .oe-listview .oe-group-name { - padding-right: 1em; -} -.openerp .oe-listview .oe-group-name, -.openerp .oe-listview .oe-group-pagination { - white-space: nowrap; -} - -.openerp .oe-listview tfoot td { - padding: 3px 3px 0; -} -.openerp .oe-listview .oe-list-footer { - text-align: center; - white-space: nowrap; - color: #444; - font-size: 85%; -} -.openerp .oe-listview .oe-list-footer span { - margin: 0 1em; -} -.openerp .oe-listview .oe-list-footer progress { - vertical-align:-10% !important; - width: 100%; -} - -/** list rounded corners - - rounded corners are a pain on tables: need to round not only table, but - also on the first and last children of the first and last row - */ -.openerp .oe-listview table.oe-listview-content { - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} -.openerp .oe-listview table.oe-listview-content thead tr:first-child th:first-child { - -webkit-border-top-left-radius: 4px; - -moz-border-radius-topleft: 4px; - border-top-left-radius: 4px; -} -.openerp .oe-listview table.oe-listview-content thead tr:first-child th:last-child { - -webkit-border-top-right-radius: 4px; - -moz-border-radius-topright: 4px; - border-top-right-radius: 4px; -} -.openerp .oe-listview table.oe-listview-content tfoot tr:last-child th:first-child, -.openerp .oe-listview table.oe-listview-content tfoot tr:last-child td:first-child, -.openerp .oe-listview table.oe-listview-content tbody:last-child tr:last-child th:first-child { - -webkit-border-bottom-left-radius: 4px; - -moz-border-radius-bottomleft: 4px; - border-bottom-left-radius: 4px; -} -.openerp .oe-listview table.oe-listview-content tfoot tr:last-child th:last-child, -.openerp .oe-listview table.oe-listview-content tfoot tr:last-child td:last-child, -.openerp .oe-listview table.oe-listview-content tbody:last-child tr:last-child td:last-child { - -webkit-border-bottom-right-radius: 4px; - -moz-border-radius-bottomright: 4px; - border-bottom-right-radius: 4px; -} - -/* Notebook */ -.openerp .oe_form_notebook { - padding: 0; - background: none; - border-width: 0; -} -.openerp .oe_form_notebook .ui-tabs-panel { - padding: 4px; - -moz-border-radius-topright: 4px; - -webkit-border-top-right-radius: 4px; - border-top-right-radius: 4px; -} -.openerp .oe_form_notebook ul.ui-tabs-nav { - padding-left: 0; - background: transparent; - border-width: 0; - border-radius: 0; - -moz-border-radius: 0; - -webkit-border-radius: 0; - line-height: 0.8em; - font-size: 95%; - color: #555; -} -.openerp .oe_form_notebook ul.ui-tabs-nav li { - font-weight: bold; -} -.openerp .oe_form_notebook .ui-tabs-panel { - background: #f9f9f9; - border-width: 1px; -} -.openerp .oe_form_notebook .ui-tabs-selected { - background: #f9f9f9; -} -/* Unedit Form */ -.openerp .field_char, -.openerp .field_date, -.openerp .field_float, -.openerp .field_selection, -.openerp a.oe_form_uri { - vertical-align: middle; - padding-top: 3px; - font-size: 90%; - color: #222; -} -.openerp a.oe_form_uri { - color: #9A0404; - line-height: 12px; -} - - - -/* Form */ -.openerp .oe_form_button_save_dirty { - display: none; -} -.openerp .oe_form_dirty > .oe_form_header > .oe_form_buttons > .oe_form_button_save { - color: white; - background: #dc5f59; - background: -moz-linear-gradient(#dc5f59, #b33630); - background: -webkit-gradient(linear, left top, left bottom, from(#dc5f59), to(#b33630)); - background: -webkit-linear-gradient(#dc5f59, #b33630); - -moz-box-shadow: none; - -webkit-box-shadow: none; - -box-shadow: none; - font-weight: bold; -} -.openerp .oe_form_frame_cell input[type="checkbox"] { - margin-top: 3px; - vertical-align: middle; -} -.openerp .oe_form_frame_cell .input[type="text"] { - padding-bottom: 1px; -} - -.openerp table.oe_frame td { - color: #4c4c4c; -} -.openerp td.oe_form_frame_cell { - padding: 2px; - position: relative; -} -.openerp .oe_frame.oe_forms { - clear: both; -} -.openerp table.oe_frame { - color: #4c4c4c; -} -.openerp fieldset.oe_group_box { - border: 1px solid #AAAAAA; - moz-border-radius: 4px; - -webkit-border-radius: 4px; - border-radius: 4px; - background: #F9F9F9; - padding: 4px; -} -.openerp fieldset.oe_group_box legend { - font-weight: bold; -} -.openerp td.oe_form_frame_cell { - padding: 2px; - position: relative; -} -.openerp td.oe_form_field_translatable, -.openerp td.oe_form_field_many2one, -.openerp td.oe_form_field_date, -.openerp td.oe_form_field_datetime { - white-space: nowrap; -} -.openerp td.oe_form_field_boolean { - padding-top: 4px; -} -.openerp td.oe_form_frame_cell.oe_form_group { - padding: 0; -} -.openerp .required.error { - border: 1px solid #900; -} -.openerp .oe_form_buttons, .openerp .oe_list_buttons { - float: left; -} -.openerp .oe_form_pager, .openerp .oe_list_pager { - float: right; - font-size: 80%; - color: gray; - font-weight: bold; -} - -.openerp .oe_form_pager { - margin-right: 3px; -} - - -.openerp label.oe_label_help, .openerp label.oe_label, -.openerp .oe_form_paragraph, -.openerp .oe_form_field_statusbar, -.openerp .oe_forms input[type="text"], -.openerp .oe_forms input[type="password"], -.openerp .oe_forms input[type="file"], -.openerp .oe_forms select, -.openerp .oe_forms .oe_button, -.openerp .oe_forms textarea { - font-size: 85%; -} - -.openerp label.oe_label_help, .openerp label.oe_label { - display: block; - color: #4c4c4c; - font-weight: normal; -} -.openerp label.oe_label_help { - cursor: help; -} -.openerp .oe_form_frame_cell .oe_label, .openerp .oe_form_frame_cell .oe_label_help { - font-weight: normal; -} -.openerp #tiptip_content { - font-size: 12px; -} -.openerp .oe_tooltip_string { - color: #FD5; - font-weight: bold; - font-size: 13px; -} -.openerp .oe_tooltip_help { - white-space: pre-wrap; -} -.openerp .oe_tooltip_technical { - padding: 0 0 4px 0; - margin: 5px 0 0 15px; - list-style: circle; -} -.openerp .oe_tooltip_technical_title { - font-weight: bold; -} - -.openerp .oe_forms label.oe_label, .openerp .oe_forms label.oe_label_help { - margin: 3px 0 0 3px; - white-space: nowrap; -} -.openerp .oe_forms .searchview_group_content label.oe_label, .openerp .searchview_group_content .oe_forms label.oe_label_help { /* making a distinction between labels in search view and other labels */ - margin: 3px 0 0 3px; -} - -.openerp label.oe_label_help span { - font-size: 80%; - color: darkgreen; - vertical-align:top; - position: relative; - top: -4px; - padding: 0 2px; -} -.openerp .oe_align_left { - text-align: left; -} -.openerp .oe_align_right { - text-align: right; -} -.openerp .oe_align_center { - text-align: center; -} -.openerp .oe_forms .oe_form_paragraph { - margin: 3px 0 0 0; - white-space: normal; -} - -.openerp .oe_forms .oe_form_paragraph.oe_multilines { - white-space: pre; -} - -.openerp .oe_form_field_one2many .oe-actions h3.oe_view_title, -.openerp .oe_form_field_one2many_list .oe-actions h3.oe_view_title{ - display: inline; - margin: 0 0.5em 0 0; -} - -.openerp .oe_forms .oe-listview th.oe-sortable .ui-icon, -.openerp .oe_forms .oe-listview th.oe-sortable .ui-icon { - height: 100%; - margin-top: -9px; -} - -.openerp table.oe_frame .oe-listview-content td { - color: inherit; -} - -/* Uneditable Form View */ -.openerp .oe_form_readonly { - -} -.openerp .oe_form_readonly .oe_form_frame_cell .field_text, -.openerp .oe_form_readonly .field_char, -.openerp .oe_form_readonly .field_int, -.openerp .oe_form_readonly .field_float, -.openerp .oe_form_readonly .field_email, -.openerp .oe_form_readonly .field_date, -.openerp .oe_form_readonly .field_selection, -.openerp .oe_forms_readonly .oe_form_field_many2one { - padding: 3px 2px 2px 2px; - background-color: white; - height: 17px; -} -.openerp .oe_form_readonly .oe_form_frame_cell .field_text { - height: auto; -} -.openerp .oe_form_readonly .field_datetime { - padding: 1px 2px 2px 2px; - background-color: white; - height:19px; -} -.openerp .oe_form_readonly .oe_form_field_many2one div { - background-color:white; - height:18px; - margin-bottom:1px; - padding: 0px 2px 5px 2px; -} - -.openerp .oe_form_readonly .oe_form_field_email div { - background-color: white; - padding: 1px 2px 3px 2px; -} - - -.openerp .oe_form_readonly .oe_form_field_text div.field_text, -.openerp .oe_form_readonly .oe_form_field_text_html div.field_text_html { - white-space: pre-wrap; -} -.openerp .oe_form_readonly .oe_form_frame_cell .field_text { - min-height:100px; -} -/* Inputs */ -.openerp .oe_forms input[type="text"], -.openerp .oe_forms input[type="password"], -.openerp .oe_forms input[type="file"], -.openerp .oe_forms select, -.openerp .oe_forms textarea { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; - padding: 0 2px; - margin: 0 2px; - border: 1px solid #999; - -moz-border-radius: 3px; - -webkit-border-radius: 3px; - border-radius: 3px; - background: white; - min-width: 90px; - color: #1f1f1f; -} - -.openerp .oe_forms input.field_many2one, -.openerp .oe_forms input.field_binary, -.openerp .oe_forms input.field_binary, -.openerp .oe_forms input.field_email, -.openerp .oe_forms input.field_url { - border-right: none; - -webkit-border-top-right-radius: 0px; - -webkit-border-bottom-right-radius: 0px; - -moz-border-radius-topright: 0px; - -moz-border-radius-bottomright: 0px; - border-top-right-radius: 0px; - border-bottom-right-radius: 0px; -} -.openerp .oe_button.oe_field_button { - -webkit-border-top-left-radius: 0px; - -webkit-border-bottom-left-radius: 0px; - -moz-border-radius-topleft: 0px; - -moz-border-radius-bottomleft: 0px; - border-top-left-radius: 0px; - border-bottom-left-radius: 0px; - margin-right:-1px; - height: 22px; -} - -.openerp .oe_form_field_email button img, -.openerp .oe_form_field_url button img { - vertical-align: top; -} -/* vertically recentering filter management select tag */ -.openerp select.oe_search-view-filters-management { - margin-top:2px; -} - -.openerp .oe_forms select{ - padding-top: 2px; -} -.openerp .oe_forms input[readonly], -.openerp .oe_forms select[readonly], -.openerp .oe_forms textarea[readonly], -.openerp .oe_forms input[disabled], -.openerp .oe_forms select[disabled], -.openerp .oe_forms textarea[disabled]{ - background: #E5E5E5 !important; - color: #666; -} -.openerp .oe_forms textarea { - resize:vertical; -} -.openerp .oe_forms input[type="text"], -.openerp .oe_forms input[type="password"], -.openerp .oe_forms input[type="file"], -.openerp .oe_forms select, -.openerp .oe_forms .oe_button { - height: 22px; -} - -.openerp .oe_forms input.field_datetime { - min-width: 11em; -} -.openerp .oe_forms .oe_form_button .oe_button { - color: #4c4c4c; - white-space: nowrap; - min-width: 100%; - width: 100%; -} -@-moz-document url-prefix() { - /* Strange firefox behaviour on width: 100% + white-space: nowrap */ - .openerp .oe_forms .oe_form_button .oe_button { - width: auto; - } -} -/* IE Hack - for IE < 9 - * Avoids buttons overflow - * */ -.openerp .oe_forms .oe_form_button .oe_button { - min-width: auto\9; -} -.openerp .oe_forms .button { - height: 22px; -} -.openerp .oe_forms .oe_button span { - position: relative; - vertical-align: top; -} -.openerp .oe_input_icon { - cursor: pointer; - margin: 3px 0 0 -21px; - vertical-align: top; -} -.openerp .oe_datepicker_container { - display: none; -} -.openerp .oe_datepicker_root { - display: inline-block; -} -.openerp .oe_form_frame_cell .oe_datepicker_root { - width: 100%; -} -.openerp .oe_input_icon_disabled { - position: absolute; - cursor: default; - opacity: 0.5; - filter:alpha(opacity=50); - right: 5px; - top: 3px; -} -.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 - */ -.openerp .oe-binary-file-set { - overflow: hidden; - position: relative; -} -.openerp input.oe-binary-file { - z-index: 0; - line-height: 0; - font-size: 50px; - position: absolute; - /* Should be adjusted for all browsers */ - top: -2px; - right: 0; - opacity: 0; - filter: alpha(opacity = 0); - -ms-filter: "alpha(opacity=0)"; - margin: 0; - padding:0; -} - -/* Widgets */ -.openerp .separator { - border: 0 solid #666; -} -.openerp .separator.horizontal { - font-weight: bold; - border-bottom-width: 1px; - margin: 3px 4px 3px 1px; - height: 17px; - font-size: 95%; -} -.openerp .separator.horizontal:empty { - height: 5px; -} -.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; -} -.openerp td.invalid input, .openerp td.invalid select, .openerp td.invalid textarea { - background-color: #F66 !important; - border: 1px solid #D00 !important; -} -.openerp div.oe-progressbar span { - position: absolute; - margin-left: 10px; - margin-top: 5px; - font-weight: bold; -} - -/* jQuery UI override */ -.openerp .ui-widget { - font-size: 1em; -} -.openerp .oe_form_field_progressbar .ui-progressbar { - height: 22px; - font-size: 10px; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; - border: 1px solid #999; - -moz-border-radius: 3px; - -webkit-border-radius: 3px; - border-radius: 3px; - background: white; - min-width: 90px; -} -.openerp tbody.ui-widget-content { - margin-bottom: 10px; - border-spacing: 4px; -} -.openerp .ui-widget-header { - background: white none; -} -/* progress bars */ -.openerp .ui-progressbar .ui-widget-header { - background: #cccccc url(/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; -} - -/* Sidebar */ -.openerp .view-manager-main-table { - margin: 0; - width:100%; - border-collapse:collapse; - height:100%; -} - -.openerp .view-manager-main-table tbody { - vertical-align: top; -} - -.openerp .oe-view-manager-header { + border-right: 1px solid #afafb6; overflow: auto; - background: url("/web/static/src/img/sep-a.gif") 0 100% repeat-x; - margin:6px 0 6px 2px; -} -.openerp .oe_form_frame_cell .oe-view-manager-header { /* Trick: remove the background when element is in a formular */ - background: none; -} - -.openerp .oe-view-manager-header h2 { + text-shadow: 0 1px 1px white; } + .openerp2 .oe_leftbar .oe_footer { + position: absolute; + width: 205px; + text-align: center; + bottom: 8px; } + .openerp2 a.oe_logo { + display: block; + text-align: center; + height: 70px; + line-height: 70px; } + .openerp2 a.oe_logo img { + height: 40px; + width: 157px; + margin: 14px 0; } + .openerp2 .oe_footer { + position: absolute; + width: 205px; + text-align: center; + bottom: 8px; } + .openerp2 .oe_footer a { + font-weight: 800; + font-family: serif; + font-size: 16px; + color: black; } + .openerp2 .oe_footer a span { + color: #c81010; + font-style: italic; } + .openerp2 .oe_menu { float: left; -} - -.openerp .oe_view_manager_menu_tips blockquote { - display: none; - font-size: 85%; - margin: 0; - background: #fff; - border-bottom: 1px solid #CECBCB; - padding: 1px 10px; - color: #4C4C4C; -} -.openerp .oe_view_manager_menu_tips blockquote p { - margin: 0; - padding: 6px 1px 4px; -} - -.openerp .oe_view_manager_menu_tips blockquote div { - text-align: right; - margin-right:10px; -} - -.openerp .oe_view_manager_menu_tips blockquote div button { - border: none; - background: none; - padding: 0 4px; - margin: 0; - display: inline; - text-decoration: underline; - color: inherit; -} -.openerp .oe-view-manager-logs { - clear: both; - background: #fff; - margin: 0.25em 0; - font-size: 85%; - color: #4C4C4C; - position: relative; - overflow: hidden; -} -.openerp .oe-view-manager-logs ul { - margin: 0; - padding: 0 10px; - list-style: none; -} -.openerp .oe-view-manager-logs li:before { - content: '\2192 '; -} -.openerp .oe-view-manager-logs a { - text-decoration: none; - color: inherit; -} -/* only display first three log items of a folded logs list */ -.openerp .oe-view-manager-logs.oe-folded li:nth-child(n+4) { - display: none; -} -/* display link to more logs if there are more logs to view and the logview is - currently folded */ -.openerp .oe-view-manager-logs a.oe-more-logs { - display: none; -} -.openerp .oe-view-manager-logs.oe-folded.oe-has-more a.oe-more-logs { - display: block; -} -.openerp .oe-view-manager-logs a.oe-remove-everything { - position: absolute; - top: 0; - right: 0; - cursor: pointer; -} - -.openerp .view-manager-main-sidebar { - width: 180px; padding: 0; - margin: 0; -} - -.openerp .sidebar-main-div { - height: 100%; - border-left: 1px solid #D2CFCF; -} - -.openerp .sidebar-content { - padding: 0; - margin: 0; - width: 180px; - height: 100%; - font-size: 0.9em; -} - -.openerp .closed-sidebar .sidebar-content { - width: 22px; -} - -.openerp .closed-sidebar .sidebar-content { - display: none; -} - -.openerp .sidebar-main-div a { - color: #555; - text-decoration: none; -} - -.openerp .sidebar-main-div a:hover { - color: black; -} - -.openerp .oe-sidebar-attachments-toolbar { - margin: 4px 0 0 4px; -} -.openerp .oe-sidebar-attachments-items { - clear: both; - padding-top: 5px !important; -} -.openerp .oe-sidebar-attachments-items li { - position: relative; - padding: 0 0 3px 10px !important; -} -.openerp .oe-sidebar-attachments-items li:hover { - background: #ddd; -} -.openerp .oe-sidebar-attachments-link { - display: block; - margin-right: 15px; - overflow: hidden; -} -.openerp .oe-sidebar-attachment-delete { - position: absolute; - right: 2px; - top: 1px; - overflow: hidden; - width: 15px; - height: 15px; - padding: 1px; - border-radius: 7px; - -moz-border-radius: 7px; - -webkit-border-radius: 7px; -} -.openerp .oe-sidebar-attachment-delete:hover { - background-color: white; -} - -.openerp .view-manager-main-sidebar h2 { - margin:0; - font-size: 1.15em; - color: #8E8E8E; - text-shadow: white 0 1px 0; - padding-left: 10px; - padding-right: 21px; - height: 21px; - - background: #ffffff; /* Old browsers */ - background: -moz-linear-gradient(top, #ffffff 0%, #ebe9e9 100%); /* FF3.6+ */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#ebe9e9)); /* Chrome,Safari4+ */ - background: -webkit-linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* Chrome10+,Safari5.1+ */ - background: -o-linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* Opera11.10+ */ - background: -ms-linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* IE10+ */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#EBE9E9',GradientType=0 ); /* IE6-9 */ - background: linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* W3C */ - - border: 1px solid #D2CFCF; - border-right-width: 0; - border-left-width: 0; -} -.openerp .view-manager-main-sidebar h2 { - border-top-width: 0; -} - -.openerp .view-manager-main-sidebar ul { - list-style-type: none; - margin: 0; - padding: 0; - display: block; -} - -.openerp .view-manager-main-sidebar li { - display: block; - padding: 3px 3px 3px 10px; -} - -.openerp .toggle-sidebar { - cursor: pointer; - border: 1px solid #D2CFCF; - border-top-width: 0; - display: block; - background: url(/web/static/src/img/toggle-a-bg.png); - width: 21px; - height: 21px; - z-index: 10; -} -.openerp .open-sidebar .toggle-sidebar { - margin-left: 158px; - background-position: 21px 0; - position: absolute; -} -.openerp .closed-sidebar .toggle-sidebar { - border-left: none; -} -.openerp li.oe_sidebar_print { - padding-left: 20px; - background: 1px 3px url(/web/static/src/img/icons/gtk-print.png) no-repeat; -} - -.openerp .oe_sidebar_print ul { - padding-left:8px; -} - -.openerp.kitten-mode-activated .main_table { - background: url(http://placekitten.com/g/1500/800) repeat; -} -.openerp.kitten-mode-activated.clark-gable .main_table { - background: url(http://amigrave.com/ClarkGable.jpg); - background-size: 100%; -} - -.openerp.kitten-mode-activated .header { - background: url(http://placekitten.com/g/211/65) repeat; -} - -.openerp.kitten-mode-activated .secondary_menu { - background: url(http://placekitten.com/g/212/100) repeat; -} - -.openerp.kitten-mode-activated .menu { - background: #828282; - background: -moz-linear-gradient(top, #828282 0%, #4D4D4D 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#828282), color-stop(100%,#4D4D4D)); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#828282', endColorstr='#4D4D4D',GradientType=0 ); -} -.openerp.kitten-mode-activated .menu a { - background: none; -} -.openerp.kitten-mode-activated .menu span { - background: none; -} -.openerp.kitten-mode-activated .sidebar-content li a, -.openerp.kitten-mode-activated .oe-application .view-manager-main-content h2.oe_view_title, -.openerp.kitten-mode-activated .oe-application .view-manager-main-content a.searchview_group_string, -.openerp.kitten-mode-activated .oe-application .view-manager-main-content label { - color: white; -} -.openerp.kitten-mode-activated .menu, -.openerp.kitten-mode-activated .header_corner, -.openerp.kitten-mode-activated .header_title, -.openerp.kitten-mode-activated .secondary_menu div, -.openerp.kitten-mode-activated .oe-application, -.openerp.kitten-mode-activated .oe_footer, -.openerp.kitten-mode-activated .loading, -.openerp.kitten-mode-activated .ui-dialog { - opacity:0.8; - filter:alpha(opacity=80); -} -.openerp.kitten-mode-activated .header .company_logo { - background: url(http://placekitten.com/g/180/46); -} -.openerp.kitten-mode-activated .loading { - background: #828282; - border-color: #828282; -} - -.openerp .oe-m2o-drop-down-button { - margin-left: -24px; -} -.openerp .oe-m2o-drop-down-button img { - margin-bottom: -4px; - cursor: pointer; -} -.openerp .oe-m2o input { - border-right: none; - margin-right: 0px !important; - padding-bottom: 2px !important; -} -.openerp .oe-m2o-disabled-cm { - color: grey; -} -.openerp ul[role="listbox"] li a { - font-size:80%; -} -.parent_top { - vertical-align: text-top; -} - -.openerp .oe-dialog-warning p { - padding-left: 1em; - font-size: 1.2em; + margin: 0; } + .openerp2 .oe_menu li { + list-style-type: none; + float: left; } + .openerp2 .oe_menu a { + display: block; + padding: 5px 10px 7px; + line-height: 20px; + height: 20px; + color: #eeeeee; + vertical-align: top; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); } + .openerp2 .oe_menu a:hover { + background: #303030; + color: white; + -moz-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset; + -webkit-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset; + -box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset; } + .openerp2 .oe_menu .oe_active { + background: #303030; + font-weight: bold; + color: white; + -moz-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset; + -webkit-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset; + -box-shadow: 0 1px 2px rgba(255, 255, 255, 0.3) inset; } + .openerp2 .oe_secondary_menu_section { font-weight: bold; -} - -.openerp .dhx_mini_calendar { - -moz-box-shadow: none; - -khtml-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} -.openerp .oe-treeview-table { + margin-left: 8px; + color: #8a89ba; } + .openerp2 .oe_secondary_submenu { + padding: 2px 0 8px 0; + margin: 0; width: 100%; - background-color : #FFFFFF; - border-spacing: 0; - -} -.openerp .oe-treeview-table tr:hover{ - color: blue; - background-color : #D8D8D8; -} -.treeview-tr, .treeview-td { - cursor: pointer; - vertical-align: top; - text-align: left; - border-bottom: 1px solid #CFCCCC; -} -.openerp .oe-treeview-table .oe-number { - text-align: right !important; -} -.treeview-tr span, .treeview-td span { - font-size: 90%; - font-weight: normal; - white-space: nowrap; - display: block; - } -.treeview-tr.oe-treeview-first { - background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat; -} -.oe-open .treeview-tr.oe-treeview-first { - background-image: url(/web/static/src/img/collapse.gif); -} -.treeview-tr.oe-treeview-first span, -.treeview-td.oe-treeview-first span { - margin-left: 16px; -} - -.treeview-header { - vertical-align: top; - background-color : #D8D8D8; - white-space: nowrap; - text-align: left; - padding: 4px 5px; -} -/* Shortcuts*/ -.oe-shortcut-toggle { - height: 20px; - margin-top: 3px; - padding: 0; - width: 24px; - cursor: pointer; - display: block; - background: url(/web/static/src/img/add-shortcut.png) no-repeat center center; - float: left; -} -.oe-shortcut-remove{ - background: url(/web/static/src/img/remove-shortcut.png) no-repeat center center; -} -.oe-shortcuts { - position: absolute; - margin: 0; - padding: 6px 15px; - top: 37px; - left: 197px; - right: 0; - height: 17px; - line-height: 1.2; -} -.oe-shortcuts ul { - display: block; - overflow: hidden; - list-style: none; - white-space: nowrap; - padding: 0; - margin: 0; -} -.oe-shortcuts li { - cursor: pointer; - display: -moz-inline-stack; - display: inline-block; - display: inline; /*IE7 */ - color: #fff; - text-align: center; - border-left: 1px solid #909090; - padding: 0 4px; - font-size: 80%; - font-weight: normal; - vertical-align: top; -} - -.oe-shortcuts li:hover { - background-color: #666; -} -.oe-shortcuts li:first-child { - border-left: none; - padding-left: 0; -} - -ul.oe-arrow-list { - padding-left: 1.1em; - margin: 0; - white-space: nowrap; -} -ul.oe-arrow-list li { - display: inline-block; - margin-left: -1em; -} -ul.oe-arrow-list li span { - vertical-align: top; - display: inline-block; - border: 1em solid #DEDEDE; - line-height:0em; -} -ul.oe-arrow-list .oe-arrow-list-before { - border-left-color: rgba(0,0,0,0); - border-right-width:0; -} -ul.oe-arrow-list .oe-arrow-list-after { - border-color: rgba(0,0,0,0); - border-left-color: #DEDEDE; - border-right-width:0; -} -ul.oe-arrow-list li.oe-arrow-list-selected span { - border-color: #B5B9FF; -} -ul.oe-arrow-list li.oe-arrow-list-selected .oe-arrow-list-before { - border-left-color: rgba(0,0,0,0); -} -ul.oe-arrow-list li.oe-arrow-list-selected .oe-arrow-list-after { - border-color: rgba(0,0,0,0); - border-left-color: #B5B9FF; -} -.openerp ul.oe-arrow-list li:first-child span:first-child{ - -webkit-border-top-left-radius: 3px; - -moz-border-radius-topleft: 3px; - border-top-left-radius: 3px; - -webkit-border-bottom-left-radius: 3px; - -moz-border-radius-bottomleft: 3px; - border-bottom-left-radius: 3px; -} -.openerp ul.oe-arrow-list li:last-child span:last-child{ - -webkit-border-top-right-radius: 3px; - -moz-border-radius-topright: 3px; - border-top-right-radius: 3px; - -webkit-border-bottom-right-radius: 3px; - -moz-border-radius-bottomright: 3px; - border-bottom-right-radius: 3px; -} -.openerp .oe_view_editor { - width:100%; - border-collapse : collapse; - margin-left: -12px; - - width: 100%; - background-color : white; - border-spacing: 0; -} -.openerp .oe_view_editor td{ - text-align: center; - white-space: nowrap; - border: 1px solid #D8D8D8; - - cursor: pointer; - font-size: 90%; -} -.openerp .oe_view_editor_field td{ - border: 0px !important; -} - -.openerp .oe_view_editor tr:hover { - background-color: #ecebf2; -} - - -/* Dialog traceback cases */ -.openerp .oe_error_detail{ - display: block; -} -.openerp .oe_error_send{ - display:block; -} -.openerp .oe_fielddiv{ - display:inline-block; - width:100%; -} -.openerp .oe_fielddiv input[type=text],textarea{ - width:100%; -} -/* for Alignment center */ -.openerp .oe_centeralign{ - text-align:center; -} - -.openerp .oe_applications_tiles { - color: #4C4C4C; - text-shadow: #EEE 0 1px 0; - margin: 0 20px; -} - -.openerp .oe_vm_switch { - margin:2px 0 0 0; -} - -.openerp .oe_vm_switch_form, -.openerp .oe_vm_switch_page, -.openerp .oe_vm_switch_tree, -.openerp .oe_vm_switch_list, -.openerp .oe_vm_switch_graph, -.openerp .oe_vm_switch_gantt, -.openerp .oe_vm_switch_calendar, -.openerp .oe_vm_switch_kanban, -.openerp .oe_vm_switch_diagram { - background: url("/web/static/src/img/views-icons-a.png") repeat-x scroll left top transparent; - overflow: hidden; - width: 22px; - height: 21px; - border: none; - background-position: 0px 0px; -} - -.openerp .oe_vm_switch_form span, -.openerp .oe_vm_switch_page span, -.openerp .oe_vm_switch_tree span, -.openerp .oe_vm_switch_list span, -.openerp .oe_vm_switch_graph span, -.openerp .oe_vm_switch_gantt span, -.openerp .oe_vm_switch_calendar span, -.openerp .oe_vm_switch_kanban span, -.openerp .oe_vm_switch_diagram span { - display: none; -} - -.openerp .oe_vm_switch_list { - background-position: 0px 0px; -} -.openerp .oe_vm_switch_list:active, -.openerp .oe_vm_switch_list:hover, -.openerp .oe_vm_switch_list:focus, -.openerp .oe_vm_switch_list[disabled="disabled"] { - background-position: 0px -21px; -} - -.openerp .oe_vm_switch_tree { - background-position: 0px 0px; -} -.openerp .oe_vm_switch_tree:active, -.openerp .oe_vm_switch_tree:hover, -.openerp .oe_vm_switch_tree:focus, -.openerp .oe_vm_switch_tree[disabled="disabled"] { - background-position: 0px -21px; -} - -.openerp .oe_vm_switch_form { - background-position: -22px 0px; -} -.openerp .oe_vm_switch_form:active, -.openerp .oe_vm_switch_form:hover, -.openerp .oe_vm_switch_form:focus, -.openerp .oe_vm_switch_form[disabled="disabled"] { - background-position: -22px -21px; -} - -.openerp .oe_vm_switch_page { - background-position: -22px 0px; -} -.openerp .oe_vm_switch_page:active, -.openerp .oe_vm_switch_page:hover, -.openerp .oe_vm_switch_page:focus, -.openerp .oe_vm_switch_page[disabled="disabled"] { - background-position: -22px -21px; -} -.openerp .oe_vm_switch_graph { - background-position: -44px 0px; -} -.openerp .oe_vm_switch_graph:active, -.openerp .oe_vm_switch_graph:hover, -.openerp .oe_vm_switch_graph:focus, -.openerp .oe_vm_switch_graph[disabled="disabled"] { - background-position: -44px -21px; -} - -.openerp .oe_vm_switch_gantt { - background-position: -66px 0px; -} -.openerp .oe_vm_switch_gantt:active, -.openerp .oe_vm_switch_gantt:hover, -.openerp .oe_vm_switch_gantt:focus, -.openerp .oe_vm_switch_gantt[disabled="disabled"] { - background-position: -66px -21px; -} - -.openerp .oe_vm_switch_calendar { - background-position: -88px 0px; -} -.openerp .oe_vm_switch_calendar:active, -.openerp .oe_vm_switch_calendar:hover, -.openerp .oe_vm_switch_calendar:focus, -.openerp .oe_vm_switch_calendar[disabled="disabled"] { - background-position: -88px -21px; -} -.openerp .oe_vm_switch_kanban { - background-position: -110px 0px; -} -.openerp .oe_vm_switch_kanban:active, -.openerp .oe_vm_switch_kanban:hover, -.openerp .oe_vm_switch_kanban:focus, -.openerp .oe_vm_switch_kanban[disabled="disabled"] { - background-position: -110px -21px; -} - -.openerp .oe_vm_switch_diagram { - background-position: 0px 0px; -} -.openerp .oe_vm_switch_diagram:active, -.openerp .oe_vm_switch_diagram:hover, -.openerp .oe_vm_switch_diagram:focus, -.openerp .oe_vm_switch_diagram[disabled="disabled"] { - background-position: 0px -21px; -} - -/* Buttons */ -.openerp .oe_button:link, -.openerp .oe_button:visited, -.openerp .oe_button { - display: inline-block; - border: 1px solid #ababab; - color: #404040; - font-size: 12px; - padding: 3px 10px; - text-align: center; - -o-background-size: 100% 100%; - -moz-background-size: 100% 100%; - -webkit-background-size: auto auto !important; - background-size: 100% 100%; - background: #d8d8d8 none; - background: none, -webkit-gradient(linear, left top, left bottom, from(#efefef), to(#d8d8d8)); - background: none, -webkit-linear-gradient(#efefef, #d8d8d8); - background: none, -moz-linear-gradient(#efefef, #d8d8d8); - background: none, -o-linear-gradient(top, #efefef, #d8d8d8); - background: none, -khtml-gradient(linear, left top, left bottom, from(#efefef), to(#d8d8d8)); - background: -ms-linear-gradient(top, #efefef, #d8d8d8); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#efefef', endColorstr='#d8d8d8',GradientType=0 ); - -moz-border-radius: 3px; - -webkit-border-radius: 3px; - -o-border-radius: 3px; - -ms-border-radius: 3px; - border-radius: 3px; - -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset; - -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset; - -o-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset; - text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5); - -webkit-font-smoothing: antialiased; - outline: none; -} - -.openerp .oe_button:hover { - -o-background-size: 100% 100%; - -moz-background-size: 100% 100%; - -webkit-background-size: auto auto !important; - background-size: 100% 100%; - background: #e3e3e3 none; - background: none, -webkit-gradient(linear, left top, left bottom, from(#f6f6f6), to(#e3e3e3)); - background: none, -webkit-linear-gradient(#f6f6f6, #e3e3e3); - background: none, -moz-linear-gradient(#f6f6f6, #e3e3e3); - background: none, -o-linear-gradient(top, #f6f6f6, #e3e3e3); - background: none, -khtml-gradient(linear, left top, left bottom, from(#f6f6f6), to(#e3e3e3)); - background: -ms-linear-gradient(top, #f6f6f6, #e3e3e3); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f6f6f6', endColorstr='#e3e3e3',GradientType=0 ); - cursor: pointer; -} - -.openerp .oe_button:focus { - border: 1px solid #80bfff; - -o-background-size: 100% 100%; - -moz-background-size: 100% 100%; - -webkit-background-size: auto auto !important; - background-size: 100% 100%; - background: #e3e3e3, none; - background: none, -webkit-gradient(linear, left top, left bottom, from(#f6f6f6), to(#e3e3e3)); - background: none, -webkit-linear-gradient(#f6f6f6, #e3e3e3); - background: none, -moz-linear-gradient(#f6f6f6, #e3e3e3); - background: none, -o-linear-gradient(top, #f6f6f6, #e3e3e3); - background: none, -khtml-gradient(linear, left top, left bottom, from(#f6f6f6), to(#e3e3e3)); - background: -ms-linear-gradient(top, #f6f6f6, #e3e3e3); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f6f6f6', endColorstr='#e3e3e3',GradientType=0 ); - -moz-box-shadow: 0 0 3px #80bfff, 0 1px 1px rgba(255, 255, 255, 0.8) inset; - -webkit-box-shadow: 0 0 3px #80bfff, 0 1px 1px rgba(255, 255, 255, 0.8) inset; - -o-box-shadow: 0 0 3px #80bfff, 0 1px 1px rgba(255, 255, 255, 0.8) inset; - box-shadow: 0 0 3px #80bfff, 0 1px 1px rgba(255, 255, 255, 0.8) inset; -} - -.openerp .oe_button:active, -.openerp .oe_button.active { - background: #e3e3e3; - background: -moz-linear-gradient(top, #e3e3e3, #f6f6f6) #1b468f; - background: -webkit-gradient(linear, left top, left bottom, from(#e3e3e3), to(#f6f6f6)) #1b468f; - background: linear-gradient(top, #e3e3e3, #f6f6f6) #1b468f; - background: -ms-linear-gradient(top, #e3e3e3, #f6f6f6); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e3e3e3', endColorstr='#f6f6f6',GradientType=0 ); - -moz-box-shadow: none, 0 0 0 transparent; - -webkit-box-shadow: none, 0 0 0 transparent; - -o-box-shadow: none, 0 0 0 transparent; - box-shadow: none, 0 0 0 transparent; -} - -.openerp .oe_button.disabled, -.openerp .oe_button:disabled { - background: #efefef !important; - border: 1px solid #d1d1d1 !important; - font-size: 12px; - padding: 3px 10px; - -moz-box-shadow: none !important, 0 0 0 transparent; - -webkit-box-shadow: none !important, 0 0 0 transparent; - -o-box-shadow: none !important, 0 0 0 transparent; - box-shadow: none !important, 0 0 0 transparent; - color: #aaaaaa !important; - cursor: default; - text-shadow: 0 1px 1px white !important; -} - -.openerp select.oe_search-view-filters-management { - font-style: oblique; - color: #999999; -} - -.openerp .oe_search-view-filters-management option, -.openerp .oe_search-view-filters-management optgroup { - font-style: normal; - color: black; -} - -/* Debug stuff */ -.openerp .oe_debug_view_log { - font-size: 95%; -} -.openerp .oe_debug_view_log label { - display: block; - width: 49%; - text-align: right; - float: left; - font-weight: bold; - color: #009; -} -.openerp .oe_debug_view_log span { - display: block; - width: 49%; + display: inline-block; } + .openerp2 .oe_secondary_submenu li { + position: relative; + padding: 1px 0 1px 16px; + list-style-type: none; } + .openerp2 .oe_secondary_submenu li a { + display: block; + color: #4c4c4c; + padding: 2px 4px 2px 0; } + .openerp2 .oe_secondary_submenu li .oe_menu_label { + position: absolute; + top: 1px; + right: 1px; + font-size: 10px; + background: #8a89ba; + color: white; + padding: 2px 4px; + margin: 1px 6px 0 0; + border: 1px solid lightGray; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2); + -box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2); } + .openerp2 .oe_secondary_submenu .oe_active { + background: #8a89ba; + border-top: 1px solid lightGray; + border-bottom: 1px solid lightGray; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2); + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2); + -box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2); } + .openerp2 .oe_secondary_submenu .oe_active a { + color: white; } + .openerp2 .oe_secondary_submenu .oe_active .oe_menu_label { + background: #eeeeee; + color: #8a89ba; + text-shadow: 0 1px 1px white; + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); + -box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); } + .openerp2 .oe_secondary_submenu .oe_menu_toggler:before { + width: 0; + height: 0; + display: inline-block; + content: "&darr"; + text-indent: -99999px; + vertical-align: top; + margin-left: -8px; + margin-top: 4px; + margin-right: 4px; + border-top: 4px solid transparent; + border-bottom: 4px solid transparent; + border-left: 4px solid #4c4c4c; + filter: alpha(opacity=50); + opacity: 0.5; } + .openerp2 .oe_secondary_submenu .oe_menu_opened:before { + margin-top: 6px; + margin-left: -12px; + margin-right: 4px; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid #4c4c4c; } + .openerp2 .oe_user_menu { float: right; - color: #333; -} - -/* Internet Explorer Fix */ -a img { - border: none; -} + padding: 0; + margin: 0; } + .openerp2 .oe_user_menu li { + list-style-type: none; + float: left; } + .openerp2 .oe_user_menu .oe_dropdown { + position: relative; } + .openerp2 .oe_user_menu .oe_dropdown_toggle:after { + width: 0; + height: 0; + display: inline-block; + content: "&darr"; + text-indent: -99999px; + vertical-align: top; + margin-top: 8px; + margin-left: 4px; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid white; + filter: alpha(opacity=50); + opacity: 0.5; } + .openerp2 .oe_user_menu .oe_dropdown_options { + float: left; + background: #333333; + background: rgba(37, 37, 37, 0.9); + display: none; + position: absolute; + top: 32px; + right: -1px; + border: 0; + z-index: 900; + margin-left: 0; + margin-right: 0; + padding: 6px 0; + zoom: 1; + border-color: #999999; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 0 1px 1px; + -moz-border-radius: 0 0 6px 6px; + -webkit-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); + -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); + -box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; } + .openerp2 .oe_user_menu .oe_dropdown_options li { + float: none; + display: block; + background-color: none; } + .openerp2 .oe_user_menu .oe_dropdown_options li a { + display: block; + padding: 4px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #eeeeee; } + .openerp2 .oe_user_menu .oe_dropdown_options li a:hover { + background-color: #292929; + background-image: -webkit-gradient(linear, left top, left bottom, from(#292929), to(#191919)); + background-image: -webkit-linear-gradient(top, #292929, #191919); + background-image: -moz-linear-gradient(top, #292929, #191919); + background-image: -ms-linear-gradient(top, #292929, #191919); + background-image: -o-linear-gradient(top, #292929, #191919); + background-image: linear-gradient(to bottom, #292929, #191919); + -moz-box-shadow: none; + -webkit-box-shadow: none; + -box-shadow: none; } diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass new file mode 100644 index 00000000000..56a735c98fd --- /dev/null +++ b/addons/web/static/src/css/base.sass @@ -0,0 +1,330 @@ +// Variables {{{ +$colour4: #8a89ba +//$colour4: #d14836 +// }}} + +// Mixins {{{ +@mixin vertical-gradient($startColor: #555, $endColor: #333) + background-color: $startColor + background-image: -webkit-gradient(linear, left top, left bottom, from($startColor), to($endColor)) /* Saf4+, Chrome */ + background-image: -webkit-linear-gradient(top, $startColor, $endColor) /* Chrome 10+, Saf5.1+, iOS 5+ */ + background-image: -moz-linear-gradient(top, $startColor, $endColor) /* FF3.6 */ + background-image: -ms-linear-gradient(top, $startColor, $endColor) /* IE10 */ + background-image: -o-linear-gradient(top, $startColor, $endColor) /* Opera 11.10+ */ + background-image: linear-gradient(to bottom, $startColor, $endColor) + + +@mixin radial-gradient($gradient) + background-position: center center + background-image: -webkit-radial-gradient(circle, $gradient) + background-image: -moz-radial-gradient($gradient) + background-image: -ms-radial-gradient($gradient) + background-image: radial-gradient($gradient) + +@mixin radius($radius: 5px) + -moz-border-radius: $radius + -webkit-border-radius: $radius + border-radius: $radius + +@mixin box-shadow($bsval: 0px 1px 4px #777) + -moz-box-shadow: $bsval + -webkit-box-shadow: $bsval + -box-shadow: $bsval + +@mixin transition($transval: (border linear 0.2s, box-shadow linear 0.2s)) + -webkit-transition: $transval + -moz-transition: $transval + -ms-transition: $transval + -o-transition: $transval + transition: $transval + +@mixin opacity($opacity: .5) + filter: alpha(opacity=$opacity * 100) + opacity: $opacity + +@mixin background-clip($clip: padding-box) + -webkit-background-clip: $clip + -moz-background-clip: $clip + background-clip: $clip +// }}} + +.openerp2 + // Common styles {{{ + padding: 0 + margin: 0 + font-family: "Lucida Grande", Helvetica, Verdana, Arial, sans-serif + color: #4c4c4c + font-size: 13px + background: white + position: relative + + a + text-decoration: none + // }}} + + // WebClient {{{ + .oe_webclient + position: absolute + top: 0 + bottom: 0 + left: 0 + right: 0 + + .oe_application + position: absolute + top: 32px + bottom: 0 + left: 206px + right: 0 + // }}} + + // Fullscreen mode {{{ + .oe_content_full_screen + .oe_application + top: 0 + left: 0 + .topbar, .leftbar + display: none + // }} + + // Topbar {{{ + .oe_topbar + width: 100% + height: 31px + border-top: solid 1px #d3d3d3 + border-bottom: solid 1px black + @include vertical-gradient(#646060, #262626) + + .oe_systray + float: right + .oe_systray > div + float: left + padding: 0 4px 0 4px + + .oe_topbar_item + li + float: left + a + display: block + padding: 5px 10px 7px + line-height: 20px + height: 20px + color: #eee + vertical-align: top + text-shadow: 0 1px 1px rgba(0,0,0,0.2) + &:hover + background: #303030 + color: white + @include box-shadow(0 1px 2px rgba(255,255,255,0.3) inset) + .oe_active + background: #303030 + font-weight: bold + color: white + @include box-shadow(0 1px 2px rgba(255,255,255,0.3) inset) + + .oe_topbar_avatar + width: 24px + height: 24px + margin: -2px 2px 0 0 + @include radius(4px) + .oe_topbar_avatar + vertical-align: top + // }}} + + // Leftbar {{{ + .oe_leftbar + width: 205px + height: 100% + background: #f0eeee + border-right: 1px solid #afafb6 + overflow: auto + text-shadow: 0 1px 1px white + + .oe_footer + position: absolute + width: 205px + text-align: center + bottom: 8px + a.oe_logo + display: block + text-align: center + height: 70px + line-height: 70px + img + height: 40px + width: 157px + margin: 14px 0 + .oe_footer + position: absolute + width: 205px + text-align: center + bottom: 8px + a + font-weight: 800 + font-family: serif + font-size: 16px + color: black + span + color: #c81010 + font-style: italic + // }}} + + // Menu {{{ + .oe_menu + float: left + padding: 0 + margin: 0 + li + list-style-type: none + float: left + a + display: block + padding: 5px 10px 7px + line-height: 20px + height: 20px + color: #eee + vertical-align: top + text-shadow: 0 1px 1px rgba(0,0,0,0.2) + &:hover + background: #303030 + color: white + @include box-shadow(0 1px 2px rgba(255,255,255,0.3) inset) + .oe_active + background: #303030 + font-weight: bold + color: white + @include box-shadow(0 1px 2px rgba(255,255,255,0.3) inset) + .oe_secondary_menu_section + font-weight: bold + margin-left: 8px + color: $colour4 + .oe_secondary_submenu + padding: 2px 0 8px 0 + margin: 0 + width: 100% + display: inline-block + li + position: relative + padding: 1px 0 1px 16px + list-style-type: none + a + display: block + color: #4c4c4c + padding: 2px 4px 2px 0 + .oe_menu_label + position: absolute + top: 1px + right: 1px + font-size: 10px + background: $colour4 + color: white + padding: 2px 4px + margin: 1px 6px 0 0 + border: 1px solid lightGray + text-shadow: 0 1px 1px rgba(0,0,0,0.2) + @include radius(4px) + @include box-shadow(inset 0 1px 1px rgba(0, 0, 0, 0.2)) + .oe_active + background: $colour4 + border-top: 1px solid lightGray + border-bottom: 1px solid lightGray + text-shadow: 0 1px 1px rgba(0,0,0,0.2) + @include box-shadow(inset 0 1px 1px rgba(0, 0, 0, 0.2)) + a + color: white + .oe_menu_label + background: #eee + color: $colour4 + text-shadow: 0 1px 1px white + @include box-shadow(0 1px 1px rgba(0, 0, 0, 0.2)) + .oe_menu_toggler:before + width: 0 + height: 0 + display: inline-block + content: "&darr" + text-indent: -99999px + vertical-align: top + margin-left: -8px + margin-top: 4px + margin-right: 4px + border-top: 4px solid transparent + border-bottom: 4px solid transparent + border-left: 4px solid #4c4c4c + @include opacity(0.5) + .oe_menu_opened:before + margin-top: 6px + margin-left: -12px + margin-right: 4px + border-left: 4px solid transparent + border-right: 4px solid transparent + border-top: 4px solid #4c4c4c + // }}} + + // UserMenu {{{ + .oe_user_menu + float: right + padding: 0 + margin: 0 + li + list-style-type: none + float: left + .oe_dropdown + position: relative + + .oe_dropdown_toggle:after + width: 0 + height: 0 + display: inline-block + content: "&darr" + text-indent: -99999px + vertical-align: top + margin-top: 8px + margin-left: 4px + border-left: 4px solid transparent + border-right: 4px solid transparent + border-top: 4px solid white + @include opacity(0.5) + + .oe_dropdown_options + float: left + background: #333 + background: rgba(37,37,37,0.9) + display: none + position: absolute + top: 32px + right: -1px + border: 0 + z-index: 900 + margin-left: 0 + margin-right: 0 + padding: 6px 0 + zoom: 1 + border-color: #999 + border-color: rgba(0, 0, 0, 0.2) + border-style: solid + border-width: 0 1px 1px + @include radius(0 0 6px 6px) + @include box-shadow(0 1px 4px rgba(0,0,0,0.3)) + @include background-clip() + li + float: none + display: block + background-color: none + a + display: block + padding: 4px 15px + clear: both + font-weight: normal + line-height: 18px + color: #eee + &:hover + @include vertical-gradient(#292929, #191919) + @include box-shadow(none) + // }}} + +.openerp + // Transitional overrides for old styles {{{ + // }}} + +// au BufWritePost,FileWritePost *.sass :!sass --style expanded --line-numbers > "%:p:r.css" +// vim:tabstop=4:shiftwidth=4:softtabstop=4:fdm=marker: diff --git a/addons/web/static/src/css/base_old.css b/addons/web/static/src/css/base_old.css new file mode 100644 index 00000000000..fe3a6074492 --- /dev/null +++ b/addons/web/static/src/css/base_old.css @@ -0,0 +1,2068 @@ +.openerp { + padding: 0; + margin: 0; + height: 100%; + font-size: 80%; + font-family: Ubuntu, Helvetica, sans-serif; +} + +.openerp, .openerp textarea, .openerp input, .openerp select, .openerp option, +.openerp button, .openerp .ui-widget { + font-family: Ubuntu, Helvetica, sans-serif; + font-size:85%; +} + +.openerp .view-manager-main-content { + width: 100%; + padding: 0 8px 8px 8px; +} + +.openerp .oe_form_frame_cell .view-manager-main-content { + padding: 0; +} + +.oe_box { + border: 1px solid #aaf; + padding: 2px; + margin: 2px; +} + + +#oe_errors pre { + margin: 0; +} + +.openerp .oe-listview .oe-number { + text-align: right !important; +} +.oe-listview-header-columns { + background: #d1d1d1; /* Old browsers */ + background: -moz-linear-gradient(top, #ffffff 0%, #d1d1d1 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#d1d1d1)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #ffffff 0%,#d1d1d1 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #ffffff 0%,#d1d1d1 100%); /* Opera11.10+ */ + background: -ms-linear-gradient(top, #ffffff 0%,#d1d1d1 100%); /* IE10+ */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#d1d1d1',GradientType=0 ); /* IE6-9 */ + background: linear-gradient(top, #ffffff 0%,#d1d1d1 100%); /* W3C */ +} + +.openerp .oe_hide { + display: none !important; +} + +/* STATES */ +.openerp .on_logged, +.openerp .db_options_row { + display: none; +} + +/* Loading */ +.loading { + cursor: wait; +} +.openerp .loading { + display: none; + z-index: 100; + position: fixed; + top: 0; + right: 50%; + padding: 4px 12px; + background: #A61300; + color: white; + text-align: center; + border: 1px solid #900; + border-top: none; + -moz-border-radius-bottomright: 8px; + -moz-border-radius-bottomleft: 8px; + border-bottom-right-radius: 8px; + border-bottom-left-radius: 8px; +} +.openerp .oe_notification { + z-index: 1050; + display: none; +} +.openerp .oe_notification * { + color: white; +} + +/* Login page */ + +.login { + padding: 0; + margin: 0; + font-family: "Lucida Grande", Helvetica, Verdana, Arial; + background: url("/web/static/src/img/pattern.png") repeat; + color: #eee; + font-size: 14px; + height: 100%; +} + +.login ul, ol { + padding: 0; + margin: 0; +} + +.login li { + list-style-type: none; + padding-bottom: 4px; +} + +.login a { + color: #eee; + text-decoration: none; +} + +.login button { + float: right; + display: inline-block; + cursor: pointer; + padding: 6px 16px; + font-size: 13px; + font-family: "Lucida Grande", Helvetica, Verdana, Arial; + border: 1px solid #222222; + color: white; + margin: 0; + background: #600606; + background: -moz-linear-gradient(#b92020, #600606); + background: -webkit-gradient(linear, left top, left bottom, from(#b92020), to(#600606)); + background: -ms-linear-gradient(top, #b92020, #600606); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b92020', endColorstr='#600606',GradientType=0 ); + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(155, 155, 155, 0.4) inset; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(155, 155, 155, 0.4) inset; + -o-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(155, 155, 155, 0.4) inset; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(155, 155, 155, 0.4) inset; +} + +.login input, .login select { + width: 252px; + font-size: 14px; + font-family: "Lucida Grande", Helvetica, Verdana, Arial; + border: 1px solid #999999; + background: whitesmoke; + -moz-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3); + -webkit-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3); + -box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3); + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; +} + +.login input { + margin-bottom: 9px; + padding: 5px 6px; +} + +.login select { + padding: 1px; +} + +.login .dbpane { + position: fixed; + top: 0; + right: 8px; + padding: 5px 10px; + color: #eee; + border: solid 1px #333; + background: #1e1e1e; + background: rgba(30,30,30,0.94); + -moz-border-radius: 0 0 8px 8px; + -webkit-border-radius: 0 0 8px 8px; + border-radius: 0 0 8px 8px; +} + +.login .bottom { + position: absolute; + top: 50%; + left: 0; + right: 0; + bottom: 0; + text-shadow: 0 1px 1px #999999; + background: #600606; + background: -moz-linear-gradient(#b41616, #600606); + background: -webkit-gradient(linear, left top, left bottom, from(#b41616), to(#600606)); + background: -ms-linear-gradient(top, #b41616, #600606); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b41616', endColorstr='#600606',GradientType=0 ); +} + +.login .pane { + position: absolute; + top: 50%; + left: 50%; + margin: -160px -166px; + border: solid 1px #333333; + background: #1e1e1e; + background: rgba(30,30,30,0.94); + padding: 22px 32px; + text-align: left; + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + border-radius: 8px; + -moz-box-shadow: 0 0 18px rgba(0, 0, 0, 0.9); + -webkit-box-shadow: 0 0 18px rgba(0, 0, 0, 0.9); + -box-shadow: 0 0 18px rgba(0, 0, 0, 0.9); +} + +.login .pane h2 { + margin-top: 0; + font-size: 18px; +} + +.login #logo { + position: absolute; + top: -70px; + left: 0; + width: 100%; + margin: 0 auto; + text-align: center; +} + +.login .footer { + position: absolute; + bottom: -40px; + left: 0; + width: 100%; + text-align: center; +} + +.login .footer a { + font-size: 13px; + margin: 0 8px; +} + +.login .footer a:hover { + text-decoration: underline; +} + +.login .openerp { + font-weight: bold; + font-family: serif; + font-size: 16px; +} + +.openerp .login { + text-align: center; +} + +.openerp .login .login_error_message { + display: none; + background-color: #b41616; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.8); + -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.8); + -box-shadow: 0 1px 4px rgba(0, 0, 0, 0.8); + color: #eee; + font-size: 14px; + padding: 14px 18px; + margin-top: 15px; + text-align: center; +} + +.openerp .login.login_invalid .login_error_message { + display: inline-block; +} + + + +/* Database */ +.login .oe-database-manager { + display: none; + height: 100%; + width: 100%; + background-color: white; +} +.login.database_block .bottom, +.login.database_block .login_error_message, +.login.database_block .pane { + display: none; +} +.login.database_block .oe-database-manager { + display: block; +} + +.login .database { + float: left; + width: 202px; + height: 100%; + background: #666666; +} +.login .oe_db_options { + margin-left: 202px; + color: black; + padding-top: 20px; +} + +.login .database ul { + margin-top: 65px; +} + +ul.db_options li { + padding: 5px 0 10px 5px; + background: #949292; /* Old browsers */ + background: -moz-linear-gradient(top, #949292 30%, #6d6b6b 95%, #282828 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(30%,#949292), color-stop(95%,#6d6b6b), color-stop(100%,#282828)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #949292 30%,#6d6b6b 95%,#282828 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #949292 30%,#6d6b6b 95%,#282828 100%); /* Opera11.10+ */ + background: -ms-linear-gradient(top, #949292 30%,#6d6b6b 95%,#282828 100%); /* IE10+ */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#282828',GradientType=0 ); /* IE6-9 */ + background: linear-gradient(top, #949292 30%,#6d6b6b 95%,#282828 100%); /* W3C */ + /* for ie9 */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#949292', endColorstr='#5B5A5A',GradientType=0 ); /* IE6-9 */ + border: none; + /* overriding jquery ui */ + -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; + display: block; + font-weight: bold; + text-transform: uppercase; + margin: 1px; + color: #EEEEEE; + cursor: pointer; + width: 195px; + font-size: 12px; +} + +.db_option_table { + border: 1px solid #5A5858; + padding: 5px; + -moz-border-radius: 10px; +} + +table.db_option_table input.required { + background-color: #D2D2FF !important; +} + +.db_option_table label { + display: block; + text-align: right; +} + +.db_option_table input[type="text"], +.db_option_table input[type="password"], +.db_option_table input[type="file"], +.db_option_table select { + width: 300px; +} + +.option_string { + font-weight: bold; + color: #555; + width: 100%; + text-align: center; + padding: 10px 0; + font-size: large; +} + +label.error { + float: none; + color: red; + padding-left: .5em; + vertical-align: top; +} + +/* Main*/ +.openerp .main_table { + width: 100%; + height: 100%; + background: #f0eeee; +} +.openerp .oe-application { + height: 100%; +} +.openerp .oe-application-container { + width: 100%; + height: 100%; +} + +/* IE Hack - for IE < 9 + * Avoids footer to be placed statically at 100% cutting the middle of the views + * */ +.openerp .oe-application-container { + height: auto\9; + min-height: 100%\9; +} + + +/* Main Application */ +.openerp .oe-main-content { + padding: 0; + height: 100%; +} + +.openerp h2.oe_view_title { + font-size: 110%; + font-weight: normal; + margin: 2px 0; + color: #252424; + text-shadow: white 0 1px 0; +} +.openerp div[id^="notebook"] .oe_view_title { + font-size:85%; + padding-bottom:4px; +} + +/* View Manager */ +.openerp .oe_vm_switch { + float: right; +} +.openerp .oe-view-manager-header .oe_view_title { + font-size:150%; + padding:2px 0 0 0; +} + +/* SearchView */ +.openerp .oe_searchview_field > div { + position: relative; + white-space: nowrap; +} +.openerp .oe_searchview_field .oe_input_icon { + top: auto; + bottom: 3px; +} + +.openerp .filter_label, .openerp .filter_icon { + background: #F0F0F0; + border: 1px solid #999; + background: -moz-linear-gradient(top, #F0F0F0 0%, #C0C0C0 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#F0F0F0), color-stop(100%,#C0C0C0)); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#F0F0F0', endColorstr='#C0C0C0',GradientType=0 ); +} +.openerp .filter_label:hover, .openerp .filter_icon:hover { + background: #F0F0F0; + background: -moz-linear-gradient(top, #F0F0F0 0%, #A1A7CE 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#F0F0F0), color-stop(100%,#A1A7CE)); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#F0F0F0', endColorstr='#A1A7CE',GradientType=0 ); +} +.openerp .filter_label:active, .openerp .filter_icon:active { + background: #aaa; + background: -moz-linear-gradient(top, #999999 0%, #EEEEEE 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#999999), color-stop(100%,#EEEEEE)); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#999999', endColorstr='#EEEEEE',GradientType=0 ); +} +.openerp .filter_label.enabled, .openerp .filter_icon.enabled { + background: #aaa; + filter: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + -o-box-shadow: none; + box-shadow: none; +} +.openerp .filter_icon { + height: 22px; + padding: 1px 2px 0 2px; + margin: 0; + vertical-align: bottom; +} +.openerp .filter_label { + font-weight: bold; + text-transform: uppercase; + text-shadow: #EEE 0 1px 0; + color: #4C4C4C; + white-space: nowrap; + min-height: 40px; + min-width: 75px; + padding: 2px 4px; + margin: 0; +} +.openerp .filter_label_group { + padding-right: 0.4em; + white-space: nowrap; +} + +.openerp .filter_label_group button { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + border-right: none; +} +.openerp .filter_label_group button:first-child { + -webkit-border-top-left-radius: 7px; + -webkit-border-bottom-left-radius: 7px; + -moz-border-radius-topleft: 7px; + -moz-border-radius-bottomleft: 7px; + border-top-left-radius: 7px; + border-bottom-left-radius: 7px; + border-right: none; +} +.openerp .filter_label_group button:last-child { + -webkit-border-top-right-radius: 7px; + -webkit-border-bottom-right-radius: 7px; + -moz-border-radius-topright: 7px; + -moz-border-radius-bottomright: 7px; + border-top-right-radius: 7px; + border-bottom-right-radius: 7px; + border-right: 1px solid #999; +} +.openerp .filter_label_group button.filter_icon img { + padding: 1px 8px 0 8px; +} +.openerp .filter_label_group button.filter_icon:first-child { + border-left: solid 1px #999; + margin-left: -7px; + -webkit-border-top-left-radius: 0; + -webkit-border-bottom-left-radius: 0; + -moz-border-radius-topleft: 0; + -moz-border-radius-bottomleft: 0; + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.openerp .searchview_group_string { + display: block; + color: #7D7979; + font-weight: bold; + padding: 2px 0 2px 10px; + text-decoration: none; +} +.openerp .searchview_group_string:hover { + background-color: #ccc; +} +.openerp .searchview_group.folded .searchview_group_string { + background: url("/web/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("/web/static/src/img/ui/group-expanded.png") no-repeat scroll 0 50%; +} +.openerp .searchview_group.expanded .searchview_group_content { + display: block; + padding-bottom:3px; +} + +.openerp .searchview_group_content .oe_label, .openerp .searchview_group_content .oe_label_help { + font-weight: bold; + color: #4c4c4c; +} + +.openerp .oe-searchview-render-line .oe_label, .openerp .oe-searchview-render-line .oe_label_help { + font-weight: bold; + font-size: 80%; + white-space: nowrap; +} + +.openerp .searchview_extended_group { + padding: 3px; + margin: 2px; +} + +.openerp .searchview_extended_group .oe_adv_filters_and { + border-bottom: 1px solid #8E8E8E; + text-align: center; + margin-top: -10px; +} +.openerp .searchview_extended_group .oe_adv_filters_and span { + background: #F0EEEE; + position: relative; + top: 0.5em; + padding: 0 1em 0 1em; + color: #8E8E8E; +} + +.openerp .searchview_extended_group.last_group .oe_adv_filters_and { + display: none; +} + +.openerp .oe_search-view-buttons { + padding: 2px 0 10px 0; + vertical-align:middle; +} +.openerp .oe_search-view-filters-management { + float: right; +} +.openerp .oe_search-view-filters-management, .openerp .oe_search-view-custom-filter-btn { + float:right; +} + +.openerp .searchview_extended_add_proposition span { + font-size: 0.9em; + background: url(/web/static/src/img/icons/gtk-add.png) repeat-y; + padding-left: 18px; +} + +.openerp .searchview_extended_delete_group { + float:right; + display: none; +} + +.openerp .searchview_extended_delete_prop { + text-decoration: none; +} + +.openerp .searchview_extended_delete_group span, +.openerp .searchview_extended_delete_prop span { + font-size: 0.9em; + background: url(/web/static/src/img/icons/gtk-close.png) repeat-y; + padding-left: 18px; +} +/* List */ +.openerp table.oe-listview-content { + clear: right; + width: 100%; + border-spacing: 0; + border: 1px solid silver; +} + +.openerp .oe-listview thead table { + width: 100%; + border: none; +} +.openerp .oe-listview tr.odd { + background-color: #f3f3f3; +} +.openerp .oe-listview tbody tr:hover { + background-color: #ecebf2; +} +.openerp .oe-listview tbody tr:hover { + background-color: #eae9f0; +} +.openerp .oe-listview thead table tr, +.openerp .oe-listview thead table tr:hover { + background: none; +} + +.openerp .oe-listview > table > tbody > tr > td, +.openerp .oe-listview th { + vertical-align: middle; + text-align: left; + padding: 1px 2px; +} + +.openerp .oe-record-delete button, +.openerp button.oe-edit-row-save { + border: none; + height: 12px; + width: 12px; + background: url("/web/static/src/img/iconset-b-remove.png") no-repeat scroll center center transparent; + cursor: pointer; +} +.openerp button.oe-edit-row-save { + background-image: url('/web/static/src/img/icons/save-document.png'); +} + +/* Could use :not selectors if they were supported by MSIE8... */ +.openerp .oe-listview > table > tbody > tr > td { + border-left: 1px solid #dadada; /*currently commenting to test with no vertical lines in list view*/ +} +.openerp .oe-listview tbody td:first-child, +.openerp .oe-listview tbody td.oe-button, +.openerp .oe-listview tbody td.oe-button, +.openerp .oe-listview tbody th.oe-record-selector, +.openerp .oe-listview tbody td.oe-record-delete { + border-left: none; +} + +.openerp .oe-listview td.oe-record-delete { + text-align: right; +} +.openerp .oe-listview th.oe-sortable { + cursor: pointer; + font-size: 75%; + text-transform: uppercase; + padding: 0; + margin: 0; + padding-left: 3px; + color: #333; +} +.openerp .oe-listview th.oe-sortable .ui-icon { + height: 60%; + margin: -6px 0 0; + display: inline; + display: inline-block; + vertical-align: middle; +} + +.openerp .oe-listview > table > tbody > tr > td { + border-bottom: 1px solid #E3E3E3; +} + + +.openerp .oe-listview td.oe-actions { + border-bottom:none; +} + +.openerp .oe-listview .oe-record-selector, .openerp .oe-listview .oe-record-edit-link { + border-bottom: 1px solid #E3E3E3; +} +.openerp .oe-listview .oe-record-edit-link { + cursor: pointer; +} + +.openerp .oe-listview .oe-field-cell { + cursor: pointer; + margin-top: 0; + margin-bottom: 0; + padding-top: 3px; + padding-bottom: 3px; + font-size: 80%; +} +.openerp .oe-listview .oe-field-cell progress { + width: 100%; +} +.openerp .oe-listview .oe-field-cell.oe-button button, +.openerp .oe-listview .oe_form_button button { + margin: 0; + padding: 0; + border: none; + background: none; + width: 16px; + box-shadow: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; +} +.openerp .oe-listview .oe-field-cell button:active { + opacity: 0.5; +} +.openerp .oe-listview .oe-field-cell button img { + cursor: pointer; +} +.openerp .oe-listview .oe-field-cell button img:hover { + opacity: 0.75; +} + +.openerp .oe-listview .oe-field-cell .oe-listview-button-disabled img { + opacity: 0.5; +} + +.openerp .oe-listview th.oe-actions { + text-align: left; + white-space: nowrap; +} +.openerp .oe-listview th.oe-list-pager { + text-align: right; + white-space: nowrap; +} +.openerp .oe-list-pager .oe-pager-state { + cursor: pointer; + font-size: 90%; + color: #555; +} + +.openerp .oe_button.oe_button_pager, +.openerp .oe-list-pager > span, +.openerp .oe_form_pager > span { + line-height: 17px; + height: 17px; + cursor: pointer; + color: gray; + font-weight: bold; + vertical-align: middle; +} +.openerp .oe_button.oe_button_pager, +.openerp .oe_button.oe_button_pager:disabled { + padding: 0 3px 0 3px; + margin: 0; + height: 17px; +} +.openerp .oe-listview .oe-group-name { + padding-right: 1em; +} +.openerp .oe-listview .oe-group-name, +.openerp .oe-listview .oe-group-pagination { + white-space: nowrap; +} + +.openerp .oe-listview tfoot td { + padding: 3px 3px 0; +} +.openerp .oe-listview .oe-list-footer { + text-align: center; + white-space: nowrap; + color: #444; + font-size: 85%; +} +.openerp .oe-listview .oe-list-footer span { + margin: 0 1em; +} +.openerp .oe-listview .oe-list-footer progress { + vertical-align:-10% !important; + width: 100%; +} + +/** list rounded corners + + rounded corners are a pain on tables: need to round not only table, but + also on the first and last children of the first and last row + */ +.openerp .oe-listview table.oe-listview-content { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.openerp .oe-listview table.oe-listview-content thead tr:first-child th:first-child { + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; +} +.openerp .oe-listview table.oe-listview-content thead tr:first-child th:last-child { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; +} +.openerp .oe-listview table.oe-listview-content tfoot tr:last-child th:first-child, +.openerp .oe-listview table.oe-listview-content tfoot tr:last-child td:first-child, +.openerp .oe-listview table.oe-listview-content tbody:last-child tr:last-child th:first-child { + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; +} +.openerp .oe-listview table.oe-listview-content tfoot tr:last-child th:last-child, +.openerp .oe-listview table.oe-listview-content tfoot tr:last-child td:last-child, +.openerp .oe-listview table.oe-listview-content tbody:last-child tr:last-child td:last-child { + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; +} + +/* Notebook */ +.openerp .oe_form_notebook { + padding: 0; + background: none; + border-width: 0; +} +.openerp .oe_form_notebook .ui-tabs-panel { + padding: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; +} +.openerp .oe_form_notebook ul.ui-tabs-nav { + padding-left: 0; + background: transparent; + border-width: 0; + border-radius: 0; + -moz-border-radius: 0; + -webkit-border-radius: 0; + line-height: 0.8em; + font-size: 95%; + color: #555; +} +.openerp .oe_form_notebook ul.ui-tabs-nav li { + font-weight: bold; +} +.openerp .oe_form_notebook .ui-tabs-panel { + background: #f9f9f9; + border-width: 1px; +} +.openerp .oe_form_notebook .ui-tabs-selected { + background: #f9f9f9; +} +/* Unedit Form */ +.openerp .field_char, +.openerp .field_date, +.openerp .field_float, +.openerp .field_selection, +.openerp a.oe_form_uri { + vertical-align: middle; + padding-top: 3px; + font-size: 90%; + color: #222; +} +.openerp a.oe_form_uri { + color: #9A0404; + line-height: 12px; +} + + + +/* Form */ +.openerp .oe_form_button_save_dirty { + display: none; +} +.openerp .oe_form_dirty > .oe_form_header > .oe_form_buttons > .oe_form_button_save { + color: white; + background: #dc5f59; + background: -moz-linear-gradient(#dc5f59, #b33630); + background: -webkit-gradient(linear, left top, left bottom, from(#dc5f59), to(#b33630)); + background: -webkit-linear-gradient(#dc5f59, #b33630); + -moz-box-shadow: none; + -webkit-box-shadow: none; + -box-shadow: none; + font-weight: bold; +} +.openerp .oe_form_frame_cell input[type="checkbox"] { + margin-top: 3px; + vertical-align: middle; +} +.openerp .oe_form_frame_cell .input[type="text"] { + padding-bottom: 1px; +} + +.openerp table.oe_frame td { + color: #4c4c4c; +} +.openerp td.oe_form_frame_cell { + padding: 2px; + position: relative; +} +.openerp .oe_frame.oe_forms { + clear: both; +} +.openerp table.oe_frame { + color: #4c4c4c; +} +.openerp fieldset.oe_group_box { + border: 1px solid #AAAAAA; + moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + background: #F9F9F9; + padding: 4px; +} +.openerp fieldset.oe_group_box legend { + font-weight: bold; +} +.openerp td.oe_form_frame_cell { + padding: 2px; + position: relative; +} +.openerp td.oe_form_field_translatable, +.openerp td.oe_form_field_many2one, +.openerp td.oe_form_field_date, +.openerp td.oe_form_field_datetime { + white-space: nowrap; +} +.openerp td.oe_form_field_boolean { + padding-top: 4px; +} +.openerp td.oe_form_frame_cell.oe_form_group { + padding: 0; +} +.openerp .required.error { + border: 1px solid #900; +} +.openerp .oe_form_buttons, .openerp .oe_list_buttons { + float: left; +} +.openerp .oe_form_pager, .openerp .oe_list_pager { + float: right; + font-size: 80%; + color: gray; + font-weight: bold; +} + +.openerp .oe_form_pager { + margin-right: 3px; +} + + +.openerp label.oe_label_help, .openerp label.oe_label, +.openerp .oe_form_paragraph, +.openerp .oe_form_field_statusbar, +.openerp .oe_forms input[type="text"], +.openerp .oe_forms input[type="password"], +.openerp .oe_forms input[type="file"], +.openerp .oe_forms select, +.openerp .oe_forms .oe_button, +.openerp .oe_forms textarea { + font-size: 85%; +} + +.openerp label.oe_label_help, .openerp label.oe_label { + display: block; + color: #4c4c4c; + font-weight: normal; +} +.openerp label.oe_label_help { + cursor: help; +} +.openerp .oe_form_frame_cell .oe_label, .openerp .oe_form_frame_cell .oe_label_help { + font-weight: normal; +} +.openerp #tiptip_content { + font-size: 12px; +} +.openerp .oe_tooltip_string { + color: #FD5; + font-weight: bold; + font-size: 13px; +} +.openerp .oe_tooltip_help { + white-space: pre-wrap; +} +.openerp .oe_tooltip_technical { + padding: 0 0 4px 0; + margin: 5px 0 0 15px; + list-style: circle; +} +.openerp .oe_tooltip_technical_title { + font-weight: bold; +} + +.openerp .oe_forms label.oe_label, .openerp .oe_forms label.oe_label_help { + margin: 3px 0 0 3px; + white-space: nowrap; +} +.openerp .oe_forms .searchview_group_content label.oe_label, .openerp .searchview_group_content .oe_forms label.oe_label_help { /* making a distinction between labels in search view and other labels */ + margin: 3px 0 0 3px; +} + +.openerp label.oe_label_help span { + font-size: 80%; + color: darkgreen; + vertical-align:top; + position: relative; + top: -4px; + padding: 0 2px; +} +.openerp .oe_align_left { + text-align: left; +} +.openerp .oe_align_right { + text-align: right; +} +.openerp .oe_align_center { + text-align: center; +} +.openerp .oe_forms .oe_form_paragraph { + margin: 3px 0 0 0; + white-space: normal; +} + +.openerp .oe_forms .oe_form_paragraph.oe_multilines { + white-space: pre; +} + +.openerp .oe_form_field_one2many .oe-actions h3.oe_view_title, +.openerp .oe_form_field_one2many_list .oe-actions h3.oe_view_title{ + display: inline; + margin: 0 0.5em 0 0; +} + +.openerp .oe_forms .oe-listview th.oe-sortable .ui-icon, +.openerp .oe_forms .oe-listview th.oe-sortable .ui-icon { + height: 100%; + margin-top: -9px; +} + +.openerp table.oe_frame .oe-listview-content td { + color: inherit; +} + +/* Uneditable Form View */ +.openerp .oe_form_readonly { + +} +.openerp .oe_form_readonly .oe_form_frame_cell .field_text, +.openerp .oe_form_readonly .field_char, +.openerp .oe_form_readonly .field_int, +.openerp .oe_form_readonly .field_float, +.openerp .oe_form_readonly .field_email, +.openerp .oe_form_readonly .field_date, +.openerp .oe_form_readonly .field_selection, +.openerp .oe_forms_readonly .oe_form_field_many2one { + padding: 3px 2px 2px 2px; + background-color: white; + height: 17px; +} +.openerp .oe_form_readonly .oe_form_frame_cell .field_text { + height: auto; +} +.openerp .oe_form_readonly .field_datetime { + padding: 1px 2px 2px 2px; + background-color: white; + height:19px; +} +.openerp .oe_form_readonly .oe_form_field_many2one div { + background-color:white; + height:18px; + margin-bottom:1px; + padding: 0px 2px 5px 2px; +} + +.openerp .oe_form_readonly .oe_form_field_email div { + background-color: white; + padding: 1px 2px 3px 2px; +} + + +.openerp .oe_form_readonly .oe_form_field_text div.field_text, +.openerp .oe_form_readonly .oe_form_field_text_html div.field_text_html { + white-space: pre-wrap; +} +.openerp .oe_form_readonly .oe_form_frame_cell .field_text { + min-height:100px; +} +/* Inputs */ +.openerp .oe_forms input[type="text"], +.openerp .oe_forms input[type="password"], +.openerp .oe_forms input[type="file"], +.openerp .oe_forms select, +.openerp .oe_forms textarea { + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + padding: 0 2px; + margin: 0 2px; + border: 1px solid #999; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; + background: white; + min-width: 90px; + color: #1f1f1f; +} + +.openerp .oe_forms input.field_many2one, +.openerp .oe_forms input.field_binary, +.openerp .oe_forms input.field_binary, +.openerp .oe_forms input.field_email, +.openerp .oe_forms input.field_url { + border-right: none; + -webkit-border-top-right-radius: 0px; + -webkit-border-bottom-right-radius: 0px; + -moz-border-radius-topright: 0px; + -moz-border-radius-bottomright: 0px; + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; +} +.openerp .oe_button.oe_field_button { + -webkit-border-top-left-radius: 0px; + -webkit-border-bottom-left-radius: 0px; + -moz-border-radius-topleft: 0px; + -moz-border-radius-bottomleft: 0px; + border-top-left-radius: 0px; + border-bottom-left-radius: 0px; + margin-right:-1px; + height: 22px; +} + +.openerp .oe_form_field_email button img, +.openerp .oe_form_field_url button img { + vertical-align: top; +} +/* vertically recentering filter management select tag */ +.openerp select.oe_search-view-filters-management { + margin-top:2px; +} + +.openerp .oe_forms select{ + padding-top: 2px; +} +.openerp .oe_forms input[readonly], +.openerp .oe_forms select[readonly], +.openerp .oe_forms textarea[readonly], +.openerp .oe_forms input[disabled], +.openerp .oe_forms select[disabled], +.openerp .oe_forms textarea[disabled]{ + background: #E5E5E5 !important; + color: #666; +} +.openerp .oe_forms textarea { + resize:vertical; +} +.openerp .oe_forms input[type="text"], +.openerp .oe_forms input[type="password"], +.openerp .oe_forms input[type="file"], +.openerp .oe_forms select, +.openerp .oe_forms .oe_button { + height: 22px; +} + +.openerp .oe_forms input.field_datetime { + min-width: 11em; +} +.openerp .oe_forms .oe_form_button .oe_button { + color: #4c4c4c; + white-space: nowrap; + min-width: 100%; + width: 100%; +} +@-moz-document url-prefix() { + /* Strange firefox behaviour on width: 100% + white-space: nowrap */ + .openerp .oe_forms .oe_form_button .oe_button { + width: auto; + } +} +/* IE Hack - for IE < 9 + * Avoids buttons overflow + * */ +.openerp .oe_forms .oe_form_button .oe_button { + min-width: auto\9; +} +.openerp .oe_forms .button { + height: 22px; +} +.openerp .oe_forms .oe_button span { + position: relative; + vertical-align: top; +} +.openerp .oe_input_icon { + cursor: pointer; + margin: 3px 0 0 -21px; + vertical-align: top; +} +.openerp .oe_datepicker_container { + display: none; +} +.openerp .oe_datepicker_root { + display: inline-block; +} +.openerp .oe_form_frame_cell .oe_datepicker_root { + width: 100%; +} +.openerp .oe_input_icon_disabled { + position: absolute; + cursor: default; + opacity: 0.5; + filter:alpha(opacity=50); + right: 5px; + top: 3px; +} +.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 + */ +.openerp .oe-binary-file-set { + overflow: hidden; + position: relative; +} +.openerp input.oe-binary-file { + z-index: 0; + line-height: 0; + font-size: 12px; + position: absolute; + /* Should be adjusted for all browsers */ + top: 1px; + right: 10px; + opacity: 0; + filter: alpha(opacity = 0); + -ms-filter: "alpha(opacity=0)"; + margin: 0; + padding:0; +} + +/* Widgets */ +.openerp .separator { + border: 0 solid #666; +} +.openerp .separator.horizontal { + font-weight: bold; + border-bottom-width: 1px; + margin: 3px 4px 3px 1px; + height: 17px; + font-size: 95%; +} +.openerp .separator.horizontal:empty { + height: 5px; +} +.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; +} +.openerp td.invalid input, .openerp td.invalid select, .openerp td.invalid textarea { + background-color: #F66 !important; + border: 1px solid #D00 !important; +} +.openerp div.oe-progressbar span { + position: absolute; + margin-left: 10px; + margin-top: 5px; + font-weight: bold; +} + +/* jQuery UI override */ +.openerp .ui-widget { + font-size: 1em; +} +.openerp .oe_form_field_progressbar .ui-progressbar { + height: 22px; + font-size: 10px; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + border: 1px solid #999; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; + background: white; + min-width: 90px; +} +.openerp tbody.ui-widget-content { + margin-bottom: 10px; + border-spacing: 4px; +} +.openerp .ui-widget-header { + background: white none; +} +/* progress bars */ +.openerp .ui-progressbar .ui-widget-header { + background: #cccccc url(/web/static/lib/jquery.ui/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; +} + +/* Sidebar */ +.openerp .view-manager-main-table { + margin: 0; + width:100%; + border-collapse:collapse; + height:100%; +} + +.openerp .view-manager-main-table tbody { + vertical-align: top; +} + +.openerp .oe-view-manager-header { + overflow: auto; + background: url("/web/static/src/img/sep-a.gif") 0 100% repeat-x; + margin:6px 0 6px 2px; +} +.openerp .oe_form_frame_cell .oe-view-manager-header { /* Trick: remove the background when element is in a formular */ + background: none; +} + +.openerp .oe-view-manager-header h2 { + float: left; +} + +.openerp .oe_view_manager_menu_tips blockquote { + display: none; + font-size: 85%; + margin: 0; + background: #fff; + border-bottom: 1px solid #CECBCB; + padding: 1px 10px; + color: #4C4C4C; +} +.openerp .oe_view_manager_menu_tips blockquote p { + margin: 0; + padding: 6px 1px 4px; +} + +.openerp .oe_view_manager_menu_tips blockquote div { + text-align: right; + margin-right:10px; +} + +.openerp .oe_view_manager_menu_tips blockquote div button { + border: none; + background: none; + padding: 0 4px; + margin: 0; + display: inline; + text-decoration: underline; + color: inherit; +} +.openerp .oe-view-manager-logs { + clear: both; + background: #fff; + margin: 0.25em 0; + font-size: 85%; + color: #4C4C4C; + position: relative; + overflow: hidden; +} +.openerp .oe-view-manager-logs ul { + margin: 0; + padding: 0 10px; + list-style: none; +} +.openerp .oe-view-manager-logs li:before { + content: '\2192 '; +} +.openerp .oe-view-manager-logs a { + text-decoration: none; + color: inherit; +} +/* only display first three log items of a folded logs list */ +.openerp .oe-view-manager-logs.oe-folded li:nth-child(n+4) { + display: none; +} +/* display link to more logs if there are more logs to view and the logview is + currently folded */ +.openerp .oe-view-manager-logs a.oe-more-logs { + display: none; +} +.openerp .oe-view-manager-logs.oe-folded.oe-has-more a.oe-more-logs { + display: block; +} +.openerp .oe-view-manager-logs a.oe-remove-everything { + position: absolute; + top: 0; + right: 0; + cursor: pointer; +} + +.openerp .view-manager-main-sidebar { + width: 180px; + padding: 0; + margin: 0; +} + +.openerp .sidebar-main-div { + height: 100%; + border-left: 1px solid #D2CFCF; +} + +.openerp .sidebar-content { + padding: 0; + margin: 0; + width: 180px; + height: 100%; + font-size: 0.9em; +} + +.openerp .closed-sidebar .sidebar-content { + width: 22px; +} + +.openerp .closed-sidebar .sidebar-content { + display: none; +} + +.openerp .sidebar-main-div a { + color: #555; + text-decoration: none; +} + +.openerp .sidebar-main-div a:hover { + color: black; +} + +.openerp .oe-sidebar-attachments-toolbar { + margin: 4px 0 0 4px; +} +.openerp .oe-sidebar-attachments-items { + clear: both; + padding-top: 5px !important; +} +.openerp .oe-sidebar-attachments-items li { + position: relative; + padding: 0 0 3px 10px !important; +} +.openerp .oe-sidebar-attachments-items li:hover { + background: #ddd; +} +.openerp .oe-sidebar-attachments-link { + display: block; + margin-right: 15px; + overflow: hidden; +} +.openerp .oe-sidebar-attachment-delete { + position: absolute; + right: 2px; + top: 1px; + overflow: hidden; + width: 15px; + height: 15px; + padding: 1px; + border-radius: 7px; + -moz-border-radius: 7px; + -webkit-border-radius: 7px; +} +.openerp .oe-sidebar-attachment-delete:hover { + background-color: white; +} + +.openerp .view-manager-main-sidebar h2 { + margin:0; + font-size: 1.15em; + color: #8E8E8E; + text-shadow: white 0 1px 0; + padding-left: 10px; + padding-right: 21px; + height: 21px; + + background: #ffffff; /* Old browsers */ + background: -moz-linear-gradient(top, #ffffff 0%, #ebe9e9 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#ebe9e9)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* Opera11.10+ */ + background: -ms-linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* IE10+ */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#EBE9E9',GradientType=0 ); /* IE6-9 */ + background: linear-gradient(top, #ffffff 0%,#ebe9e9 100%); /* W3C */ + + border: 1px solid #D2CFCF; + border-right-width: 0; + border-left-width: 0; +} +.openerp .view-manager-main-sidebar h2 { + border-top-width: 0; +} + +.openerp .view-manager-main-sidebar ul { + list-style-type: none; + margin: 0; + padding: 0; + display: block; +} + +.openerp .view-manager-main-sidebar li { + display: block; + padding: 3px 3px 3px 10px; +} + +.openerp .toggle-sidebar { + cursor: pointer; + border: 1px solid #D2CFCF; + border-top-width: 0; + display: block; + background: url(/web/static/src/img/toggle-a-bg.png); + width: 21px; + height: 21px; + z-index: 10; +} +.openerp .open-sidebar .toggle-sidebar { + margin-left: 158px; + background-position: 21px 0; + position: absolute; +} +.openerp .closed-sidebar .toggle-sidebar { + border-left: none; +} +.openerp li.oe_sidebar_print { + padding-left: 20px; + background: 1px 3px url(/web/static/src/img/icons/gtk-print.png) no-repeat; +} + +.openerp .oe_sidebar_print ul { + padding-left:8px; +} + +.openerp.kitten-mode-activated .main_table { + background: url(http://placekitten.com/g/1500/800) repeat; +} +.openerp.kitten-mode-activated.clark-gable .main_table { + background: url(http://amigrave.com/ClarkGable.jpg); + background-size: 100%; +} + +.openerp.kitten-mode-activated .header { + background: url(http://placekitten.com/g/211/65) repeat; +} + +.openerp.kitten-mode-activated .menu { + background: #828282; + background: -moz-linear-gradient(top, #828282 0%, #4D4D4D 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#828282), color-stop(100%,#4D4D4D)); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#828282', endColorstr='#4D4D4D',GradientType=0 ); +} +.openerp.kitten-mode-activated .menu a { + background: none; +} +.openerp.kitten-mode-activated .menu span { + background: none; +} +.openerp.kitten-mode-activated .sidebar-content li a, +.openerp.kitten-mode-activated .oe-application .view-manager-main-content h2.oe_view_title, +.openerp.kitten-mode-activated .oe-application .view-manager-main-content a.searchview_group_string, +.openerp.kitten-mode-activated .oe-application .view-manager-main-content label { + color: white; +} +.openerp.kitten-mode-activated .menu, +.openerp.kitten-mode-activated .header_corner, +.openerp.kitten-mode-activated .header_title, +.openerp.kitten-mode-activated .oe-application, +.openerp.kitten-mode-activated .oe_footer, +.openerp.kitten-mode-activated .loading, +.openerp.kitten-mode-activated .ui-dialog { + opacity:0.8; + filter:alpha(opacity=80); +} +.openerp.kitten-mode-activated .header .company_logo { + background: url(http://placekitten.com/g/180/46); +} +.openerp.kitten-mode-activated .loading { + background: #828282; + border-color: #828282; +} + +.openerp .oe-m2o-drop-down-button { + margin-left: -24px; +} +.openerp .oe-m2o-drop-down-button img { + margin-bottom: -4px; + cursor: pointer; +} +.openerp .oe-m2o input { + border-right: none; + margin-right: 0px !important; + padding-bottom: 2px !important; +} +.openerp .oe-m2o-disabled-cm { + color: grey; +} +.openerp ul[role="listbox"] li a { + font-size:80%; +} +.parent_top { + vertical-align: text-top; +} + +.openerp .oe-dialog-warning p { + padding-left: 1em; + font-size: 1.2em; + font-weight: bold; +} + +.openerp .dhx_mini_calendar { + -moz-box-shadow: none; + -khtml-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} +.openerp .oe-treeview-table { + width: 100%; + background-color : #FFFFFF; + border-spacing: 0; + +} +.openerp .oe-treeview-table tr:hover{ + color: blue; + background-color : #D8D8D8; +} +.treeview-tr, .treeview-td { + cursor: pointer; + vertical-align: top; + text-align: left; + border-bottom: 1px solid #CFCCCC; +} +.openerp .oe-treeview-table .oe-number { + text-align: right !important; +} +.treeview-tr span, .treeview-td span { + font-size: 90%; + font-weight: normal; + white-space: nowrap; + display: block; + } +.treeview-tr.oe-treeview-first { + background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat; +} +.oe-open .treeview-tr.oe-treeview-first { + background-image: url(/web/static/src/img/collapse.gif); +} +.treeview-tr.oe-treeview-first span, +.treeview-td.oe-treeview-first span { + margin-left: 16px; +} + +.treeview-header { + vertical-align: top; + background-color : #D8D8D8; + white-space: nowrap; + text-align: left; + padding: 4px 5px; +} +/* Shortcuts*/ +.oe-shortcut-toggle { + height: 20px; + margin-top: 3px; + padding: 0; + width: 24px; + cursor: pointer; + display: block; + background: url(/web/static/src/img/add-shortcut.png) no-repeat center center; + float: left; +} +.oe-shortcut-remove{ + background: url(/web/static/src/img/remove-shortcut.png) no-repeat center center; +} +.oe-shortcuts { + position: absolute; + margin: 0; + padding: 6px 15px; + top: 37px; + left: 197px; + right: 0; + height: 17px; + line-height: 1.2; +} +.oe-shortcuts ul { + display: block; + overflow: hidden; + list-style: none; + white-space: nowrap; + padding: 0; + margin: 0; +} +.oe-shortcuts li { + cursor: pointer; + display: -moz-inline-stack; + display: inline-block; + display: inline; /*IE7 */ + color: #fff; + text-align: center; + border-left: 1px solid #909090; + padding: 0 4px; + font-size: 80%; + font-weight: normal; + vertical-align: top; +} + +.oe-shortcuts li:hover { + background-color: #666; +} +.oe-shortcuts li:first-child { + border-left: none; + padding-left: 0; +} + +ul.oe-arrow-list { + padding-left: 1.1em; + margin: 0; + white-space: nowrap; +} +ul.oe-arrow-list li { + display: inline-block; + margin-left: -1em; +} +ul.oe-arrow-list li span { + vertical-align: top; + display: inline-block; + border: 1em solid #DEDEDE; + line-height:0em; +} +ul.oe-arrow-list .oe-arrow-list-before { + border-left-color: rgba(0,0,0,0); + border-right-width:0; +} +ul.oe-arrow-list .oe-arrow-list-after { + border-color: rgba(0,0,0,0); + border-left-color: #DEDEDE; + border-right-width:0; +} +ul.oe-arrow-list li.oe-arrow-list-selected span { + border-color: #B5B9FF; +} +ul.oe-arrow-list li.oe-arrow-list-selected .oe-arrow-list-before { + border-left-color: rgba(0,0,0,0); +} +ul.oe-arrow-list li.oe-arrow-list-selected .oe-arrow-list-after { + border-color: rgba(0,0,0,0); + border-left-color: #B5B9FF; +} +.openerp ul.oe-arrow-list li:first-child span:first-child{ + -webkit-border-top-left-radius: 3px; + -moz-border-radius-topleft: 3px; + border-top-left-radius: 3px; + -webkit-border-bottom-left-radius: 3px; + -moz-border-radius-bottomleft: 3px; + border-bottom-left-radius: 3px; +} +.openerp ul.oe-arrow-list li:last-child span:last-child{ + -webkit-border-top-right-radius: 3px; + -moz-border-radius-topright: 3px; + border-top-right-radius: 3px; + -webkit-border-bottom-right-radius: 3px; + -moz-border-radius-bottomright: 3px; + border-bottom-right-radius: 3px; +} +.openerp .oe_view_editor { + width:100%; + border-collapse : collapse; + margin-left: -12px; + + width: 100%; + background-color : white; + border-spacing: 0; +} +.openerp .oe_view_editor td{ + text-align: center; + white-space: nowrap; + border: 1px solid #D8D8D8; + + cursor: pointer; + font-size: 90%; +} +.openerp .oe_view_editor_field td{ + border: 0px !important; +} + +.openerp .oe_view_editor tr:hover { + background-color: #ecebf2; +} + + +/* Dialog traceback cases */ +.openerp .oe_error_detail{ + display: block; +} +.openerp .oe_error_send{ + display:block; +} +.openerp .oe_fielddiv{ + display:inline-block; + width:100%; +} +.openerp .oe_fielddiv input[type=text],textarea{ + width:100%; +} +/* for Alignment center */ +.openerp .oe_centeralign{ + text-align:center; +} + +.openerp .oe_applications_tiles { + color: #4C4C4C; + text-shadow: #EEE 0 1px 0; + margin: 0 20px; +} + +.openerp .oe_vm_switch { + margin:2px 0 0 0; +} + +.openerp .oe_vm_switch_form, +.openerp .oe_vm_switch_page, +.openerp .oe_vm_switch_tree, +.openerp .oe_vm_switch_list, +.openerp .oe_vm_switch_graph, +.openerp .oe_vm_switch_gantt, +.openerp .oe_vm_switch_calendar, +.openerp .oe_vm_switch_kanban, +.openerp .oe_vm_switch_diagram { + background: url("/web/static/src/img/views-icons-a.png") repeat-x scroll left top transparent; + overflow: hidden; + width: 22px; + height: 21px; + border: none; + background-position: 0px 0px; +} + +.openerp .oe_vm_switch_form span, +.openerp .oe_vm_switch_page span, +.openerp .oe_vm_switch_tree span, +.openerp .oe_vm_switch_list span, +.openerp .oe_vm_switch_graph span, +.openerp .oe_vm_switch_gantt span, +.openerp .oe_vm_switch_calendar span, +.openerp .oe_vm_switch_kanban span, +.openerp .oe_vm_switch_diagram span { + display: none; +} + +.openerp .oe_vm_switch_list { + background-position: 0px 0px; +} +.openerp .oe_vm_switch_list:active, +.openerp .oe_vm_switch_list:hover, +.openerp .oe_vm_switch_list:focus, +.openerp .oe_vm_switch_list[disabled="disabled"] { + background-position: 0px -21px; +} + +.openerp .oe_vm_switch_tree { + background-position: 0px 0px; +} +.openerp .oe_vm_switch_tree:active, +.openerp .oe_vm_switch_tree:hover, +.openerp .oe_vm_switch_tree:focus, +.openerp .oe_vm_switch_tree[disabled="disabled"] { + background-position: 0px -21px; +} + +.openerp .oe_vm_switch_form { + background-position: -22px 0px; +} +.openerp .oe_vm_switch_form:active, +.openerp .oe_vm_switch_form:hover, +.openerp .oe_vm_switch_form:focus, +.openerp .oe_vm_switch_form[disabled="disabled"] { + background-position: -22px -21px; +} + +.openerp .oe_vm_switch_page { + background-position: -22px 0px; +} +.openerp .oe_vm_switch_page:active, +.openerp .oe_vm_switch_page:hover, +.openerp .oe_vm_switch_page:focus, +.openerp .oe_vm_switch_page[disabled="disabled"] { + background-position: -22px -21px; +} +.openerp .oe_vm_switch_graph { + background-position: -44px 0px; +} +.openerp .oe_vm_switch_graph:active, +.openerp .oe_vm_switch_graph:hover, +.openerp .oe_vm_switch_graph:focus, +.openerp .oe_vm_switch_graph[disabled="disabled"] { + background-position: -44px -21px; +} + +.openerp .oe_vm_switch_gantt { + background-position: -66px 0px; +} +.openerp .oe_vm_switch_gantt:active, +.openerp .oe_vm_switch_gantt:hover, +.openerp .oe_vm_switch_gantt:focus, +.openerp .oe_vm_switch_gantt[disabled="disabled"] { + background-position: -66px -21px; +} + +.openerp .oe_vm_switch_calendar { + background-position: -88px 0px; +} +.openerp .oe_vm_switch_calendar:active, +.openerp .oe_vm_switch_calendar:hover, +.openerp .oe_vm_switch_calendar:focus, +.openerp .oe_vm_switch_calendar[disabled="disabled"] { + background-position: -88px -21px; +} +.openerp .oe_vm_switch_kanban { + background-position: -110px 0px; +} +.openerp .oe_vm_switch_kanban:active, +.openerp .oe_vm_switch_kanban:hover, +.openerp .oe_vm_switch_kanban:focus, +.openerp .oe_vm_switch_kanban[disabled="disabled"] { + background-position: -110px -21px; +} + +.openerp .oe_vm_switch_diagram { + background-position: 0px 0px; +} +.openerp .oe_vm_switch_diagram:active, +.openerp .oe_vm_switch_diagram:hover, +.openerp .oe_vm_switch_diagram:focus, +.openerp .oe_vm_switch_diagram[disabled="disabled"] { + background-position: 0px -21px; +} + +/* Buttons */ +.openerp .oe_button:link, +.openerp .oe_button:visited, +.openerp .oe_button { + display: inline-block; + border: 1px solid #ababab; + color: #404040; + font-size: 12px; + padding: 3px 10px; + text-align: center; + -o-background-size: 100% 100%; + -moz-background-size: 100% 100%; + -webkit-background-size: auto auto !important; + background-size: 100% 100%; + background: #d8d8d8 none; + background: none, -webkit-gradient(linear, left top, left bottom, from(#efefef), to(#d8d8d8)); + background: none, -webkit-linear-gradient(#efefef, #d8d8d8); + background: none, -moz-linear-gradient(#efefef, #d8d8d8); + background: none, -o-linear-gradient(top, #efefef, #d8d8d8); + background: none, -khtml-gradient(linear, left top, left bottom, from(#efefef), to(#d8d8d8)); + background: -ms-linear-gradient(top, #efefef, #d8d8d8); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#efefef', endColorstr='#d8d8d8',GradientType=0 ); + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + -o-border-radius: 3px; + -ms-border-radius: 3px; + border-radius: 3px; + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset; + -o-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5); + -webkit-font-smoothing: antialiased; + outline: none; +} + +.openerp .oe_button:hover { + -o-background-size: 100% 100%; + -moz-background-size: 100% 100%; + -webkit-background-size: auto auto !important; + background-size: 100% 100%; + background: #e3e3e3 none; + background: none, -webkit-gradient(linear, left top, left bottom, from(#f6f6f6), to(#e3e3e3)); + background: none, -webkit-linear-gradient(#f6f6f6, #e3e3e3); + background: none, -moz-linear-gradient(#f6f6f6, #e3e3e3); + background: none, -o-linear-gradient(top, #f6f6f6, #e3e3e3); + background: none, -khtml-gradient(linear, left top, left bottom, from(#f6f6f6), to(#e3e3e3)); + background: -ms-linear-gradient(top, #f6f6f6, #e3e3e3); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f6f6f6', endColorstr='#e3e3e3',GradientType=0 ); + cursor: pointer; +} + +.openerp .oe_button:focus { + border: 1px solid #80bfff; + -o-background-size: 100% 100%; + -moz-background-size: 100% 100%; + -webkit-background-size: auto auto !important; + background-size: 100% 100%; + background: #e3e3e3, none; + background: none, -webkit-gradient(linear, left top, left bottom, from(#f6f6f6), to(#e3e3e3)); + background: none, -webkit-linear-gradient(#f6f6f6, #e3e3e3); + background: none, -moz-linear-gradient(#f6f6f6, #e3e3e3); + background: none, -o-linear-gradient(top, #f6f6f6, #e3e3e3); + background: none, -khtml-gradient(linear, left top, left bottom, from(#f6f6f6), to(#e3e3e3)); + background: -ms-linear-gradient(top, #f6f6f6, #e3e3e3); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f6f6f6', endColorstr='#e3e3e3',GradientType=0 ); + -moz-box-shadow: 0 0 3px #80bfff, 0 1px 1px rgba(255, 255, 255, 0.8) inset; + -webkit-box-shadow: 0 0 3px #80bfff, 0 1px 1px rgba(255, 255, 255, 0.8) inset; + -o-box-shadow: 0 0 3px #80bfff, 0 1px 1px rgba(255, 255, 255, 0.8) inset; + box-shadow: 0 0 3px #80bfff, 0 1px 1px rgba(255, 255, 255, 0.8) inset; +} + +.openerp .oe_button:active, +.openerp .oe_button.active { + background: #e3e3e3; + background: -moz-linear-gradient(top, #e3e3e3, #f6f6f6) #1b468f; + background: -webkit-gradient(linear, left top, left bottom, from(#e3e3e3), to(#f6f6f6)) #1b468f; + background: linear-gradient(top, #e3e3e3, #f6f6f6) #1b468f; + background: -ms-linear-gradient(top, #e3e3e3, #f6f6f6); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e3e3e3', endColorstr='#f6f6f6',GradientType=0 ); + -moz-box-shadow: none, 0 0 0 transparent; + -webkit-box-shadow: none, 0 0 0 transparent; + -o-box-shadow: none, 0 0 0 transparent; + box-shadow: none, 0 0 0 transparent; +} + +.openerp .oe_button.disabled, +.openerp .oe_button:disabled { + background: #efefef !important; + border: 1px solid #d1d1d1 !important; + font-size: 12px; + padding: 3px 10px; + -moz-box-shadow: none !important, 0 0 0 transparent; + -webkit-box-shadow: none !important, 0 0 0 transparent; + -o-box-shadow: none !important, 0 0 0 transparent; + box-shadow: none !important, 0 0 0 transparent; + color: #aaaaaa !important; + cursor: default; + text-shadow: 0 1px 1px white !important; +} + +.openerp select.oe_search-view-filters-management { + font-style: oblique; + color: #999999; +} + +.openerp .oe_search-view-filters-management option, +.openerp .oe_search-view-filters-management optgroup { + font-style: normal; + color: black; +} + +/* Debug stuff */ +.openerp .oe_debug_view_log { + font-size: 95%; +} +.openerp .oe_debug_view_log label { + display: block; + width: 49%; + text-align: right; + float: left; + font-weight: bold; + color: #009; +} +.openerp .oe_debug_view_log span { + display: block; + width: 49%; + float: right; + color: #333; +} + +/* Internet Explorer Fix */ +a img { + border: none; +} diff --git a/addons/web/static/src/css/full.css b/addons/web/static/src/css/full.css new file mode 100644 index 00000000000..7f3a2f60ea4 --- /dev/null +++ b/addons/web/static/src/css/full.css @@ -0,0 +1,6 @@ +body { + padding: 0; + margin: 0; + overflow-y: scroll; + height: 100%; +} \ No newline at end of file diff --git a/addons/web/static/src/img/header-about.png b/addons/web/static/src/img/header-about.png deleted file mode 100644 index b53e9a86ebe..00000000000 Binary files a/addons/web/static/src/img/header-about.png and /dev/null differ diff --git a/addons/web/static/src/img/header-background.png b/addons/web/static/src/img/header-background.png deleted file mode 100644 index 774b3954124..00000000000 Binary files a/addons/web/static/src/img/header-background.png and /dev/null differ diff --git a/addons/web/static/src/img/header-help.png b/addons/web/static/src/img/header-help.png deleted file mode 100644 index 19e9906fdef..00000000000 Binary files a/addons/web/static/src/img/header-help.png and /dev/null differ diff --git a/addons/web/static/src/img/header-home.png b/addons/web/static/src/img/header-home.png deleted file mode 100644 index fd96742d15a..00000000000 Binary files a/addons/web/static/src/img/header-home.png and /dev/null differ diff --git a/addons/web/static/src/img/header-preferences.png b/addons/web/static/src/img/header-preferences.png deleted file mode 100644 index 6c978b49f55..00000000000 Binary files a/addons/web/static/src/img/header-preferences.png and /dev/null differ diff --git a/addons/web/static/src/img/header-requests.png b/addons/web/static/src/img/header-requests.png deleted file mode 100644 index 6577e7e6448..00000000000 Binary files a/addons/web/static/src/img/header-requests.png and /dev/null differ diff --git a/addons/web/static/src/img/topbar-avatar.png b/addons/web/static/src/img/topbar-avatar.png new file mode 100644 index 00000000000..a2c70ea7d49 Binary files /dev/null and b/addons/web/static/src/img/topbar-avatar.png differ diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index ba31ec81846..f8af815d187 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -45,6 +45,12 @@ openerp.web.Notification = openerp.web.OldWidget.extend(/** @lends openerp.web. }); +openerp.web.dialog = function(element) { + var result = element.dialog.apply(element, _.rest(_.toArray(arguments))); + result.dialog("widget").addClass("openerp"); + return result; +} + openerp.web.Dialog = openerp.web.OldWidget.extend(/** @lends openerp.web.Dialog# */{ dialog_title: "", /** @@ -86,7 +92,7 @@ openerp.web.Dialog = openerp.web.OldWidget.extend(/** @lends openerp.web.Dialog# if (this.dialog_options.autoOpen) { this.open(); } else { - this.$element.dialog(this.get_options()); + openerp.web.dialog(this.$element, this.get_options()); } }, get_options: function(options) { @@ -125,7 +131,7 @@ openerp.web.Dialog = openerp.web.OldWidget.extend(/** @lends openerp.web.Dialog# this.$element.html(this.render()); } var o = this.get_options(options); - this.$element.dialog(o).dialog('open'); + openerp.web.dialog(this.$element, o).dialog('open'); if (o.height === 'auto' && o.max_height) { this.$element.css({ 'max-height': o.max_height, 'overflow-y': 'auto' }); } @@ -142,7 +148,7 @@ openerp.web.Dialog = openerp.web.OldWidget.extend(/** @lends openerp.web.Dialog# on_resized: function() { //openerp.log("Dialog resized to %d x %d", this.$element.width(), this.$element.height()); }, - stop: function () { + destroy: function () { // Destroy widget this.close(); this.$element.dialog('destroy'); @@ -166,7 +172,7 @@ openerp.web.CrashManager = openerp.web.CallbackEnabled.extend({ } }, on_managed_error: function(error) { - $('
    ' + QWeb.render('CrashManagerWarning', {error: error}) + '
    ').dialog({ + openerp.web.dialog($('
    ' + QWeb.render('CrashManagerWarning', {error: error}) + '
    '), { title: "OpenERP " + _.str.capitalize(error.type), buttons: [ {text: _t("Ok"), click: function() { $(this).dialog("close"); }} @@ -234,7 +240,7 @@ openerp.web.Loading = openerp.web.OldWidget.extend(/** @lends openerp.web.Loadin this.session.on_rpc_request.add_first(this.request_call); this.session.on_rpc_response.add_last(this.response_call); }, - stop: function() { + destroy: function() { this.session.on_rpc_request.remove(this.request_call); this.session.on_rpc_response.remove(this.response_call); this.on_rpc_event(-this.count); @@ -255,7 +261,7 @@ openerp.web.Loading = openerp.web.OldWidget.extend(/** @lends openerp.web.Loadin $(".loading",this.$element).text(_.str.sprintf( _t("Loading (%d)"), this.count)); $(".loading",this.$element).show(); - this.widget_parent.$element.addClass('loading'); + this.getParent().$element.addClass('loading'); } else { this.count = 0; clearTimeout(this.long_running_timer); @@ -265,7 +271,7 @@ openerp.web.Loading = openerp.web.OldWidget.extend(/** @lends openerp.web.Loadin $.unblockUI(); } $(".loading",this.$element).fadeOut(); - this.widget_parent.$element.removeClass('loading'); + this.getParent().$element.removeClass('loading'); } } }); @@ -312,7 +318,7 @@ openerp.web.Database = openerp.web.OldWidget.extend(/** @lends openerp.web.Datab self.hide(); }); }, - stop: function () { + destroy: function () { this.hide(); this.$option_id.empty(); @@ -344,44 +350,6 @@ openerp.web.Database = openerp.web.OldWidget.extend(/** @lends openerp.web.Datab }); return result; }, - /** - * Waits until the new database is done creating, then unblocks the UI and - * logs the user in as admin - * - * @param {Number} db_creation_id identifier for the db-creation operation, used to fetch the current installation progress - * @param {Object} info info fields for this database creation - * @param {String} info.db name of the database being created - * @param {String} info.password super-admin password for the database - */ - wait_for_newdb: function (db_creation_id, info) { - var self = this; - self.rpc('/web/database/progress', { - id: db_creation_id, - password: info.password - }, function (result) { - var progress = result[0]; - // I'd display a progress bar, but turns out the progress status - // the server report kind-of blows goats: it's at 0 for ~75% of - // the installation, then jumps to 75%, then jumps down to either - // 0 or ~40%, then back up to 75%, then terminates. Let's keep that - // mess hidden behind a not-very-useful but not overly weird - // message instead. - if (progress < 1) { - setTimeout(function () { - self.wait_for_newdb(db_creation_id, info); - }, 500); - return; - } - - var admin = result[1][0]; - setTimeout(function () { - self.widget_parent.do_login( - info.db, admin.login, admin.password); - self.stop(); - self.unblockUI(); - }); - }); - }, /** * Blocks UI and replaces $.unblockUI by a noop to prevent third parties * from unblocking the UI @@ -407,7 +375,7 @@ openerp.web.Database = openerp.web.OldWidget.extend(/** @lends openerp.web.Datab * @param {String} error.error message of the error dialog */ display_error: function (error) { - return $('
    ').dialog({ + return openerp.web.dialog($('
    '), { modal: true, title: error.title, buttons: [ @@ -421,23 +389,19 @@ openerp.web.Database = openerp.web.OldWidget.extend(/** @lends openerp.web.Datab self.$option_id.find("form[name=create_db_form]").validate({ submitHandler: function (form) { var fields = $(form).serializeArray(); - self.blockUI(); self.rpc("/web/database/create", {'fields': fields}, function(result) { - if (result.error) { - self.unblockUI(); - self.display_error(result); - return; - } if (self.db_list) { self.db_list.push(self.to_object(fields)['db_name']); self.db_list.sort(); self.widget_parent.set_db_list(self.db_list); } + var form_obj = self.to_object(fields); - self.wait_for_newdb(result, { - password: form_obj['super_admin_pwd'], - db: form_obj['db_name'] - }); + self.getParent().do_login( + form_obj['db_name'], + 'admin', + form_obj['create_admin_pwd']); + self.destroy(); }); } }); @@ -449,7 +413,7 @@ openerp.web.Database = openerp.web.OldWidget.extend(/** @lends openerp.web.Datab submitHandler: function (form) { var $form = $(form), fields = $form.serializeArray(), - $db_list = $form.find('select[name=drop_db]'), + $db_list = $form.find('[name=drop_db]'), db = $db_list.val(); if (!confirm("Do you really want to delete the database: " + db + " ?")) { @@ -463,7 +427,7 @@ openerp.web.Database = openerp.web.OldWidget.extend(/** @lends openerp.web.Datab $db_list.find(':selected').remove(); if (self.db_list) { self.db_list.splice(_.indexOf(self.db_list, db, true), 1); - self.widget_parent.set_db_list(self.db_list); + self.getParent().set_db_list(self.db_list); } self.do_notify("Dropping database", "The database '" + db + "' has been dropped"); }); @@ -660,58 +624,212 @@ openerp.web.Login = openerp.web.OldWidget.extend(/** @lends openerp.web.Login# } }); -openerp.web.Header = openerp.web.OldWidget.extend(/** @lends openerp.web.Header# */{ - template: "Header", +openerp.web.Menu = openerp.web.Widget.extend(/** @lends openerp.web.Menu# */{ /** - * @constructs openerp.web.Header - * @extends openerp.web.OldWidget + * @constructs openerp.web.Menu + * @extends openerp.web.Widget + * + * @param parent + */ + template: 'Menu', + init: function() { + this._super.apply(this, arguments); + this.has_been_loaded = $.Deferred(); + }, + start: function() { + this._super.apply(this, arguments); + this.$secondary_menus = this.getParent().$element.find('.oe_secondary_menus_container'); + this.$secondary_menus.on('click', 'a[data-menu]', this.on_menu_click); + }, + do_reload: function() { + var self = this; + return this.rpc("/web/menu/load", {}, this.on_loaded).then(function () { + if (self.current_menu) { + self.open_menu(self.current_menu); + } + }); + }, + on_loaded: function(data) { + this.data = data; + this.renderElement(); + this.$element.on('click', 'a[data-menu]', this.on_menu_click); + this.$secondary_menus.html(QWeb.render("Menu.secondary", { widget : this })); + // Hide second level submenus + this.$secondary_menus.find('.oe_menu_toggler').siblings('.oe_secondary_submenu').hide(); + this.has_been_loaded.resolve(); + }, + /** + * Opens a given menu by id, as if a user had browsed to that menu by hand + * except does not trigger any event on the way + * + * @param {Number} id database id of the terminal menu to select + */ + open_menu: function (id) { + var $clicked_menu, $sub_menu, $main_menu; + $clicked_menu = this.$element.add(this.$secondary_menus).find('a[data-menu=' + id + ']'); + + if (this.$secondary_menus.has($clicked_menu).length) { + $sub_menu = $clicked_menu.parents('.oe_secondary_menu'); + $main_menu = this.$element.find('a[data-menu=' + $sub_menu.data('menu-parent') + ']'); + } else { + $sub_menu = this.$secondary_menus.find('.oe_secondary_menu[data-menu-parent=' + $clicked_menu.attr('data-menu') + ']'); + $main_menu = $clicked_menu; + } + + // Activate current main menu + this.$element.find('.oe_active').removeClass('oe_active'); + $main_menu.addClass('oe_active'); + + // Show current sub menu + this.$secondary_menus.find('.oe_secondary_menu').hide(); + $sub_menu.show(); + + // Activate current menu item and show parents + this.$secondary_menus.find('.oe_active').removeClass('oe_active'); + if ($main_menu !== $clicked_menu) { + $clicked_menu.parents().show(); + if ($clicked_menu.is('.oe_menu_toggler')) { + $clicked_menu.toggleClass('oe_menu_opened').siblings('.oe_secondary_submenu:first').toggle(); + } else { + $clicked_menu.parent().addClass('oe_active'); + } + } + }, + open_action: function (id) { + var menu_id, $menu = this.$element.add(this.$secondary_menus).find('a[data-action-id=' + id + ']'); + if (menu_id = $menu.data('menu')) { + this.open_menu(menu_id); + } + }, + on_menu_click: function(ev, id) { + id = id || 0; + var $clicked_menu, manual = false; + + if (id) { + // We can manually activate a menu with it's id (for hash url mapping) + manual = true; + $clicked_menu = this.$element.find('a[data-menu=' + id + ']'); + if (!$clicked_menu.length) { + $clicked_menu = this.$secondary_menus.find('a[data-menu=' + id + ']'); + } + } else { + $clicked_menu = $(ev.currentTarget); + id = $clicked_menu.data('menu'); + } + + this.trigger('menuClicked', id, $clicked_menu); + + if (id) { + this.open_menu(id); + this.current_menu = id; + this.session.active_id = id; + var action_id = $clicked_menu.data('action-id'); + if (action_id) { + this.on_action(action_id); + } + } + if (ev) { + ev.stopPropagation(); + } + return false; + }, + do_show_secondary: function($sub_menu, $main_menu) { + var self = this; + this.$secondary_menus.show(); + if (!arguments.length) { + return; + } + $sub_menu.show(); + }, + on_action: function(action) { + } +}); + +openerp.web.UserMenu = openerp.web.Widget.extend(/** @lends openerp.web.UserMenu# */{ + template: "UserMenu", + /** + * @constructs openerp.web.UserMenu + * @extends openerp.web.Widget * * @param parent */ init: function(parent) { this._super(parent); - this.qs = "?" + jQuery.param.querystring(); - this.$content = $(); this.update_promise = $.Deferred().resolve(); }, start: function() { - this._super(); + var self = this; + this._super.apply(this, arguments); + $('html').bind('click', function() { + self.$element.find('.oe_dropdown_options').hide(); + }); + this.$element.find('.oe_dropdown_toggle').click(function() { + self.$element.find('.oe_dropdown_options').toggle(); + return false; + }); + this.$element.on('click', '.oe_dropdown_options li a[data-menu]', function() { + var f = self['on_menu_' + $(this).data('menu')]; + f && f($(this)); + self.$element.find('.oe_dropdown_options').hide(); + return false; + }); + }, + change_password :function() { + var self = this; + this.dialog = new openerp.web.Dialog(this, { + title: _t("Change Password"), + width : 'auto' + }).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("/web/session/change_password",{ + 'fields': $(form).serializeArray() + }, function(result) { + if (result.error) { + self.display_error(result); + return; + } else { + openerp.webclient.on_logout(); + } + }); + } + }); + }, + display_error: function (error) { + return openerp.web.dialog($('
    '), { + modal: true, + title: error.title, + buttons: [ + {text: _("Ok"), click: function() { $(this).dialog("close"); }} + ] + }).html(error.error); }, do_update: function () { var self = this; var fct = function() { - self.$content.remove(); + var $avatar = self.$element.find('.oe_topbar_avatar'); + $avatar.attr('src', $avatar.data('default-src')); if (!self.session.uid) return; var func = new openerp.web.Model("res.users").get_func("read"); return func(self.session.uid, ["name", "company_id"]).pipe(function(res) { - self.$content = $(QWeb.render("Header-content", {widget: self, user: res})); - self.$content.appendTo(self.$element); - self.$element.find(".logout").click(self.on_logout); - self.$element.find("a.preferences").click(self.on_preferences); - self.$element.find(".about").click(self.on_about); + // TODO: Only show company if multicompany in use + self.$element.find('.oe_topbar_name').text(res.name + '/' + res.company_id[1]); return self.shortcut_load(); }); }; this.update_promise = this.update_promise.pipe(fct, fct); }, - on_about: function() { - var self = this; - self.rpc("/web/webclient/version_info", {}).then(function(res) { - var $help = $(QWeb.render("About-Page", {version_info: res})); - $help.find('a.oe_activate_debug_mode').click(function (e) { - e.preventDefault(); - window.location = $.param.querystring( - window.location.href, 'debug'); - }); - $help.dialog({autoOpen: true, - modal: true, width: 960, title: _t("About")}); - }); + on_action: function() { }, shortcut_load :function(){ var self = this, sc = self.session.shortcuts, shortcuts_ds = new openerp.web.DataSet(this, 'ir.ui.view_sc'); + self.$element.find('.oe_dropdown_options a[data-menu=shortcut]').each(function() { + $(this).parent().remove(); + }); // TODO: better way to communicate between sections. // sc.bindings, because jquery does not bind/trigger on arrays... if (!sc.binding) { @@ -719,52 +837,41 @@ openerp.web.Header = openerp.web.OldWidget.extend(/** @lends openerp.web.Header $(sc.binding).bind({ 'add': function (e, attrs) { shortcuts_ds.create(attrs, function (out) { - $('
  1. ', { - 'data-shortcut-id':out.result, - 'data-id': attrs.res_id - }).text(attrs.name) - .appendTo(self.$element.find('.oe-shortcuts ul')); + var shortcut = QWeb.render('UserMenu.shortcut', { + shortcuts : [{ + name : attrs.name, + id : out.result, + res_id : attrs.res_id + }] + }); + $(shortcut).appendTo(self.$element.find('.oe_dropdown_options')); attrs.id = out.result; sc.push(attrs); }); }, 'remove-current': function () { var menu_id = self.session.active_id; - var $shortcut = self.$element - .find('.oe-shortcuts li[data-id=' + menu_id + ']'); + var $shortcut = self.$element.find('.oe_dropdown_options li a[data-id=' + menu_id + ']'); var shortcut_id = $shortcut.data('shortcut-id'); $shortcut.remove(); shortcuts_ds.unlink([shortcut_id]); var sc_new = _.reject(sc, function(shortcut){ return shortcut_id === shortcut.id}); sc.splice(0, sc.length); sc.push.apply(sc, sc_new); - } + } }); } return this.rpc('/web/session/sc_list', {}, function(shortcuts) { sc.splice(0, sc.length); sc.push.apply(sc, shortcuts); - self.$element.find('.oe-shortcuts') - .html(QWeb.render('Shortcuts', {'shortcuts': shortcuts})) - .undelegate('li', 'click') - - .delegate('li', 'click', function(e) { - e.stopPropagation(); - var id = $(this).data('id'); - self.session.active_id = id; - self.rpc('/web/menu/action', {'menu_id':id}, function(ir_menu_data) { - if (ir_menu_data.action.length){ - self.on_action(ir_menu_data.action[0][2]); - } - }); - }); + $(QWeb.render('UserMenu.shortcut', {'shortcuts': shortcuts})) + .appendTo(self.$element.find('.oe_dropdown_options')); }); }, - - on_action: function(action) { + on_menu_logout: function() { }, - on_preferences: function(){ + on_menu_settings: function() { var self = this; var action_manager = new openerp.web.ActionManager(this); var dataset = new openerp.web.DataSet (this,'res.users',this.context); @@ -793,7 +900,7 @@ openerp.web.Header = openerp.web.OldWidget.extend(/** @lends openerp.web.Header var inner_viewmanager = action_manager.inner_viewmanager; inner_viewmanager.views[inner_viewmanager.active_view].controller.do_save() .then(function() { - self.dialog.stop(); + self.dialog.destroy(); // needs to refresh interface in case language changed window.location.reload(); }); @@ -804,298 +911,66 @@ openerp.web.Header = openerp.web.OldWidget.extend(/** @lends openerp.web.Header action_manager.appendTo(this.dialog); action_manager.render(this.dialog); }, - - change_password :function() { + on_menu_about: function() { var self = this; - this.dialog = new openerp.web.Dialog(this, { - title: _t("Change Password"), - width : 'auto' - }).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("/web/session/change_password",{ - 'fields': $(form).serializeArray() - }, function(result) { - if (result.error) { - self.display_error(result); - return; - } else { - openerp.webclient.on_logout(); - } - }); - } - }); - }, - display_error: function (error) { - return $('
    ').dialog({ - modal: true, - title: error.title, - buttons: [ - {text: _("Ok"), click: function() { $(this).dialog("close"); }} - ] - }).html(error.error); - }, - on_logout: function() { - } -}); - -openerp.web.Menu = openerp.web.OldWidget.extend(/** @lends openerp.web.Menu# */{ - /** - * @constructs openerp.web.Menu - * @extends openerp.web.OldWidget - * - * @param parent - * @param element_id - * @param secondary_menu_id - */ - init: function(parent, element_id, secondary_menu_id) { - this._super(parent, element_id); - this.secondary_menu_id = secondary_menu_id; - this.$secondary_menu = $("#" + secondary_menu_id); - this.menu = false; - this.folded = false; - if (window.localStorage) { - this.folded = localStorage.getItem('oe_menu_folded') === 'true'; - } - this.float_timeout = 700; - }, - start: function() { - this.$secondary_menu.addClass(this.folded ? 'oe_folded' : 'oe_unfolded'); - }, - do_reload: function() { - var self = this; - return this.rpc("/web/menu/load", {}, this.on_loaded).then(function () { - if (self.current_menu) { - self.open_menu(self.current_menu); - } - }); - }, - on_loaded: function(data) { - this.data = data; - this.$element.html(QWeb.render("Menu", { widget : this })); - this.$secondary_menu.html(QWeb.render("Menu.secondary", { widget : this })); - this.$element.add(this.$secondary_menu).find("a").click(this.on_menu_click); - this.$secondary_menu.find('.oe_toggle_secondary_menu').click(this.on_toggle_fold); - }, - on_toggle_fold: function() { - this.$secondary_menu.toggleClass('oe_folded').toggleClass('oe_unfolded'); - if (this.folded) { - this.$secondary_menu.find('.oe_secondary_menu.active').show(); - } else { - this.$secondary_menu.find('.oe_secondary_menu').hide(); - } - this.folded = !this.folded; - if (window.localStorage) { - localStorage.setItem('oe_menu_folded', this.folded.toString()); - } - }, - /** - * Opens a given menu by id, as if a user had browsed to that menu by hand - * except does not trigger any event on the way - * - * @param {Number} menu_id database id of the terminal menu to select - */ - open_menu: function (menu_id) { - this.$element.add(this.$secondary_menu).find('.active') - .removeClass('active'); - this.$secondary_menu.find('> .oe_secondary_menu').hide(); - - var $primary_menu; - var $secondary_submenu = this.$secondary_menu.find( - 'a[data-menu=' + menu_id +']'); - if ($secondary_submenu.length) { - for(;;) { - if ($secondary_submenu.hasClass('leaf')) { - $secondary_submenu.addClass('active'); - } else if ($secondary_submenu.hasClass('submenu')) { - $secondary_submenu.addClass('opened') - } - var $parent = $secondary_submenu.parent().show(); - if ($parent.hasClass('oe_secondary_menu')) { - var primary_id = $parent.data('menu-parent'); - $primary_menu = this.$element.find( - 'a[data-menu=' + primary_id + ']'); - break; - } - $secondary_submenu = $parent.prev(); - } - } else { - $primary_menu = this.$element.find('a[data-menu=' + menu_id + ']'); - } - if (!$primary_menu.length) { - return; - } - $primary_menu.addClass('active'); - this.$secondary_menu.find( - 'div[data-menu-parent=' + $primary_menu.data('menu') + ']').addClass('active').toggle(!this.folded); - }, - on_menu_click: function(ev, id) { - id = id || 0; - var $clicked_menu, manual = false; - - if (id) { - // We can manually activate a menu with it's id (for hash url mapping) - manual = true; - $clicked_menu = this.$element.find('a[data-menu=' + id + ']'); - if (!$clicked_menu.length) { - $clicked_menu = this.$secondary_menu.find('a[data-menu=' + id + ']'); - } - } else { - $clicked_menu = $(ev.currentTarget); - id = $clicked_menu.data('menu'); - } - - if (this.do_menu_click($clicked_menu, manual) && id) { - this.current_menu = id; - this.session.active_id = id; - this.rpc('/web/menu/action', {'menu_id': id}, this.on_menu_action_loaded); - } - if (ev) { - ev.stopPropagation(); - } - return false; - }, - do_menu_click: function($clicked_menu, manual) { - var $sub_menu, $main_menu, - active = $clicked_menu.is('.active'), - sub_menu_visible = false, - has_submenu_items = false; - - if (this.$secondary_menu.has($clicked_menu).length) { - $sub_menu = $clicked_menu.parents('.oe_secondary_menu'); - $main_menu = this.$element.find('a[data-menu=' + $sub_menu.data('menu-parent') + ']'); - } else { - $sub_menu = this.$secondary_menu.find('.oe_secondary_menu[data-menu-parent=' + $clicked_menu.attr('data-menu') + ']'); - $main_menu = $clicked_menu; - } - - sub_menu_visible = $sub_menu.is(':visible'); - has_submenu_items = !!$sub_menu.children().length; - this.$secondary_menu.find('.oe_secondary_menu').hide(); - - $('.active', this.$element.add(this.$secondary_menu)).removeClass('active'); - $main_menu.add($clicked_menu).add($sub_menu).addClass('active'); - - if (has_submenu_items) { - if (!(this.folded && manual)) { - this.do_show_secondary($sub_menu, $main_menu); - } else { - this.do_show_secondary(); - } - } - - if ($main_menu != $clicked_menu) { - if ($clicked_menu.is('.submenu')) { - $sub_menu.find('.submenu.opened').each(function() { - if (!$(this).next().has($clicked_menu).length && !$(this).is($clicked_menu)) { - $(this).removeClass('opened').next().hide(); - } - }); - $clicked_menu.toggleClass('opened').next().toggle(); - } else if ($clicked_menu.is('.leaf')) { - $sub_menu.toggle(!this.folded); - return true; - } - } else if (this.folded) { - if ((active && sub_menu_visible) || !has_submenu_items) { - $sub_menu.hide(); - return true; - } - return manual; - } else { - return true; - } - return false; - }, - do_hide_secondary: function() { - this.$secondary_menu.hide(); - }, - do_show_secondary: function($sub_menu, $main_menu) { - var self = this; - this.$secondary_menu.show(); - if (!arguments.length) { - return; - } - if (this.folded) { - var css = $main_menu.position(), - fold_width = this.$secondary_menu.width() + 2, - window_width = $(window).width(); - css.top += 33; - css.left -= Math.round(($sub_menu.width() - $main_menu.width()) / 2); - css.left = css.left < fold_width ? fold_width : css.left; - if ((css.left + $sub_menu.width()) > window_width) { - delete(css.left); - css.right = 1; - } - $sub_menu.css(css); - $sub_menu.mouseenter(function() { - clearTimeout($sub_menu.data('timeoutId')); - $sub_menu.data('timeoutId', null); - return false; - }).mouseleave(function(evt) { - var timeoutId = setTimeout(function() { - if (self.folded && $sub_menu.data('timeoutId')) { - $sub_menu.hide().unbind('mouseenter').unbind('mouseleave'); - } - }, self.float_timeout); - $sub_menu.data('timeoutId', timeoutId); - return false; + self.rpc("/web/webclient/version_info", {}).then(function(res) { + var $help = $(QWeb.render("About-Page", {version_info: res})); + $help.find('a.oe_activate_debug_mode').click(function (e) { + e.preventDefault(); + window.location = $.param.querystring( + window.location.href, 'debug'); }); - } - $sub_menu.show(); + openerp.web.dialog($help, {autoOpen: true, + modal: true, width: 960, title: _t("About")}); + }); }, - on_menu_action_loaded: function(data) { - var self = this; - if (data.action.length) { - var action = data.action[0][2]; - action.from_menu = true; - self.on_action(action); - } else { - self.on_action({type: 'null_action'}); - } - }, - on_action: function(action) { + on_menu_shortcut: function($link) { + var self = this, + id = $link.data('id'); + self.session.active_id = id; + self.rpc('/web/menu/action', {'menu_id': id}, function(ir_menu_data) { + if (ir_menu_data.action.length){ + self.on_action(ir_menu_data.action[0][2]); + } + }); } }); -openerp.web.WebClient = openerp.web.OldWidget.extend(/** @lends openerp.web.WebClient */{ +openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClient */{ /** * @constructs openerp.web.WebClient - * @extends openerp.web.OldWidget - * - * @param element_id + * @extends openerp.web.Widget */ init: function(parent) { var self = this; this._super(parent); openerp.webclient = this; - + this.querystring = '?' + jQuery.param.querystring(); this._current_state = null; }, start: function() { var self = this; - this.$element = $(document.body); + this.$element.addClass("openerp openerp2"); if (jQuery.param != undefined && jQuery.deparam(jQuery.param.querystring()).kitten != undefined) { this.$element.addClass("kitten-mode-activated"); this.$element.delegate('img.oe-record-edit-link-img', 'hover', function(e) { self.$element.toggleClass('clark-gable'); }); } - this.session.bind().then(function() { + this.session.bind_session().then(function() { if (!self.session.session_is_valid()) { self.show_login(); } }); this.session.on_session_valid.add(function() { self.show_application(); - - self.header.do_update(); + + self.user_menu.do_update(); self.menu.do_reload(); if(self.action_manager) - self.action_manager.stop(); + self.action_manager.destroy(); self.action_manager = new openerp.web.ActionManager(self); - self.action_manager.appendTo($("#oe_app")); + self.action_manager.appendTo(self.$element.find('.oe_application')); self.bind_hashchange(); var version_label = _t("OpenERP - Unsupported/Community Version"); if (!self.session.openerp_entreprise) { @@ -1103,6 +978,9 @@ openerp.web.WebClient = openerp.web.OldWidget.extend(/** @lends openerp.web.WebC document.title = version_label; } }); + this.$element.on('mouseenter', '.oe_systray > div:not([data-tipsy=true])', function() { + $(this).attr('data-tipsy', 'true').tipsy().trigger('mouseenter'); + }); }, show_login: function() { var self = this; @@ -1115,15 +993,15 @@ openerp.web.WebClient = openerp.web.OldWidget.extend(/** @lends openerp.web.WebC var self = this; this.destroy_content(); this.show_common(); - self.$table = $(QWeb.render("Interface", {})); + self.$table = $(QWeb.render("WebClient", {})); self.$element.append(self.$table); - self.header = new openerp.web.Header(self); - self.header.on_logout.add(this.proxy('on_logout')); - self.header.on_action.add(this.proxy('on_menu_action')); - self.header.appendTo($("#oe_header")); - self.menu = new openerp.web.Menu(self, "oe_menu", "oe_secondary_menu"); + self.menu = new openerp.web.Menu(self); + self.menu.replace(this.$element.find('.oe_menu_placeholder')); self.menu.on_action.add(this.proxy('on_menu_action')); - self.menu.start(); + self.user_menu = new openerp.web.UserMenu(self); + self.user_menu.replace(this.$element.find('.oe_user_menu_placeholder')); + self.user_menu.on_menu_logout.add(this.proxy('on_logout')); + self.user_menu.on_action.add(this.proxy('on_menu_action')); }, show_common: function() { var self = this; @@ -1144,8 +1022,8 @@ openerp.web.WebClient = openerp.web.OldWidget.extend(/** @lends openerp.web.WebC this.loading.appendTo(this.$element); }, destroy_content: function() { - _.each(_.clone(this.widget_children), function(el) { - el.stop(); + _.each(_.clone(this.getChildren()), function(el) { + el.destroy(); }); this.$element.children().remove(); }, @@ -1207,6 +1085,12 @@ openerp.web.WebClient = openerp.web.OldWidget.extend(/** @lends openerp.web.WebC self.menu.on_menu_click(null, action.menu_id); }); } + }, + set_content_full_screen: function(fullscreen) { + if (fullscreen) + $(".oe_webclient", this.$element).addClass("oe_content_full_screen"); + else + $(".oe_webclient", this.$element).removeClass("oe_content_full_screen"); } }); @@ -1250,7 +1134,7 @@ openerp.web.embed = function (origin, dbname, login, key, action, options) { var sc = document.getElementsByTagName('script'); currentScript = sc[sc.length-1]; } - openerp.connection.bind(origin).then(function () { + openerp.connection.bind_session(origin).then(function () { openerp.connection.session_authenticate(dbname, login, key, true).then(function () { var client = new openerp.web.EmbeddedClient(action, options); client.insertAfter(currentScript); diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js index a1d2d04f697..9bcf037fefc 100644 --- a/addons/web/static/src/js/core.js +++ b/addons/web/static/src/js/core.js @@ -10,110 +10,8 @@ if (!console.debug) { } openerp.web.core = function(openerp) { -/** - * John Resig Class with factory improvement - */ -(function() { - var initializing = false, - fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; - // The web Class implementation (does nothing) - /** - * Extended version of John Resig's Class pattern - * - * @class - */ - openerp.web.Class = function(){}; - /** - * Subclass an existing class - * - * @param {Object} prop class-level properties (class attributes and instance methods) to set on the new class - */ - openerp.web.Class.extend = function(prop) { - var _super = this.prototype; - - // Instantiate a web class (but only create the instance, - // don't run the init constructor) - initializing = true; - var prototype = new this(); - initializing = false; - - // Copy the properties over onto the new prototype - for (var name in prop) { - // Check if we're overwriting an existing function - prototype[name] = typeof prop[name] == "function" && - typeof _super[name] == "function" && - fnTest.test(prop[name]) ? - (function(name, fn) { - return function() { - var tmp = this._super; - - // Add a new ._super() method that is the same - // method but on the super-class - this._super = _super[name]; - - // The method only need to be bound temporarily, so - // we remove it when we're done executing - var ret = fn.apply(this, arguments); - this._super = tmp; - - return ret; - }; - })(name, prop[name]) : - prop[name]; - } - - // The dummy class constructor - function Class() { - // All construction is actually done in the init method - if (!initializing && this.init) { - var ret = this.init.apply(this, arguments); - if (ret) { return ret; } - } - return this; - } - Class.include = function (properties) { - for (var name in properties) { - if (typeof properties[name] !== 'function' - || !fnTest.test(properties[name])) { - prototype[name] = properties[name]; - } else if (typeof prototype[name] === 'function' - && prototype.hasOwnProperty(name)) { - prototype[name] = (function (name, fn, previous) { - return function () { - var tmp = this._super; - this._super = previous; - var ret = fn.apply(this, arguments); - this._super = tmp; - return ret; - } - })(name, properties[name], prototype[name]); - } else if (typeof _super[name] === 'function') { - prototype[name] = (function (name, fn) { - return function () { - var tmp = this._super; - this._super = _super[name]; - var ret = fn.apply(this, arguments); - this._super = tmp; - return ret; - } - })(name, properties[name]); - } - } - }; - - // Populate our constructed prototype object - Class.prototype = prototype; - - // Enforce the constructor to be what we expect - Class.constructor = Class; - - // And make this class extendable - Class.extend = arguments.callee; - - return Class; - }; -})(); +openerp.web.Class = nova.Class; openerp.web.callback = function(obj, method) { var callback = function() { @@ -174,31 +72,6 @@ openerp.web.callback = function(obj, method) { }); }; -/** - * Generates an inherited class that replaces all the methods by null methods (methods - * that does nothing and always return undefined). - * - * @param {Class} claz - * @param {Object} add Additional functions to override. - * @return {Class} - */ -openerp.web.generate_null_object_class = function(claz, add) { - var newer = {}; - var copy_proto = function(prototype) { - for (var name in prototype) { - if(typeof prototype[name] == "function") { - newer[name] = function() {}; - } - } - if (prototype.prototype) - copy_proto(prototype.prototype); - }; - copy_proto(claz.prototype); - newer.init = openerp.web.Widget.prototype.init; - var tmpclass = claz.extend(newer); - return tmpclass.extend(add || {}); -}; - /** * web error for lookup failure * @@ -362,11 +235,7 @@ openerp.web.Registry = openerp.web.Class.extend( /** @lends openerp.web.Registry } }); -openerp.web.CallbackEnabled = openerp.web.Class.extend(/** @lends openerp.web.CallbackEnabled# */{ - /** - * @constructs openerp.web.CallbackEnabled - * @extends openerp.web.Class - */ +openerp.web.CallbackEnabledMixin = { init: function() { // Transform on_* method into openerp.web.callbacks for (var name in this) { @@ -404,7 +273,14 @@ openerp.web.CallbackEnabled = openerp.web.Class.extend(/** @lends openerp.web.Ca return self[method_name].apply(self, arguments); } } -}); +}; + +openerp.web.CallbackEnabled = openerp.web.Class.extend(_.extend({}, nova.GetterSetterMixin, openerp.web.CallbackEnabledMixin, { + init: function() { + nova.GetterSetterMixin.init.call(this); + openerp.web.CallbackEnabledMixin.init.call(this); + } +})); openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp.web.Connection# */{ /** @@ -422,7 +298,7 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp. this.name = openerp._session_id; this.qweb_mutex = new $.Mutex(); }, - bind: function(origin) { + bind_session: function(origin) { var window_origin = location.protocol+"//"+location.host, self=this; this.origin = origin ? _.str.rtrim(origin,'/') : window_origin; this.prefix = this.origin; @@ -445,6 +321,269 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp. this.active_id = null; return this.session_init(); }, + test_eval_get_context: function () { + var asJS = function (arg) { + if (arg instanceof py.object) { + return arg.toJSON(); + } + return arg; + }; + + var datetime = new py.object(); + datetime.datetime = new py.type(function datetime() { + throw new Error('datetime.datetime not implemented'); + }); + var date = datetime.date = new py.type(function date(y, m, d) { + if (y instanceof Array) { + d = y[2]; + m = y[1]; + y = y[0]; + } + this.year = asJS(y); + this.month = asJS(m); + this.day = asJS(d); + }, py.object, { + strftime: function (args) { + var f = asJS(args[0]), self = this; + return new py.str(f.replace(/%([A-Za-z])/g, function (m, c) { + switch (c) { + case 'Y': return self.year; + case 'm': return _.str.sprintf('%02d', self.month); + case 'd': return _.str.sprintf('%02d', self.day); + } + throw new Error('ValueError: No known conversion for ' + m); + })); + } + }); + date.__getattribute__ = function (name) { + if (name === 'today') { + return date.today; + } + throw new Error("AttributeError: object 'date' has no attribute '" + name +"'"); + }; + date.today = new py.def(function () { + var d = new Date(); + return new date(d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate()); + }); + datetime.time = new py.type(function time() { + throw new Error('datetime.time not implemented'); + }); + + var time = new py.object(); + time.strftime = new py.def(function (args) { + return date.today.__call__().strftime(args); + }); + + var relativedelta = new py.type(function relativedelta(args, kwargs) { + if (!_.isEmpty(args)) { + throw new Error('Extraction of relative deltas from existing datetimes not supported'); + } + this.ops = kwargs; + }, py.object, { + __add__: function (other) { + if (!(other instanceof datetime.date)) { + return py.NotImplemented; + } + // TODO: test this whole mess + var year = asJS(this.ops.year) || asJS(other.year); + if (asJS(this.ops.years)) { + year += asJS(this.ops.years); + } + + var month = asJS(this.ops.month) || asJS(other.month); + if (asJS(this.ops.months)) { + month += asJS(this.ops.months); + // FIXME: no divmod in JS? + while (month < 1) { + year -= 1; + month += 12; + } + while (month > 12) { + year += 1; + month -= 12; + } + } + + var lastMonthDay = new Date(year, month, 0).getDate(); + var day = asJS(this.ops.day) || asJS(other.day); + if (day > lastMonthDay) { day = lastMonthDay; } + var days_offset = ((asJS(this.ops.weeks) || 0) * 7) + (asJS(this.ops.days) || 0); + if (days_offset) { + day = new Date(year, month-1, day + days_offset).getDate(); + } + // TODO: leapdays? + // TODO: hours, minutes, seconds? Not used in XML domains + // TODO: weekday? + return new datetime.date(year, month, day); + }, + __radd__: function (other) { + return this.__add__(other); + }, + + __sub__: function (other) { + if (!(other instanceof datetime.date)) { + return py.NotImplemented; + } + // TODO: test this whole mess + var year = asJS(this.ops.year) || asJS(other.year); + if (asJS(this.ops.years)) { + year -= asJS(this.ops.years); + } + + var month = asJS(this.ops.month) || asJS(other.month); + if (asJS(this.ops.months)) { + month -= asJS(this.ops.months); + // FIXME: no divmod in JS? + while (month < 1) { + year -= 1; + month += 12; + } + while (month > 12) { + year += 1; + month -= 12; + } + } + + var lastMonthDay = new Date(year, month, 0).getDate(); + var day = asJS(this.ops.day) || asJS(other.day); + if (day > lastMonthDay) { day = lastMonthDay; } + var days_offset = ((asJS(this.ops.weeks) || 0) * 7) + (asJS(this.ops.days) || 0); + if (days_offset) { + day = new Date(year, month-1, day - days_offset).getDate(); + } + // TODO: leapdays? + // TODO: hours, minutes, seconds? Not used in XML domains + // TODO: weekday? + return new datetime.date(year, month, day); + }, + __rsub__: function (other) { + return this.__sub__(other); + } + }); + + return { + uid: new py.float(this.uid), + datetime: datetime, + time: time, + relativedelta: relativedelta + }; + }, + /** + * FIXME: Huge testing hack, especially the evaluation context, rewrite + test for real before switching + */ + test_eval: function (source, expected) { + try { + var ctx = this.test_eval_contexts(source.contexts); + if (!_.isEqual(ctx, expected.context)) { + console.group('Local context does not match remote, nothing is broken but please report to R&D (xmo)'); + console.warn('source', source.contexts); + console.warn('local', ctx); + console.warn('remote', expected.context); + console.groupEnd(); + } + } catch (e) { + console.group('Failed to evaluate contexts, nothing is broken but please report to R&D (xmo)'); + console.error(e); + console.log('source', source.contexts); + console.groupEnd(); + } + + try { + var dom = this.test_eval_domains(source.domains, this.test_eval_get_context()); + if (!_.isEqual(dom, expected.domain)) { + console.group('Local domain does not match remote, nothing is broken but please report to R&D (xmo)'); + console.warn('source', source.domains); + console.warn('local', dom); + console.warn('remote', expected.domain); + console.groupEnd(); + } + } catch (e) { + console.group('Failed to evaluate domains, nothing is broken but please report to R&D (xmo)'); + console.error(e); + console.log('source', source.domains); + console.groupEnd(); + } + + try { + var groups = this.test_eval_groupby(source.group_by_seq); + if (!_.isEqual(groups, expected.group_by)) { + console.group('Local groupby does not match remote, nothing is broken but please report to R&D (xmo)'); + console.warn('source', source.group_by_seq); + console.warn('local', groups); + console.warn('remote', expected.group_by); + console.groupEnd(); + } + } catch (e) { + console.group('Failed to evaluate groupby, nothing is broken but please report to R&D (xmo)'); + console.error(e); + console.log('source', source.group_by_seq); + console.groupEnd(); + } + }, + test_eval_contexts: function (contexts) { + var result_context = _.extend({}, this.user_context), + self = this; + _(contexts).each(function (ctx) { + switch(ctx.__ref) { + case 'context': + _.extend(result_context, py.eval(ctx.__debug)); + break; + case 'compound_context': + _.extend( + result_context, self.test_eval_contexts(ctx.__contexts)); + break; + default: + _.extend(result_context, ctx); + } + }); + return result_context; + }, + test_eval_domains: function (domains, eval_context) { + var result_domain = [], self = this; + _(domains).each(function (dom) { + switch(dom.__ref) { + case 'domain': + result_domain.push.apply( + result_domain, py.eval(dom.__debug, eval_context)); + break; + case 'compound_domain': + result_domain.push.apply( + result_domain, self.test_eval_domains( + dom.__domains, eval_context)); + break; + default: + result_domain.push.apply( + result_domain, dom); + } + }); + return result_domain; + }, + test_eval_groupby: function (contexts) { + var result_group = [], self = this; + _(contexts).each(function (ctx) { + var group; + switch(ctx.__ref) { + case 'context': + group = py.eval(ctx.__debug).group_by; + break; + case 'compound_context': + group = self.test_eval_contexts(ctx.__contexts).group_by; + break; + default: + group = ctx.group_by + } + if (!group) { return; } + if (typeof group === 'string') { + result_group.push(group); + } else if (group instanceof Array) { + result_group.push.apply(result_group, group); + } else { + throw new Error('Got invalid groupby {{' + + JSON.stringify(group) + '}}'); + } + }); + return result_group; + }, /** * Executes an RPC call, registering the provided callbacks. * @@ -480,6 +619,9 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp. function (response, textStatus, jqXHR) { self.on_rpc_response(); if (!response.error) { + if (url.url === '/web/session/eval_domain_and_context') { + self.test_eval(params, response.result); + } deferred.resolve(response["result"], textStatus, jqXHR); } else if (response.error.data.type === "session_invalid") { self.uid = false; @@ -733,6 +875,14 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp. var file_list = ["/web/static/lib/datejs/globalization/" + lang.replace("_", "-") + ".js"]; return self.rpc('/web/webclient/jslist', {mods: to_load}).pipe(function(files) { return self.do_load_js(file_list.concat(files)); + }).then(function () { + if (!Date.CultureInfo.pmDesignator) { + // If no am/pm designator is specified but the openerp + // datetime format uses %i, date.js won't be able to + // correctly format a date. See bug#938497. + Date.CultureInfo.amDesignator = 'AM'; + Date.CultureInfo.pmDesignator = 'PM'; + } }); })) } @@ -873,9 +1023,12 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp. _(_.extend({}, options.data || {}, {session_id: this.session_id, token: token})) .each(function (value, key) { - $('') - .val(value) - .appendTo($form_data); + var $input = $form.find('[name=' + key +']'); + if (!$input.length) { + $input = $('') + .appendTo($form_data); + } + $input.val(value) }); $form @@ -958,11 +1111,11 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp. * * And of course, when you don't need that widget anymore, just do: * - * my_widget.stop(); + * my_widget.destroy(); * * That will kill the widget in a clean way and erase its content from the dom. */ -openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.Widget# */{ +openerp.web.Widget = nova.Widget.extend(_.extend({}, openerp.web.CallbackEnabledMixin, { /** * The name of the QWeb template that will be used for rendering. Must be * redefined in subclasses or the default render() method can not be used. @@ -970,11 +1123,6 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W * @type string */ template: null, - /** - * Tag name when creating a default $element. - * @type string - */ - tag_name: 'div', /** * Constructs the widget and sets its parent if a parent is given. * @@ -982,7 +1130,7 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W * @extends openerp.web.CallbackEnabled * * @param {openerp.web.Widget} parent Binds the current instance to the given Widget instance. - * When that widget is destroyed by calling stop(), the current instance will be + * When that widget is destroyed by calling destroy(), the current instance will be * destroyed too. Can be null. * @param {String} element_id Deprecated. Sets the element_id. Only useful when you want * to bind the current Widget to an already existing part of the DOM, which is not compatible @@ -990,132 +1138,24 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W * for new components this argument should not be provided any more. */ init: function(parent) { - this._super(); + this._super(parent); + openerp.web.CallbackEnabledMixin.init.call(this); this.session = openerp.connection; - - this.$element = $(document.createElement(this.tag_name)); - - this.widget_parent = parent; - this.widget_children = []; - if(parent && parent.widget_children) { - parent.widget_children.push(this); - } - // useful to know if the widget was destroyed and should not be used anymore - this.widget_is_stopped = false; }, /** - * Renders the current widget and appends it to the given jQuery object or Widget. - * - * @param target A jQuery object or a Widget instance. + * Renders the element. The default implementation renders the widget using QWeb, + * `this.template` must be defined. The context given to QWeb contains the "widget" + * key that references `this`. */ - appendTo: function(target) { - var self = this; - return this._render_and_insert(function(t) { - self.$element.appendTo(t); - }, target); - }, - /** - * Renders the current widget and prepends it to the given jQuery object or Widget. - * - * @param target A jQuery object or a Widget instance. - */ - prependTo: function(target) { - var self = this; - return this._render_and_insert(function(t) { - self.$element.prependTo(t); - }, target); - }, - /** - * Renders the current widget and inserts it after to the given jQuery object or Widget. - * - * @param target A jQuery object or a Widget instance. - */ - insertAfter: function(target) { - var self = this; - return this._render_and_insert(function(t) { - self.$element.insertAfter(t); - }, target); - }, - /** - * Renders the current widget and inserts it before to the given jQuery object or Widget. - * - * @param target A jQuery object or a Widget instance. - */ - insertBefore: function(target) { - var self = this; - return this._render_and_insert(function(t) { - self.$element.insertBefore(t); - }, target); - }, - /** - * Renders the current widget and replaces the given jQuery object. - * - * @param target A jQuery object or a Widget instance. - */ - replace: function(target) { - return this._render_and_insert(_.bind(function(t) { - this.$element.replaceAll(t); - }, this), target); - }, - _render_and_insert: function(insertion, target) { - this.render_element(); - if (target instanceof openerp.web.Widget) - target = target.$element; - insertion(target); - this.on_inserted(this.$element, this); - return this.start(); - }, - on_inserted: function(element, widget) {}, - /** - * Renders the element and insert the result of the render() method in this.$element. - */ - render_element: function() { - var rendered = this.render(); - if (rendered) { + renderElement: function() { + var rendered = null; + if (this.template) + rendered = openerp.web.qweb.render(this.template, {widget: this}); + if (_.str.trim(rendered)) { var elem = $(rendered); this.$element.replaceWith(elem); this.$element = elem; } - return this; - }, - /** - * Renders the widget using QWeb, `this.template` must be defined. - * The context given to QWeb contains the "widget" key that references `this`. - * - * @param {Object} additional Additional context arguments to pass to the template. - */ - render: function (additional) { - if (this.template) - return openerp.web.qweb.render(this.template, _.extend({widget: this}, additional || {})); - return null; - }, - /** - * Method called after rendering. Mostly used to bind actions, perform asynchronous - * calls, etc... - * - * By convention, the method should return a promise to inform the caller when - * this widget has been initialized. - * - * @returns {jQuery.Deferred} - */ - start: function() { - return $.Deferred().done().promise(); - }, - /** - * Destroys the current widget, also destroys all its children before destroying itself. - */ - stop: function() { - _.each(_.clone(this.widget_children), function(el) { - el.stop(); - }); - if(this.$element != null) { - this.$element.remove(); - } - if (this.widget_parent && this.widget_parent.widget_children) { - this.widget_parent.widget_children = _.without(this.widget_parent.widget_children, this); - } - this.widget_parent = null; - this.widget_is_stopped = true; }, /** * Informs the action manager to do an action. This supposes that @@ -1123,37 +1163,36 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W * If that's not the case this method will simply return `false`. */ do_action: function(action, on_finished) { - if (this.widget_parent) { - return this.widget_parent.do_action(action, on_finished); + if (this.getParent()) { + return this.getParent().do_action(action, on_finished); } return false; }, do_notify: function() { - if (this.widget_parent) { - return this.widget_parent.do_notify.apply(this,arguments); + if (this.getParent()) { + return this.getParent().do_notify.apply(this,arguments); } return false; }, do_warn: function() { - if (this.widget_parent) { - return this.widget_parent.do_warn.apply(this,arguments); + if (this.getParent()) { + return this.getParent().do_warn.apply(this,arguments); } return false; }, - rpc: function(url, data, success, error) { var def = $.Deferred().then(success, error); var self = this; openerp.connection.rpc(url, data). then(function() { - if (!self.widget_is_stopped) + if (!self.isDestroyed()) def.resolve.apply(def, arguments); }, function() { - if (!self.widget_is_stopped) + if (!self.isDestroyed()) def.reject.apply(def, arguments); }); return def.promise(); } -}); +})); /** * @deprecated use :class:`openerp.web.Widget` @@ -1164,7 +1203,21 @@ openerp.web.OldWidget = openerp.web.Widget.extend({ this.element_id = element_id; this.element_id = this.element_id || _.uniqueId('widget-'); var tmp = document.getElementById(this.element_id); - this.$element = tmp ? $(tmp) : $(document.createElement(this.tag_name)); + this.$element = tmp ? $(tmp) : $(document.createElement(this.tagName)); + }, + renderElement: function() { + var rendered = this.render(); + if (rendered) { + var elem = $(rendered); + this.$element.replaceWith(elem); + this.$element = elem; + } + return this; + }, + render: function (additional) { + if (this.template) + return openerp.web.qweb.render(this.template, _.extend({widget: this}, additional || {})); + return null; } }); @@ -1196,7 +1249,7 @@ openerp.web.TranslationDataBase = openerp.web.Class.extend(/** @lends openerp.we if (translation_bundle.lang_parameters) { this.parameters = translation_bundle.lang_parameters; this.parameters.grouping = py.eval( - this.parameters.grouping).toJSON(); + this.parameters.grouping); } }, add_module_translation: function(mod) { @@ -1244,7 +1297,7 @@ openerp.web._lt = function (s) { return {toString: function () { return openerp.web._t(s); }} }; openerp.web.qweb = new QWeb2.Engine(); -openerp.web.qweb.debug = (window.location.search.indexOf('?debug') !== -1); +openerp.web.qweb.debug = ($.deparam($.param.querystring()).debug != undefined); openerp.web.qweb.default_dict = { '_' : _, '_t' : openerp.web._t @@ -1279,6 +1332,23 @@ openerp.web.qweb.preprocess_node = function() { } }; +/** + * A small utility function to check if a class implements correctly an interface, assuming that + * interface is simply specified using a dictionary containing methods and attributes with the + * correct type. It only performs the check when in debug mode and the only effect of an invalid + * check is messages in the console. + */ +openerp.web.check_interface = function(_class, _interface) { + if (! openerp.web.check_interface.debug) + return; + for (var member in _interface) { + if ( (typeof _class.prototype[member] != typeof _interface[member]) ) { + console.error("class failed to implement interface member '" + member + "'"); + } + } +} +openerp.web.check_interface.debug = ($.deparam($.param.querystring()).debug != undefined); + /** Jquery extentions */ $.Mutex = (function() { function Mutex() { diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index b3ed5b08280..a29a9c5ad36 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -1012,18 +1012,25 @@ openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({ : (v1 > v2) ? 1 : 0; }; - records.sort(function (a, b) { - return _.reduce(sort_fields, function (acc, field) { - if (acc) { return acc; } - - var sign = 1; - if (field[0] === '-') { - sign = -1; - field = field.slice(1); - } - return sign * compare(a[field], b[field]); - }, 0); - }); + // Array.sort is not necessarily stable. We must be careful with this because + // sorting an array where all items are considered equal is a worst-case that + // will randomize the array with an unstable sort! Therefore we must avoid + // sorting if there are no sort_fields (i.e. all items are considered equal) + // See also: http://ecma262-5.com/ELS5_Section_15.htm#Section_15.4.4.11 + // http://code.google.com/p/v8/issues/detail?id=90 + if (sort_fields.length) { + records.sort(function (a, b) { + return _.reduce(sort_fields, function (acc, field) { + if (acc) { return acc; } + var sign = 1; + if (field[0] === '-') { + sign = -1; + field = field.slice(1); + } + return sign * compare(a[field], b[field]); + }, 0); + }); + } completion.resolve(records); }; if(to_get.length > 0) { diff --git a/addons/web/static/src/js/data_import.js b/addons/web/static/src/js/data_import.js index 83eea2cccbb..3054a7784c4 100644 --- a/addons/web/static/src/js/data_import.js +++ b/addons/web/static/src/js/data_import.js @@ -66,11 +66,11 @@ openerp.web.DataImport = openerp.web.Dialog.extend({ this._super(); this.open({ buttons: [ - {text: _t("Close"), click: function() { self.stop(); }}, + {text: _t("Close"), click: function() { self.destroy(); }}, {text: _t("Import File"), click: function() { self.do_import(); }, 'class': 'oe-dialog-import-button'} ], close: function(event, ui) { - self.stop(); + self.destroy(); } }); this.toggle_import_button(false); @@ -151,7 +151,7 @@ openerp.web.DataImport = openerp.web.Dialog.extend({ }); }, toggle_import_button: function (newstate) { - this.$element.dialog('widget') + openerp.web.dialog(this.$element, 'widget') .find('.oe-dialog-import-button') .button('option', 'disabled', !newstate); }, @@ -201,10 +201,10 @@ openerp.web.DataImport = openerp.web.Dialog.extend({ return; } if (results['success']) { - if (this.widget_parent.widget_parent.active_view == "list") { - this.widget_parent.reload_content(); + if (this.getParent().getParent().active_view == "list") { + this.getParent().reload_content(); } - this.stop(); + this.destroy(); return; } @@ -358,7 +358,7 @@ openerp.web.DataImport = openerp.web.Dialog.extend({ } return true; }, - stop: function() { + destroy: function() { this.$element.remove(); this._super(); } diff --git a/addons/web/static/src/js/formats.js b/addons/web/static/src/js/formats.js index 4fb576e4a90..53863e63e97 100644 --- a/addons/web/static/src/js/formats.js +++ b/addons/web/static/src/js/formats.js @@ -148,7 +148,7 @@ openerp.web.format_value = function (value, descriptor, value_if_empty) { if (typeof(value) == "string") value = openerp.web.auto_str_to_date(value); return value.toString(normalize_format(l10n.time_format)); - case 'selection': + case 'selection': case 'statusbar': // Each choice is [value, label] if(_.isArray(value)) { value = value[0] @@ -336,7 +336,7 @@ openerp.web.format_cell = function (row_data, column, options) { case 'progressbar': return _.template( '<%-value%>%', { - value: row_data[column.id].value + value: _.str.sprintf("%.0f", row_data[column.id].value || 0) }); } diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index b1ee33c4125..7263aa948e2 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -32,6 +32,8 @@ openerp.web.SearchView = openerp.web.OldWidget.extend(/** @lends openerp.web.Sea this.hidden = !!hidden; this.headless = this.hidden && !this.has_defaults; + this.filter_data = {}; + this.ready = $.Deferred(); }, start: function() { @@ -232,7 +234,7 @@ openerp.web.SearchView = openerp.web.OldWidget.extend(/** @lends openerp.web.Sea context.add({"group_by": groupbys}); var dial_html = QWeb.render("SearchView.managed-filters.add"); var $dial = $(dial_html); - $dial.dialog({ + openerp.web.dialog($dial, { modal: true, title: _t("Filter Entry"), buttons: [ @@ -263,10 +265,20 @@ openerp.web.SearchView = openerp.web.OldWidget.extend(/** @lends openerp.web.Sea var filter = this.managed_filters[val]; this.do_clear(false).then(_.bind(function() { select.val('get:' + val); - var groupbys = _.map(filter.context.group_by.split(","), function(el) { - return {"group_by": el}; - }); - this.on_search([filter.domain], [filter.context], groupbys); + + var groupbys = []; + var group_by = filter.context.group_by; + if (group_by) { + groupbys = _.map( + group_by instanceof Array ? group_by : group_by.split(','), + function (el) { return { group_by: el }; }); + } + this.filter_data = { + domains: [filter.domain], + contexts: [filter.context], + groupbys: groupbys + }; + this.do_search(); }, this)); } else { select.val(''); @@ -281,7 +293,7 @@ openerp.web.SearchView = openerp.web.OldWidget.extend(/** @lends openerp.web.Sea selected_menu_id : menu.$element.find('a.active').data('menu') })); $dialog.find('input').val(this.fields_view.name); - $dialog.dialog({ + openerp.web.dialog($dialog, { modal: true, title: _t("Add to Dashboard"), buttons: [ @@ -303,10 +315,10 @@ openerp.web.SearchView = openerp.web.OldWidget.extend(/** @lends openerp.web.Sea }); self.rpc('/web/searchview/add_to_dashboard', { menu_id: menu_id, - action_id: self.widget_parent.action.id, + action_id: self.getParent().action.id, context_to_save: context, domain: domain, - view_mode: self.widget_parent.active_view, + view_mode: self.getParent().active_view, name: title }, function(r) { if (r === false) { @@ -334,9 +346,6 @@ openerp.web.SearchView = openerp.web.OldWidget.extend(/** @lends openerp.web.Sea if (this.headless && !this.has_defaults) { return this.on_search([], [], []); } - // reset filters management - var select = this.$element.find(".oe_search-view-filters-management"); - select.val("_filters"); if (e && e.preventDefault) { e.preventDefault(); } @@ -380,6 +389,16 @@ openerp.web.SearchView = openerp.web.OldWidget.extend(/** @lends openerp.web.Sea .map(function (filter) { return filter.get_context();}) .compact() .value(); + + if (this.filter_data.contexts) { + contexts = this.filter_data.contexts.concat(contexts) + } + if (this.filter_data.domains) { + domains = this.filter_data.domains.concat(domains); + } + if (this.filter_data.groupbys) { + groupbys = this.filter_data.groupbys.concat(groupbys); + } return {domains: domains, contexts: contexts, errors: errors, groupbys: groupbys}; }, /** @@ -418,6 +437,9 @@ openerp.web.SearchView = openerp.web.OldWidget.extend(/** @lends openerp.web.Sea * @param {Boolean} [reload_view=true] */ do_clear: function (reload_view) { + this.filter_data = {}; + this.$element.find(".oe_search-view-filters-management").val(''); + this.$element.find('.filter_label, .filter_icon').removeClass('enabled'); this.enabled_filters.splice(0); var string = $('a.searchview_group_string'); @@ -552,7 +574,7 @@ openerp.web.search.Widget = openerp.web.OldWidget.extend( /** @lends openerp.web * "Stops" the widgets. Called when the view destroys itself, this * lets the widgets clean up after themselves. */ - stop: function () { + destroy: function () { delete this.view; this._super(); }, @@ -1114,7 +1136,7 @@ openerp.web.search.ExtendedSearch = openerp.web.search.Input.extend({ if(this.$element.closest("table.oe-searchview-render-line").css("display") == "none") { return null; } - return _.reduce(this.widget_children, + return _.reduce(this.getChildren(), function(mem, x) { return mem.concat(x.get_domain());}, []); }, on_activate: function() { @@ -1133,9 +1155,9 @@ openerp.web.search.ExtendedSearch = openerp.web.search.Input.extend({ } }, check_last_element: function() { - _.each(this.widget_children, function(x) {x.set_last_group(false);}); - if (this.widget_children.length >= 1) { - this.widget_children[this.widget_children.length - 1].set_last_group(true); + _.each(this.getChildren(), function(x) {x.set_last_group(false);}); + if (this.getChildren().length >= 1) { + this.getChildren()[this.getChildren().length - 1].set_last_group(true); } } }); @@ -1148,7 +1170,7 @@ openerp.web.search.ExtendedSearchGroup = openerp.web.OldWidget.extend({ }, add_prop: function() { var prop = new openerp.web.search.ExtendedSearchProposition(this, this.fields); - var render = prop.render({'index': this.widget_children.length - 1}); + var render = prop.render({'index': this.getChildren().length - 1}); this.$element.find('.searchview_extended_propositions_list').append(render); prop.start(); }, @@ -1159,11 +1181,11 @@ openerp.web.search.ExtendedSearchGroup = openerp.web.OldWidget.extend({ _this.add_prop(); }); this.$element.find('.searchview_extended_delete_group').click(function () { - _this.stop(); + _this.destroy(); }); }, get_domain: function() { - var props = _(this.widget_children).chain().map(function(x) { + var props = _(this.getChildren()).chain().map(function(x) { return x.get_proposition(); }).compact().value(); var choice = this.$element.find(".searchview_extended_group_choice").val(); @@ -1172,10 +1194,10 @@ openerp.web.search.ExtendedSearchGroup = openerp.web.OldWidget.extend({ _.map(_.range(_.max([0,props.length - 1])), function() { return op; }), props); }, - stop: function() { - var parent = this.widget_parent; - if (this.widget_parent.widget_children.length == 1) - this.widget_parent.hide(); + destroy: function() { + var parent = this.getParent(); + if (this.getParent().getChildren().length == 1) + this.getParent().hide(); this._super(); parent.check_last_element(); }, @@ -1210,16 +1232,16 @@ openerp.web.search.ExtendedSearchProposition = openerp.web.OldWidget.extend(/** _this.changed(); }); this.$element.find('.searchview_extended_delete_prop').click(function () { - _this.stop(); + _this.destroy(); }); }, - stop: function() { + destroy: function() { var parent; - if (this.widget_parent.widget_children.length == 1) - parent = this.widget_parent; + if (this.getParent().getChildren().length == 1) + parent = this.getParent(); this._super(); if (parent) - parent.stop(); + parent.destroy(); }, changed: function() { var nval = this.$element.find(".searchview_extended_prop_field").val(); @@ -1235,7 +1257,7 @@ openerp.web.search.ExtendedSearchProposition = openerp.web.OldWidget.extend(/** select_field: function(field) { var self = this; if(this.attrs.selected != null) { - this.value.stop(); + this.value.destroy(); this.value = null; this.$element.find('.searchview_extended_prop_op').html(''); } diff --git a/addons/web/static/src/js/view_editor.js b/addons/web/static/src/js/view_editor.js index 0258509f172..2c0dc3d70b4 100644 --- a/addons/web/static/src/js/view_editor.js +++ b/addons/web/static/src/js/view_editor.js @@ -1002,10 +1002,10 @@ openerp.web.ViewEditor = openerp.web.OldWidget.extend({ $.when(action_manager.do_action(action)).then(function() { var controller = action_manager.dialog_viewmanager.views['form'].controller; controller.on_button_cancel.add_last(function(){ - action_manager.stop() + action_manager.destroy() }); controller.do_save.add_last(function(){ - action_manager.stop(); + action_manager.destroy(); var value =controller.fields.name.value; self.add_node_dialog.$element.find('select[id=field_value]').append($("").attr("value",value).text(value)); _.detect(self.add_widget,function(widget){ diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 2a678bee393..7808c646a43 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -74,13 +74,13 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# }, this.on_loaded); } }, - stop: function() { + destroy: function() { if (this.sidebar) { - this.sidebar.attachments.stop(); - this.sidebar.stop(); + this.sidebar.attachments.destroy(); + this.sidebar.destroy(); } _.each(this.widgets, function(w) { - w.stop(); + w.destroy(); }); this._super(); }, @@ -90,17 +90,23 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# }, on_loaded: function(data) { var self = this; - if (data) { - this.fields_order = []; - this.fields_view = data; - var frame = new (this.registry.get_object('frame'))(this, this.fields_view.arch); - - this.rendered = QWeb.render(this.form_template, { 'frame': frame, 'widget': this }); + if (!data) { + throw "No data provided."; } + if (this.root_frame) { + throw "Form view does not support multiple calls to on_loaded"; + } + this.fields_order = []; + this.fields_view = data; + + this.rendered = QWeb.render(this.form_template, {'widget': this}); this.$element.html(this.rendered); - _.each(this.widgets, function(w) { - w.start(); - }); + + this.root_frame = instanciate_widget(this.registry.get_object('frame'), this, this.fields_view.arch); + var to_append = $(".oe_form_header", this.$element); + this.root_frame.appendTo(to_append.length > 0 ? to_append : this.$element); + this.root_frame.$element.children().unwrap(); + this.$form_header = this.$element.find('.oe_form_header:first'); this.$form_header.find('div.oe_form_pager button[data-pager-action]').click(function() { var action = $(this).data('pager-action'); @@ -205,7 +211,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# if (self.sidebar) { self.sidebar.attachments.do_update(); } - if (self.default_focus_field && !self.embedded_view) { + if (self.default_focus_field) { self.default_focus_field.focus(); } if (record.id) { @@ -418,7 +424,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# this.on_form_changed(); } if (!_.isEmpty(result.warning)) { - $(QWeb.render("CrashManagerWarning", result.warning)).dialog({ + openerp.web.dialog($(QWeb.render("CrashManagerWarning", result.warning)), { modal: true, buttons: [ {text: _t("Ok"), click: function() { $(this).dialog("close"); }} @@ -879,7 +885,7 @@ openerp.web.form.compute_domain = function(expr, fields) { }; openerp.web.form.Widget = openerp.web.OldWidget.extend(/** @lends openerp.web.form.Widget# */{ - template: 'Widget', + form_template: 'Widget', /** * @constructs openerp.web.form.Widget * @extends openerp.web.OldWidget @@ -894,13 +900,9 @@ openerp.web.form.Widget = openerp.web.OldWidget.extend(/** @lends openerp.web.fo this.always_invisible = (this.modifiers.invisible && this.modifiers.invisible === true); this.type = this.type || node.tag; this.element_name = this.element_name || this.type; - this.element_class = [ - 'formview', this.view.view_id, this.element_name, - this.view.widgets_counter++].join("_"); this._super(view); - this.view.widgets[this.element_class] = this; this.children = node.children; this.colspan = parseInt(node.attrs.colspan || 1, 10); this.decrease_max_width = 0; @@ -919,14 +921,9 @@ openerp.web.form.Widget = openerp.web.OldWidget.extend(/** @lends openerp.web.fo this.align = 'center'; } - this.width = this.node.attrs.width; }, - start: function() { - this.$element = this.view.$element.find( - '.' + this.element_class.replace(/[^\r\n\f0-9A-Za-z_-]/g, "\\$&")); - }, - stop: function() { + destroy: function() { this._super.apply(this, arguments); $.fn.tipsy.clear(); }, @@ -939,9 +936,8 @@ openerp.web.form.Widget = openerp.web.OldWidget.extend(/** @lends openerp.web.fo update_dom: function() { this.$element.toggle(!this.invisible); }, - render: function() { - var template = this.template; - return QWeb.render(template, { "widget": this }); + renderElement: function() { + this.$element.html(QWeb.render(this.form_template, { "widget": this })); }, do_attach_tooltip: function(widget, trigger, options) { widget = widget || this; @@ -951,7 +947,7 @@ openerp.web.form.Widget = openerp.web.OldWidget.extend(/** @lends openerp.web.fo delayOut: 0, fade: true, title: function() { - var template = widget.template + '.tooltip'; + var template = widget.form_template + '.tooltip'; if (!QWeb.has_template(template)) { template = 'WidgetLabel.tooltip'; } @@ -1016,7 +1012,7 @@ openerp.web.form.Widget = openerp.web.OldWidget.extend(/** @lends openerp.web.fo }); openerp.web.form.WidgetFrame = openerp.web.form.Widget.extend({ - template: 'WidgetFrame', + form_template: 'WidgetFrame', init: function(view, node) { this._super(view, node); this.columns = parseInt(node.attrs.col || 4, 10); @@ -1034,6 +1030,23 @@ openerp.web.form.WidgetFrame = openerp.web.form.Widget.extend({ } this.set_row_cells_with(this.table[this.table.length - 1]); }, + renderElement: function() { + this._super(); + var self = this; + _.each(this.table, function(row) { + _.each(row, function(td) { + td.$element = self.$element.find('.' + td.element_class); + td.renderElement(); + }); + }); + }, + start: function() { + _.each(this.table, function(row) { + _.each(row, function(td) { + td.start(); + }); + }); + }, add_row: function(){ if (this.table.length) { this.set_row_cells_with(this.table[this.table.length - 1]); @@ -1081,14 +1094,14 @@ openerp.web.form.WidgetFrame = openerp.web.form.Widget.extend({ node.attrs.nolabel = '1'; } } - var widget = new (this.view.registry.get_any( - [node.attrs.widget, type.type, node.tag])) (this.view, node); + var widget = instanciate_widget(this.view.registry.get_any( + [node.attrs.widget, type.type, node.tag]), this.view, node); if (node.tag == 'field') { if (!this.view.default_focus_field || node.attrs.default_focus == '1') { this.view.default_focus_field = widget; } if (node.attrs.nolabel != '1') { - var label = new (this.view.registry.get_object('label')) (this.view, node); + var label = instanciate_widget(this.view.registry.get_object('label'), this.view, node); label["for"] = widget; this.add_widget(label, widget.colspan + 1); } @@ -1110,23 +1123,31 @@ openerp.web.form.WidgetFrame = openerp.web.form.Widget.extend({ }); openerp.web.form.WidgetGroup = openerp.web.form.WidgetFrame.extend({ - template: 'WidgetGroup' + form_template: 'WidgetGroup' }), openerp.web.form.WidgetNotebook = openerp.web.form.Widget.extend({ - template: 'WidgetNotebook', + form_template: 'WidgetNotebook', init: function(view, node) { this._super(view, node); this.pages = []; for (var i = 0; i < node.children.length; i++) { var n = node.children[i]; if (n.tag == "page") { - var page = new (this.view.registry.get_object('notebookpage'))( + var page = instanciate_widget(this.view.registry.get_object('notebookpage'), this.view, n, this, this.pages.length); this.pages.push(page); } } }, + renderElement: function() { + this._super(); + var self = this; + _.each(this.pages, function(page) { + page.$element = self.$element.find('.' + page.element_class); + page.renderElement(); + }); + }, start: function() { var self = this; this._super.apply(this, arguments); @@ -1146,6 +1167,9 @@ openerp.web.form.WidgetNotebook = openerp.web.form.Widget.extend({ gravity: 's' }); } + _.each(this.pages, function(page) { + page.start(); + }); }, do_select_first_visible_tab: function() { for (var i = 0; i < this.pages.length; i++) { @@ -1159,7 +1183,7 @@ openerp.web.form.WidgetNotebook = openerp.web.form.Widget.extend({ }); openerp.web.form.WidgetNotebookPage = openerp.web.form.WidgetFrame.extend({ - template: 'WidgetNotebookPage', + form_template: 'WidgetNotebookPage', init: function(view, node, notebook, index) { this.notebook = notebook; this.index = index; @@ -1181,7 +1205,7 @@ openerp.web.form.WidgetNotebookPage = openerp.web.form.WidgetFrame.extend({ }); openerp.web.form.WidgetSeparator = openerp.web.form.Widget.extend({ - template: 'WidgetSeparator', + form_template: 'WidgetSeparator', init: function(view, node) { this._super(view, node); this.orientation = node.attrs.orientation || 'horizontal'; @@ -1193,7 +1217,7 @@ openerp.web.form.WidgetSeparator = openerp.web.form.Widget.extend({ }); openerp.web.form.WidgetButton = openerp.web.form.Widget.extend({ - template: 'WidgetButton', + form_template: 'WidgetButton', init: function(view, node) { this._super(view, node); this.force_disabled = false; @@ -1227,7 +1251,7 @@ openerp.web.form.WidgetButton = openerp.web.form.Widget.extend({ var exec_action = function() { if (self.node.attrs.confirm) { var def = $.Deferred(); - var dialog = $('
    ' + self.node.attrs.confirm + '
    ').dialog({ + var dialog = openerp.web.dialog($('
    ' + self.node.attrs.confirm + '
    '), { title: _t('Confirm'), modal: true, buttons: [ @@ -1283,7 +1307,7 @@ openerp.web.form.WidgetButton = openerp.web.form.Widget.extend({ }); openerp.web.form.WidgetLabel = openerp.web.form.Widget.extend({ - template: 'WidgetLabel', + form_template: 'WidgetLabel', init: function(view, node) { this.element_name = 'label_' + node.attrs.name; @@ -1295,7 +1319,7 @@ openerp.web.form.WidgetLabel = openerp.web.form.Widget.extend({ } if (this.node.tag == 'label' && (this.align === 'left' || this.node.attrs.colspan || (this.string && this.string.length > 32))) { - this.template = "WidgetParagraph"; + this.form_template = "WidgetParagraph"; this.colspan = parseInt(this.node.attrs.colspan || 1, 10); // Widgets default to right-aligned, but paragraph defaults to // left-aligned @@ -1311,12 +1335,15 @@ openerp.web.form.WidgetLabel = openerp.web.form.Widget.extend({ this.nowrap = true; } }, - render: function () { + renderElement: function() { + var rendered; if (this['for'] && this.type !== 'label') { - return QWeb.render(this.template, {widget: this['for']}); + rendered = QWeb.render(this.form_template, {widget: this['for']}); + } else { + // Actual label widgets should not have a false and have type label + rendered = QWeb.render(this.form_template, {widget: this}); } - // Actual label widgets should not have a false and have type label - return QWeb.render(this.template, {widget: this}); + this.$element.html(rendered); }, start: function() { this._super(); @@ -1332,6 +1359,58 @@ openerp.web.form.WidgetLabel = openerp.web.form.Widget.extend({ } }); +/** + * Interface to be implemented by fields. + * + * Novajs Attributes: + * - ... + * + * Novajs Events: + * - ... + * + */ +openerp.web.form.FieldInterface = { + /** + * Called by the form view to indicate the value of the field. + * + * set_value() may return an object that can be passed to $.when() that represents the moment when + * the field has finished all operations necessary before the user can effectively use the widget. + * + * Multiple calls to set_value() can occur at any time and must be handled correctly by the implementation, + * regardless of any asynchronous operation currently running and the status of any promise that a + * previous call to set_value() could have returned. + * + * set_value() must be able, at any moment, to handle the syntax returned by the "read" method of the + * osv class in the OpenERP server as well as the syntax used by the set_value() (see below). It must + * also be able to handle any other format commonly used in the _defaults key on the models in the addons + * as well as any format commonly returned in a on_change. It must be able to autodetect those formats as + * no information is ever given to know which format is used. + */ + set_value: function(value) {}, + /** + * Get the current value of the widget. + * + * Must always return a syntaxically correct value to be passed to the "write" method of the osv class in + * the OpenERP server, although it is not assumed to respect the constraints applied to the field. + * For example if the field is marqued as "required", a call to get_value() can return false. + * + * get_value() can also be called *before* a call to set_value() and, in that case, is supposed to + * return a defaut value according to the type of field. + * + * This method is always assumed to perform synchronously, it can not return a promise. + * + * If there was no user interaction to modify the value of the field, it is always assumed that + * get_value() return the same semantic value than the one passed in the last call to set_value(), + * altough the syntax can be different. This can be the case for type of fields that have a different + * syntax for "read" and "write" (example: m2o: set_value([0, "Administrator"]), get_value() => 0). + */ + get_value: function() {}, +}; + +/** + * Abstract class for classes implementing FieldInterface. Should be renamed to AbstractField some + * day. + */ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.form.Field# */{ /** * @constructs openerp.web.form.Field @@ -1448,7 +1527,7 @@ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.f }); openerp.web.form.FieldChar = openerp.web.form.Field.extend({ - template: 'FieldChar', + form_template: 'FieldChar', init: function (view, node) { this._super(view, node); this.password = this.node.attrs.password === 'True' || this.node.attrs.password === '1'; @@ -1493,7 +1572,7 @@ openerp.web.form.FieldID = openerp.web.form.FieldChar.extend({ }); openerp.web.form.FieldEmail = openerp.web.form.FieldChar.extend({ - template: 'FieldEmail', + form_template: 'FieldEmail', start: function() { this._super.apply(this, arguments); this.$element.find('button').click(this.on_button_clicked); @@ -1508,7 +1587,7 @@ openerp.web.form.FieldEmail = openerp.web.form.FieldChar.extend({ }); openerp.web.form.FieldUrl = openerp.web.form.FieldChar.extend({ - template: 'FieldUrl', + form_template: 'FieldUrl', start: function() { this._super.apply(this, arguments); this.$element.find('button').click(this.on_button_clicked); @@ -1526,16 +1605,11 @@ openerp.web.form.FieldFloat = openerp.web.form.FieldChar.extend({ init: function (view, node) { this._super(view, node); if (node.attrs.digits) { - this.parse_digits(node.attrs.digits); + this.digits = py.eval(node.attrs.digits).toJSON(); } else { this.digits = view.fields_view.fields[node.attrs.name].digits; } }, - parse_digits: function (digits_attr) { - // could use a Python parser instead. - var match = /^\s*[\(\[](\d+),\s*(\d+)/.exec(digits_attr); - return [parseInt(match[1], 10), parseInt(match[2], 10)]; - }, set_value: function(value) { if (value === false || value === undefined) { // As in GTK client, floats default to 0 @@ -1631,7 +1705,7 @@ openerp.web.DateWidget = openerp.web.DateTimeWidget.extend({ }); openerp.web.form.FieldDatetime = openerp.web.form.Field.extend({ - template: "EmptyComponent", + form_template: "EmptyComponent", build_widget: function() { return new openerp.web.DateTimeWidget(this); }, @@ -1668,7 +1742,7 @@ openerp.web.form.FieldDate = openerp.web.form.FieldDatetime.extend({ }); openerp.web.form.FieldText = openerp.web.form.Field.extend({ - template: 'FieldText', + form_template: 'FieldText', start: function() { this._super.apply(this, arguments); this.$element.find('textarea').change(this.on_ui_change); @@ -1729,7 +1803,7 @@ openerp.web.form.FieldText = openerp.web.form.Field.extend({ }); openerp.web.form.FieldBoolean = openerp.web.form.Field.extend({ - template: 'FieldBoolean', + form_template: 'FieldBoolean', start: function() { var self = this; this._super.apply(this, arguments); @@ -1753,7 +1827,7 @@ openerp.web.form.FieldBoolean = openerp.web.form.Field.extend({ }); openerp.web.form.FieldProgressBar = openerp.web.form.Field.extend({ - template: 'FieldProgressBar', + form_template: 'FieldProgressBar', start: function() { this._super.apply(this, arguments); this.$element.find('div').progressbar({ @@ -1777,7 +1851,7 @@ openerp.web.form.FieldTextXml = openerp.web.form.Field.extend({ }); openerp.web.form.FieldSelection = openerp.web.form.Field.extend({ - template: 'FieldSelection', + form_template: 'FieldSelection', init: function(view, node) { var self = this; this._super(view, node); @@ -1883,7 +1957,7 @@ openerp.web.form.dialog = function(content, options) { }; openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({ - template: 'FieldMany2One', + form_template: 'FieldMany2One', init: function(view, node) { this._super(view, node); this.limit = 7; @@ -1912,9 +1986,13 @@ openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({ $cmenu.append(QWeb.render("FieldMany2One.context_menu", {widget: self})); var bindings = {}; bindings[self.cm_id + "_search"] = function() { + if (self.readonly) + return; self._search_create_popup("search"); }; bindings[self.cm_id + "_create"] = function() { + if (self.readonly) + return; self._search_create_popup("form"); }; bindings[self.cm_id + "_open"] = function() { @@ -2019,6 +2097,7 @@ openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({ minLength: 0, delay: 0 }); + this.$input.autocomplete("widget").addClass("openerp"); // used to correct a bug when selecting an element by pushing 'enter' in an editable list this.$input.keyup(function(e) { if (e.which === 13) { @@ -2201,6 +2280,7 @@ openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({ this.$input.prop('readonly', this.readonly); } }); +openerp.web.check_interface(openerp.web.form.FieldMany2One, openerp.web.form.FieldInterface); /* # Values: (0, 0, { fields }) create @@ -2248,7 +2328,7 @@ var commands = { } }; openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({ - template: 'FieldOne2Many', + form_template: 'FieldOne2Many', multi_selection: false, init: function(view, node) { this._super(view, node); @@ -2522,7 +2602,7 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({ this.previous_readonly = this.readonly; if (this.viewmanager) { this.is_loaded = this.is_loaded.pipe(function() { - self.viewmanager.stop(); + self.viewmanager.destroy(); return $.when(self.load_views()).then(function() { self.reload_current_view(); }); @@ -2622,7 +2702,7 @@ openerp.web.form.One2ManyFormView = openerp.web.FormView.extend({ }); openerp.web.form.FieldMany2Many = openerp.web.form.Field.extend({ - template: 'FieldMany2Many', + form_template: 'FieldMany2Many', multi_selection: false, init: function(view, node) { this._super(view, node); @@ -2702,7 +2782,7 @@ openerp.web.form.FieldMany2Many = openerp.web.form.Field.extend({ this.previous_readonly = this.readonly; if (this.list_view) { this.is_loaded = this.is_loaded.pipe(function() { - self.list_view.stop(); + self.list_view.destroy(); return $.when(self.load_view()).then(function() { self.reload_content(); }); @@ -2750,7 +2830,7 @@ openerp.web.form.Many2ManyListView = openerp.web.ListView.extend(/** @lends open var pop = new openerp.web.form.FormOpenPopup(this); pop.show_element(this.dataset.model, id, this.m2m_field.build_context(), { title: _t("Open: ") + this.name, - readonly: this.widget_parent.is_readonly() + readonly: this.getParent().is_readonly() }); pop.on_write_completed.add_last(function() { self.reload_content(); @@ -2787,7 +2867,7 @@ openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends ope }, read_function: null}); this.initial_ids = this.options.initial_ids; this.created_elements = []; - this.render_element(); + this.renderElement(); openerp.web.form.dialog(this.$element, { close: function() { self.check_exit(); @@ -2831,10 +2911,14 @@ openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends ope this.new_object(); } }, + stop: function () { + this.$element.dialog('close'); + this._super(); + }, setup_search_view: function(search_defaults) { var self = this; if (this.searchview) { - this.searchview.stop(); + this.searchview.destroy(); } this.searchview = new openerp.web.SearchView(this, this.dataset, false, search_defaults); @@ -2864,7 +2948,7 @@ openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends ope $buttons.prepend(QWeb.render("SelectCreatePopup.search.buttons")); var $cbutton = $buttons.find(".oe_selectcreatepopup-search-close"); $cbutton.click(function() { - self.stop(); + self.destroy(); }); var $sbutton = $buttons.find(".oe_selectcreatepopup-search-select"); if(self.options.disable_multiple_selection) { @@ -2872,7 +2956,7 @@ openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends ope } $sbutton.click(function() { self.on_select_elements(self.selected_ids); - self.stop(); + self.destroy(); }); }); }); @@ -2956,7 +3040,7 @@ openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends ope if (this.created_elements.length > 0) { this.on_select_elements(this.created_elements); } - this.stop(); + this.destroy(); }, on_default_get: function(res) {} }); @@ -2967,7 +3051,7 @@ openerp.web.form.SelectCreateListView = openerp.web.ListView.extend({ }, select_record: function(index) { this.popup.on_select_elements([this.dataset.ids[index]]); - this.popup.stop(); + this.popup.destroy(); }, do_select: function(ids, records) { this._super(ids, records); @@ -2996,8 +3080,8 @@ openerp.web.form.FormOpenPopup = openerp.web.OldWidget.extend(/** @lends openerp this.row_id = row_id; this.context = context || {}; this.options = _.defaults(options || {}, {"auto_write": true}); - this.render_element(); - this.$element.dialog({ + this.renderElement(); + openerp.web.dialog(this.$element, { title: options.title || '', modal: true, width: 960, @@ -3043,12 +3127,12 @@ openerp.web.form.FormOpenPopup = openerp.web.OldWidget.extend(/** @lends openerp var $nbutton = $buttons.find(".oe_formopenpopup-form-save"); $nbutton.click(function() { self.view_form.do_save().then(function() { - self.stop(); + self.destroy(); }); }); var $cbutton = $buttons.find(".oe_formopenpopup-form-close"); $cbutton.click(function() { - self.stop(); + self.destroy(); }); if (self.options.readonly) { $nbutton.hide(); @@ -3071,7 +3155,7 @@ openerp.web.form.FormOpenDataset = openerp.web.ProxyDataSet.extend({ }); openerp.web.form.FieldReference = openerp.web.form.Field.extend({ - template: 'FieldReference', + form_template: 'FieldReference', init: function(view, node) { this._super(view, node); this.fields_view = { @@ -3086,7 +3170,7 @@ openerp.web.form.FieldReference = openerp.web.form.Field.extend({ }; this.get_fields_values = view.get_fields_values; this.get_selected_ids = view.get_selected_ids; - this.do_onchange = this.on_form_changed = this.on_nop; + this.do_onchange = this.on_form_changed = this.do_notify_change = this.on_nop; this.dataset = this.view.dataset; this.widgets_counter = 0; this.view_id = 'reference_' + _.uniqueId(); @@ -3117,7 +3201,11 @@ openerp.web.form.FieldReference = openerp.web.form.Field.extend({ }, start: function() { this._super(); + this.selection.$element = $(".oe_form_view_reference_selection", this.$element); + this.selection.renderElement(); this.selection.start(); + this.m2o.$element = $(".oe_form_view_reference_m2o", this.$element); + this.m2o.renderElement(); this.m2o.start(); }, is_valid: function() { @@ -3226,7 +3314,7 @@ openerp.web.form.FieldBinary = openerp.web.form.Field.extend({ }); openerp.web.form.FieldBinaryFile = openerp.web.form.FieldBinary.extend({ - template: 'FieldBinaryFile', + form_template: 'FieldBinaryFile', update_dom: function() { this._super.apply(this, arguments); this.$element.find('.oe-binary-file-set, .oe-binary-file-clear').toggle(!this.readonly); @@ -3264,7 +3352,7 @@ openerp.web.form.FieldBinaryFile = openerp.web.form.FieldBinary.extend({ }); openerp.web.form.FieldBinaryImage = openerp.web.form.FieldBinary.extend({ - template: 'FieldBinaryImage', + form_template: 'FieldBinaryImage', start: function() { this._super.apply(this, arguments); this.$image = this.$element.find('img.oe-binary-image'); @@ -3276,8 +3364,14 @@ openerp.web.form.FieldBinaryImage = openerp.web.form.FieldBinary.extend({ set_value: function(value) { this._super.apply(this, arguments); this.set_image_maxwidth(); - var url = '/web/binary/image?session_id=' + this.session.session_id + '&model=' + - this.view.dataset.model +'&id=' + (this.view.datarecord.id || '') + '&field=' + this.name + '&t=' + (new Date().getTime()); + + var url; + if (value && value.substr(0, 10).indexOf(' ') == -1) { + url = 'data:image/png;base64,' + this.value; + } else { + url = '/web/binary/image?session_id=' + this.session.session_id + '&model=' + + this.view.dataset.model +'&id=' + (this.view.datarecord.id || '') + '&field=' + this.name + '&t=' + (new Date().getTime()); + } this.$image.attr('src', url); }, set_image_maxwidth: function() { @@ -3299,7 +3393,7 @@ openerp.web.form.FieldBinaryImage = openerp.web.form.FieldBinary.extend({ }); openerp.web.form.FieldStatus = openerp.web.form.Field.extend({ - template: "EmptyComponent", + form_template: "EmptyComponent", start: function() { this._super(); this.selected_value = null; @@ -3364,10 +3458,11 @@ openerp.web.form.FieldStatus = openerp.web.form.Field.extend({ }); openerp.web.form.WidgetHtml = openerp.web.form.Widget.extend({ - render: function () { + renderElement: function () { var $root = $('
    '); this.render_children(this, $root); - return $root.html(); + var rendered = $root.html(); + this.$element.html(rendered); }, render_children: function (object, $into) { var self = this, @@ -3376,10 +3471,9 @@ openerp.web.form.WidgetHtml = openerp.web.form.Widget.extend({ if (typeof child === 'string') { $into.text(child); } else if (child.tag === 'field') { - $into.append( - new (self.view.registry.get_object('frame'))( - self.view, {tag: 'ueule', attrs: {}, children: [child] }) - .render()); + var widget = instanciate_widget(self.view.registry.get_object('frame'), + self.view, {tag: 'ueule', attrs: {}, children: [child] }); + widget.appendTo($into); } else { var $child = $(document.createElement(child.tag)) .attr(child.attrs) @@ -3426,6 +3520,14 @@ openerp.web.form.widgets = new openerp.web.Registry({ 'html': 'openerp.web.form.WidgetHtml' }); +var instanciate_widget = function(claz, view, node, o1, o2) { + var widget = new (claz)(view, node, o1, o2); + widget.element_class = (['formview', view.view_id, widget.element_name, + view.widgets_counter++].join("_")).replace(/[^\r\n\f0-9A-Za-z_-]/g, "_"); + view.widgets[widget.element_class] = widget; + return widget; +} + }; diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index 8d8e342370e..e8fff450c6e 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -96,7 +96,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView# if (this._limit === undefined) { this._limit = (this.options.limit || this.defaults.limit - || (this.widget_parent.action || {}).limit + || (this.getParent().action || {}).limit || 80); } return this._limit; @@ -158,7 +158,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView# var pair = this.colors[i], color = pair[0], expression = pair[1]; - if (py.evaluate(expression, _.extend({bool: py.bool}, context))) { + if (py.evaluate(expression, context).toJSON()) { return 'color: ' + color + ';'; } // TODO: handle evaluation errors @@ -291,7 +291,10 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView# */ configure_pager: function (dataset) { this.dataset.ids = dataset.ids; - this.dataset._length = dataset._length; + // Not exactly clean + if (dataset._length) { + this.dataset._length = dataset._length; + } var limit = this.limit(), total = dataset.size(), @@ -360,7 +363,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView# _(this.fields_view.arch.children).map(field_to_column)); if (grouped) { this.columns.unshift({ - id: '_group', tag: '', string: "Group", meta: true, + id: '_group', tag: '', string: _t("Group"), meta: true, modifiers_for: function () { return {}; } }, { id: '_count', tag: '', string: '#', meta: true, @@ -541,19 +544,17 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView# * @param {Array} records selected record values */ do_select: function (ids, records) { - this.$element.find('.oe-list-delete') - .attr('disabled', !ids.length); - if (this.sidebar) { - if (ids.length) { - this.sidebar.do_unfold(); - } else { - this.sidebar.do_fold(); - } - } - if (!records.length) { + this.$element.find('.oe-list-delete').attr('disabled', !ids.length); + if (!ids.length) { + this.dataset.index = 0; + if (this.sidebar) { this.sidebar.do_fold(); } this.compute_aggregates(); return; } + + this.dataset.index = _(this.dataset.ids).indexOf(ids[0]); + if (this.sidebar) { this.sidebar.do_unfold(); } + this.compute_aggregates(_(records).map(function (record) { return {count: 1, values: record}; })); @@ -1260,9 +1261,11 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L if (column.meta) { // do not do anything } else if (column.id in group.aggregates) { - var value = group.aggregates[column.id]; + var r = {}; + r[column.id] = {value: group.aggregates[column.id]}; $('') - .html(openerp.web.format_value(value, column)) + .html(openerp.web.format_cell( + r, column, {process_modifiers: false})) .appendTo($row); } else { $row.append(''); diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js index c7222455889..b8699bcc006 100644 --- a/addons/web/static/src/js/view_list_editable.js +++ b/addons/web/static/src/js/view_list_editable.js @@ -139,7 +139,7 @@ openerp.web.list_editable = function (openerp) { } cancelled.then(function () { self.view.unpad_columns(); - self.edition_form.stop(); + self.edition_form.destroy(); self.edition_form.$element.remove(); delete self.edition_form; delete self.edition_id; @@ -235,26 +235,16 @@ openerp.web.list_editable = function (openerp) { } self.edition = true; self.edition_id = record_id; - self.edition_form = _.extend(new openerp.web.ListEditableFormView(self.view, self.dataset, false), { - form_template: 'ListView.row.form', - registry: openerp.web.list.form.widgets, - $element: $new_row - }); - // HA HA - self.edition_form.appendTo(); + self.edition_form = new openerp.web.ListEditableFormView(self.view, self.dataset, false); + self.edition_form.$element = $new_row; + self.edition_form.editable_list = self; + // HO HO + // empty $.when(self.edition_form.on_loaded(self.get_form_fields_view())).then(function () { // put in $.when just in case FormView.on_loaded becomes asynchronous $new_row.find('> td') - .addClass('oe-field-cell') - .removeAttr('width') .end() .find('td:last').removeClass('oe-field-cell').end(); - if (self.options.selectable) { - $new_row.prepend(''); - } - if (self.options.isClarkGable) { - $new_row.prepend(''); - } // pad in case of groupby _(self.columns).each(function (column) { if (column.meta) { @@ -383,7 +373,7 @@ openerp.web.list_editable = function (openerp) { openerp.web.list.form = {}; } openerp.web.list.form.WidgetFrame = openerp.web.form.WidgetFrame.extend({ - template: 'ListView.row.frame' + form_template: 'ListView.row.frame' }); var form_widgets = openerp.web.form.widgets; openerp.web.list.form.widgets = form_widgets.extend({ @@ -418,9 +408,10 @@ openerp.web.list_editable = function (openerp) { }); openerp.web.ListEditableFormView = openerp.web.FormView.extend({ - init_view: function() {}, - _render_and_insert: function () { - return this.start(); - } + form_template: 'ListView.row.form', + init: function() { + this._super.apply(this, arguments); + this.registry = openerp.web.list.form.widgets; + }, }); }; diff --git a/addons/web/static/src/js/view_page.js b/addons/web/static/src/js/view_page.js index 33eabc63b3c..e3367f56b4a 100644 --- a/addons/web/static/src/js/view_page.js +++ b/addons/web/static/src/js/view_page.js @@ -68,13 +68,13 @@ openerp.web.page = function (openerp) { openerp.web.page = {}; openerp.web.page.WidgetFrameReadonly = openerp.web.form.WidgetFrame.extend({ - template: 'WidgetFrame.readonly' + form_template: 'WidgetFrame.readonly' }); openerp.web.page.FieldReadonly = openerp.web.form.Field.extend({ }); openerp.web.page.FieldCharReadonly = openerp.web.page.FieldReadonly.extend({ - template: 'FieldChar.readonly', + form_template: 'FieldChar.readonly', init: function(view, node) { this._super(view, node); this.password = this.node.attrs.password === 'True' || this.node.attrs.password === '1'; @@ -89,13 +89,27 @@ openerp.web.page = function (openerp) { return show_value; } }); + openerp.web.page.FieldFloatReadonly = openerp.web.page.FieldCharReadonly.extend({ + init: function (view, node) { + this._super(view, node); + if (node.attrs.digits) { + this.digits = py.eval(node.attrs.digits).toJSON(); + } else { + this.digits = view.fields_view.fields[node.attrs.name].digits; + } + } + }); openerp.web.page.FieldURIReadonly = openerp.web.page.FieldCharReadonly.extend({ - template: 'FieldURI.readonly', + form_template: 'FieldURI.readonly', scheme: null, format_value: function (value) { return value; }, set_value: function (value) { + if (!value) { + this.$element.find('a').text('').attr('href', '#'); + return; + } this.$element.find('a') .attr('href', this.scheme + ':' + value) .text(this.format_value(value)); @@ -106,6 +120,10 @@ openerp.web.page = function (openerp) { }); openerp.web.page.FieldUrlReadonly = openerp.web.page.FieldURIReadonly.extend({ set_value: function (value) { + if (!value) { + this.$element.find('a').text('').attr('href', '#'); + return; + } var s = /(\w+):(.+)/.exec(value); if (!s) { value = "http://" + value; @@ -120,7 +138,7 @@ openerp.web.page = function (openerp) { } }); openerp.web.page.FieldSelectionReadonly = openerp.web.page.FieldReadonly.extend({ - template: 'FieldChar.readonly', + form_template: 'FieldChar.readonly', init: function(view, node) { // lifted straight from r/w version var self = this; @@ -225,7 +243,7 @@ openerp.web.page = function (openerp) { } }); openerp.web.page.FieldBinaryFileReadonly = openerp.web.form.FieldBinary.extend({ - template: 'FieldURI.readonly', + form_template: 'FieldURI.readonly', start: function() { this._super.apply(this, arguments); var self = this; @@ -261,7 +279,7 @@ openerp.web.page = function (openerp) { 'one2many_list' : 'openerp.web.page.FieldOne2ManyReadonly', 'reference': 'openerp.web.page.FieldReferenceReadonly', 'boolean': 'openerp.web.page.FieldBooleanReadonly', - 'float': 'openerp.web.page.FieldCharReadonly', + 'float': 'openerp.web.page.FieldFloatReadonly', 'integer': 'openerp.web.page.FieldCharReadonly', 'float_time': 'openerp.web.page.FieldCharReadonly', 'binary': 'openerp.web.page.FieldBinaryFileReadonly', diff --git a/addons/web/static/src/js/view_tree.js b/addons/web/static/src/js/view_tree.js index dea53793ffb..6039e4a0822 100644 --- a/addons/web/static/src/js/view_tree.js +++ b/addons/web/static/src/js/view_tree.js @@ -146,7 +146,7 @@ openerp.web.TreeView = openerp.web.View.extend(/** @lends openerp.web.TreeView# var pair = this.colors[i], color = pair[0], expression = pair[1]; - if (py.evaluate(expression, _.extend({bool: py.bool}, context))) { + if (py.evaluate(expression, context).toJSON()) { return 'color: ' + color + ';'; } // TODO: handle evaluation errors @@ -224,21 +224,25 @@ openerp.web.TreeView = openerp.web.View.extend(/** @lends openerp.web.TreeView# active_model: self.dataset.model, active_id: id, active_ids: [id]}; - this.rpc('/web/treeview/action', { + return this.rpc('/web/treeview/action', { id: id, model: this.dataset.model, context: new openerp.web.CompoundContext( this.dataset.get_context(), local_context) - }, function (actions) { + }).pipe(function (actions) { if (!actions.length) { return; } var action = actions[0][2]; var c = new openerp.web.CompoundContext(local_context); if (action.context) { c.add(action.context); } - action.context = c; - self.do_action(action); - }); + return self.rpc('/web/session/eval_domain_and_context', { + contexts: [c], domains: [] + }).pipe(function (res) { + action.context = res.context; + return self.do_action(action); + }, null); + }, null); }, // show & hide the contents diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 56997190bc1..5be0fad74f0 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -30,31 +30,31 @@ session.web.ActionManager = session.web.OldWidget.extend({ }, dialog_stop: function () { if (this.dialog) { - this.dialog_viewmanager.stop(); + this.dialog_viewmanager.destroy(); this.dialog_viewmanager = null; - this.dialog.stop(); + this.dialog.destroy(); this.dialog = null; } }, content_stop: function () { if (this.inner_viewmanager) { - this.inner_viewmanager.stop(); + this.inner_viewmanager.destroy(); this.inner_viewmanager = null; } if (this.client_widget) { - this.client_widget.stop(); + this.client_widget.destroy(); this.client_widget = null; } }, do_push_state: function(state) { - if (this.widget_parent && this.widget_parent.do_push_state) { + if (this.getParent() && this.getParent().do_push_state) { if (this.inner_action) { state['model'] = this.inner_action.res_model; if (this.inner_action.id) { state['action_id'] = this.inner_action.id; } } - this.widget_parent.do_push_state(state); + this.getParent().do_push_state(state); } }, do_load_state: function(state, warm) { @@ -65,6 +65,9 @@ session.web.ActionManager = session.web.OldWidget.extend({ if (run_action) { this.null_action(); action_loaded = this.do_action(state.action_id); + session.webclient.menu.has_been_loaded.then(function() { + session.webclient.menu.open_action(state.action_id); + }); } } else if (state.model && state.id) { // TODO handle context & domain ? @@ -142,7 +145,7 @@ session.web.ActionManager = session.web.OldWidget.extend({ if(on_close) this.dialog.on_close.add(on_close); } else { - this.dialog_viewmanager.stop(); + this.dialog_viewmanager.destroy(); } this.dialog.dialog_title = action.name; this.dialog_viewmanager = new session.web.ViewManagerAction(this, action); @@ -150,7 +153,7 @@ session.web.ActionManager = session.web.OldWidget.extend({ this.dialog.open(); } else { if(action.menu_id) { - return this.widget_parent.do_action(action, function () { + return this.getParent().do_action(action, function () { session.webclient.menu.open_menu(action.menu_id); }); } @@ -180,7 +183,7 @@ session.web.ActionManager = session.web.OldWidget.extend({ this.content_stop(); this.dialog_stop(); var ClientWidget = session.web.client_actions.get_object(action.tag); - (this.client_widget = new ClientWidget(this, action.params)).appendTo(this); + (this.client_widget = new ClientWidget(this, action.params)).appendTo(this.$element); }, ir_actions_report_xml: function(action, on_closed) { var self = this; @@ -209,7 +212,7 @@ session.web.ActionManager = session.web.OldWidget.extend({ window.open(action.url, action.target === 'self' ? '_self' : '_blank'); }, ir_ui_menu: function (action) { - this.widget_parent.do_action(action); + this.getParent().do_action(action); } }); @@ -385,7 +388,7 @@ session.web.ViewManager = session.web.OldWidget.extend(/** @lends session.web.V setup_search_view: function(view_id, search_defaults) { var self = this; if (this.searchview) { - this.searchview.stop(); + this.searchview.destroy(); } this.searchview = new session.web.SearchView( this, this.dataset, @@ -408,6 +411,9 @@ session.web.ViewManager = session.web.OldWidget.extend(/** @lends session.web.V var groupby = results.group_by.length ? results.group_by : action_context.group_by; + if (_.isString(groupby)) { + groupby = [groupby]; + } controller.do_search(results.domain, results.context, groupby || []); }); }, @@ -680,9 +686,9 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner }); }, do_push_state: function(state) { - if (this.widget_parent && this.widget_parent.do_push_state) { + if (this.getParent() && this.getParent().do_push_state) { state["view_type"] = this.active_view; - this.widget_parent.do_push_state(state); + this.getParent().do_push_state(state); } }, do_load_state: function(state, warm) { @@ -702,7 +708,7 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner }, shortcut_check : function(view) { var self = this; - var grandparent = this.widget_parent && this.widget_parent.widget_parent; + var grandparent = this.getParent() && this.getParent().getParent(); // display shortcuts if on the first view for the action var $shortcut_toggle = this.$element.find('.oe-shortcut-toggle'); if (!this.action.name || @@ -796,8 +802,8 @@ session.web.Sidebar = session.web.OldWidget.extend({ }, add_default_sections: function() { var self = this, - view = this.widget_parent, - view_manager = view.widget_parent, + view = this.getParent(), + view_manager = view.getParent(), action = view_manager.action; if (this.session.uid === 1) { this.add_section(_t('Customize'), 'customize'); @@ -912,11 +918,11 @@ session.web.Sidebar = session.web.OldWidget.extend({ }, on_item_action_clicked: function(item) { var self = this; - self.widget_parent.sidebar_context().then(function (context) { - var ids = self.widget_parent.get_selected_ids(); + self.getParent().sidebar_context().then(function (context) { + var ids = self.getParent().get_selected_ids(); if (ids.length == 0) { //TODO: make prettier warning? - $("
    ").text(_t("You must choose at least one record.")).dialog({ + openerp.web.dialog($("
    ").text(_t("You must choose at least one record.")), { title: _t("Warning"), modal: true }); @@ -925,7 +931,7 @@ session.web.Sidebar = session.web.OldWidget.extend({ var additional_context = _.extend({ active_id: ids[0], active_ids: ids, - active_model: self.widget_parent.dataset.model + active_model: self.getParent().dataset.model }, context); self.rpc("/web/action/load", { action_id: item.action.id, @@ -937,7 +943,7 @@ session.web.Sidebar = session.web.OldWidget.extend({ result.result.flags.new_window = true; self.do_action(result.result, function () { // reload view - self.widget_parent.reload(); + self.getParent().reload(); }); }); }); @@ -1111,8 +1117,8 @@ session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{ var self = this; var result_handler = function () { if (on_closed) { on_closed.apply(null, arguments); } - if (self.widget_parent && self.widget_parent.on_action_executed) { - return self.widget_parent.on_action_executed.apply(null, arguments); + if (self.getParent() && self.getParent().on_action_executed) { + return self.getParent().on_action_executed.apply(null, arguments); } }; var context = new session.web.CompoundContext(dataset.get_context(), action_data.context || {}); @@ -1184,8 +1190,8 @@ session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{ this.$element.hide(); }, do_push_state: function(state) { - if (this.widget_parent && this.widget_parent.do_push_state) { - this.widget_parent.do_push_state(state); + if (this.getParent() && this.getParent().do_push_state) { + this.getParent().do_push_state(state); } }, do_load_state: function(state, warm) { diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 09ae4457221..c8a6762ab34 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -17,35 +17,24 @@
    - - - - - - - - - - - -
    -
    - -
    - - - - - -
    -
    -
    -
    -
    -
    +
    +
    +
    @@ -154,7 +143,7 @@ - @@ -335,81 +324,73 @@
    - -
    - - - - -

    - ()
    - -

    -
    -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    -
    - LOGOUT -
    -
    -
    -
    -
      -
    • -
    - - - - -
    - - - -
    +
      +
    • + +
    • +
    -
    - - -
    - - - - + +
      +
    • + + + +
    • +
    +
    + +
    + -
    - - oe_secondary_submenu_item - - -
    + + + + + +
  2. + + + +
  3. + + @@ -728,7 +709,8 @@ - + + @@ -743,7 +725,6 @@ - @@ -892,7 +873,8 @@ - +
    +
    @@ -909,9 +891,7 @@
    -
    - -
    +
    @@ -1107,11 +1087,9 @@
    - -
    - + - +
    @@ -1128,7 +1106,7 @@
    - +
    + +
    - - - $(document.createElement('t')) - .append(this.contents()) - .attr({ - 't-foreach': this.attr('t-foreach'), - 't-as': this.attr('t-as') - }) - .replaceAll(this) - .after($(document.createElement('td')).append( - $(document.createElement('button')).attr({ - 'class': 'oe-edit-row-save', 'type': 'button'}) - .html(' '))) - .unwrap(); + + + + + + + +
    diff --git a/addons/web/test/test_dataset.py b/addons/web/test/test_dataset.py index 898ca5a582c..b9fe5a3cca2 100644 --- a/addons/web/test/test_dataset.py +++ b/addons/web/test/test_dataset.py @@ -10,6 +10,7 @@ class TestDataSetController(unittest2.TestCase): self.read = self.request.session.model().read self.search = self.request.session.model().search + @unittest2.skip def test_empty_find(self): self.search.return_value = [] self.read.return_value = [] @@ -17,6 +18,7 @@ class TestDataSetController(unittest2.TestCase): self.assertFalse(self.dataset.do_search_read(self.request, 'fake.model')) self.read.assert_called_once_with([], False, self.request.context) + @unittest2.skip def test_regular_find(self): self.search.return_value = [1, 2, 3] @@ -24,6 +26,7 @@ class TestDataSetController(unittest2.TestCase): self.read.assert_called_once_with([1, 2, 3], False, self.request.context) + @unittest2.skip def test_ids_shortcut(self): self.search.return_value = [1, 2, 3] self.read.return_value = [ @@ -37,6 +40,7 @@ class TestDataSetController(unittest2.TestCase): [{'id': 1}, {'id': 2}, {'id': 3}]) self.assertFalse(self.read.called) + @unittest2.skip def test_get(self): self.read.return_value = [ {'id': 1, 'name': 'baz'}, diff --git a/addons/web/test/test_menu.py b/addons/web/test/test_menu.py index d763fd7dcb1..7e69442c4b8 100644 --- a/addons/web/test/test_menu.py +++ b/addons/web/test/test_menu.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- import mock import unittest2 -import web.controllers.main -import openerpweb.openerpweb + +from ..controllers import main +from ..common.session import OpenERPSession class Placeholder(object): def __init__(self, **kwargs): @@ -11,17 +12,16 @@ class Placeholder(object): class LoadTest(unittest2.TestCase): def setUp(self): - self.menu = web.controllers.main.Menu() + self.menu = main.Menu() self.menus_mock = mock.Mock() - self.request = Placeholder( - session=openerpweb.openerpweb.OpenERPSession( - model_factory=lambda _session, _name: self.menus_mock)) + self.request = Placeholder(session=OpenERPSession()) def tearDown(self): del self.request del self.menus_mock del self.menu + @unittest2.skip def test_empty(self): self.menus_mock.search = mock.Mock(return_value=[]) self.menus_mock.read = mock.Mock(return_value=[]) @@ -36,6 +36,7 @@ class LoadTest(unittest2.TestCase): root['children'], []) + @unittest2.skip def test_applications_sort(self): self.menus_mock.search = mock.Mock(return_value=[1, 2, 3]) self.menus_mock.read = mock.Mock(return_value=[ @@ -62,6 +63,7 @@ class LoadTest(unittest2.TestCase): 'parent_id': False, 'children': [] }]) + @unittest2.skip def test_deep(self): self.menus_mock.search = mock.Mock(return_value=[1, 2, 3, 4]) self.menus_mock.read = mock.Mock(return_value=[ @@ -100,7 +102,7 @@ class LoadTest(unittest2.TestCase): class ActionMungerTest(unittest2.TestCase): def setUp(self): - self.menu = web.controllers.main.Menu() + self.menu = main.Menu() def test_actual_treeview(self): action = { "views": [[False, "tree"], [False, "form"], @@ -111,10 +113,11 @@ class ActionMungerTest(unittest2.TestCase): } changed = action.copy() del action['view_type'] - web.controllers.main.fix_view_modes(changed) + main.fix_view_modes(changed) self.assertEqual(changed, action) + @unittest2.skip def test_list_view(self): action = { "views": [[False, "tree"], [False, "form"], @@ -123,7 +126,7 @@ class ActionMungerTest(unittest2.TestCase): "view_id": False, "view_mode": "tree,form,calendar" } - web.controllers.main.fix_view_modes(action) + main.fix_view_modes(action) self.assertEqual(action, { "views": [[False, "list"], [False, "form"], @@ -132,6 +135,7 @@ class ActionMungerTest(unittest2.TestCase): "view_mode": "list,form,calendar" }) + @unittest2.skip def test_redundant_views(self): action = { @@ -141,7 +145,7 @@ class ActionMungerTest(unittest2.TestCase): "view_id": False, "view_mode": "tree,form,calendar" } - web.controllers.main.fix_view_modes(action) + main.fix_view_modes(action) self.assertEqual(action, { "views": [[False, "list"], [False, "form"], diff --git a/addons/web/test/test_serving_base.py b/addons/web/test/test_serving_base.py new file mode 100644 index 00000000000..0bb7a83ac24 --- /dev/null +++ b/addons/web/test/test_serving_base.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +import random +import unittest2 + +from ..controllers.main import topological_sort + +def sample(population): + return random.sample( + population, + random.randint(0, min(len(population), 5))) + +class TestModulesLoading(unittest2.TestCase): + def setUp(self): + self.mods = map(str, range(1000)) + def test_topological_sort(self): + random.shuffle(self.mods) + modules = [ + (k, sample(self.mods[:i])) + for i, k in enumerate(self.mods)] + random.shuffle(modules) + ms = dict(modules) + + seen = set() + sorted_modules = topological_sort(ms) + for module in sorted_modules: + deps = ms[module] + self.assertGreaterEqual( + seen, set(deps), + 'Module %s (index %d), ' \ + 'missing dependencies %s from loaded modules %s' % ( + module, sorted_modules.index(module), deps, seen + )) + seen.add(module) diff --git a/addons/web/test/test_view.py b/addons/web/test/test_view.py index 677ed42eb2b..0a778ccffd1 100644 --- a/addons/web/test/test_view.py +++ b/addons/web/test/test_view.py @@ -6,8 +6,7 @@ import unittest2 import simplejson import web.controllers.main -import openerpweb.nonliterals -import openerpweb.openerpweb +from ..common import nonliterals, session as s def field_attrs(fields_view_get, fieldname): (field,) = filter(lambda f: f['attrs'].get('name') == fieldname, @@ -47,7 +46,7 @@ class DomainsAndContextsTest(unittest2.TestCase): ) def test_retrieve_nonliteral_domain(self): - session = mock.Mock(spec=openerpweb.openerpweb.OpenERPSession) + session = mock.Mock(spec=s.OpenERPSession) session.domains_store = {} domain_string = ("[('month','=',(datetime.date.today() - " "datetime.timedelta(365/12)).strftime('%%m'))]") @@ -56,9 +55,9 @@ class DomainsAndContextsTest(unittest2.TestCase): self.view.parse_domains_and_contexts(e, session) - self.assertIsInstance(e.get('domain'), openerpweb.nonliterals.Domain) + self.assertIsInstance(e.get('domain'), nonliterals.Domain) self.assertEqual( - openerpweb.nonliterals.Domain( + nonliterals.Domain( session, key=e.get('domain').key).get_domain_string(), domain_string) @@ -90,7 +89,7 @@ class DomainsAndContextsTest(unittest2.TestCase): ) def test_retrieve_nonliteral_context(self): - session = mock.Mock(spec=openerpweb.openerpweb.OpenERPSession) + session = mock.Mock(spec=s.OpenERPSession) session.contexts_store = {} context_string = ("{'month': (datetime.date.today() - " "datetime.timedelta(365/12)).strftime('%%m')}") @@ -99,9 +98,9 @@ class DomainsAndContextsTest(unittest2.TestCase): self.view.parse_domains_and_contexts(e, session) - self.assertIsInstance(e.get('context'), openerpweb.nonliterals.Context) + self.assertIsInstance(e.get('context'), nonliterals.Context) self.assertEqual( - openerpweb.nonliterals.Context( + nonliterals.Context( session, key=e.get('context').key).get_context_string(), context_string) @@ -127,6 +126,8 @@ class AttrsNormalizationTest(unittest2.TestCase): xml.etree.ElementTree.tostring(transformed), xml.etree.ElementTree.tostring(pristine) ) + + @unittest2.skip def test_transform_states(self): element = xml.etree.ElementTree.Element( 'field', states="open,closed") @@ -137,6 +138,7 @@ class AttrsNormalizationTest(unittest2.TestCase): simplejson.loads(element.get('attrs')), {'invisible': [['state', 'not in', ['open', 'closed']]]}) + @unittest2.skip def test_transform_invisible(self): element = xml.etree.ElementTree.Element( 'field', invisible="context.get('invisible_country', False)") @@ -149,12 +151,13 @@ class AttrsNormalizationTest(unittest2.TestCase): self.view.normalize_attrs(full_context, {'invisible_country': True}) self.assertEqual(full_context.get('invisible'), '1') + @unittest2.skip def test_transform_invisible_list_column(self): req = mock.Mock() req.context = {'set_editable':True, 'set_visible':True, 'gtd_visible':True, 'user_invisible':True} req.session.evaluation_context = \ - openerpweb.openerpweb.OpenERPSession().evaluation_context + s.OpenERPSession().evaluation_context req.session.model('project.task').fields_view_get.return_value = { 'arch': ''' @@ -183,13 +186,17 @@ class ListViewTest(unittest2.TestCase): self.view = web.controllers.main.ListView() self.request = mock.Mock() self.request.context = {'set_editable': True} + + @unittest2.skip def test_no_editable_editable_context(self): self.request.session.model('fake').fields_view_get.return_value = \ {'arch': ''} - view = self.view.fields_view_get(self.request, 'fake', False) + view = self.view.fields_view_get(self.request, 'fake', False, False) self.assertEqual(view['arch']['attrs']['editable'], 'bottom') + + @unittest2.skip def test_editable_top_editable_context(self): self.request.session.model('fake').fields_view_get.return_value = \ {'arch': ''} @@ -198,6 +205,7 @@ class ListViewTest(unittest2.TestCase): self.assertEqual(view['arch']['attrs']['editable'], 'top') + @unittest2.skip def test_editable_bottom_editable_context(self): self.request.session.model('fake').fields_view_get.return_value = \ {'arch': ''} diff --git a/addons/web_calendar/__openerp__.py b/addons/web_calendar/__openerp__.py index 877e96d918f..62537ba2345 100644 --- a/addons/web_calendar/__openerp__.py +++ b/addons/web_calendar/__openerp__.py @@ -19,5 +19,5 @@ 'qweb' : [ "static/src/xml/*.xml", ], - 'active': True + 'auto_install': True } diff --git a/addons/web_calendar/i18n/cs.po b/addons/web_calendar/i18n/cs.po new file mode 100644 index 00000000000..b409cc7185a --- /dev/null +++ b/addons/web_calendar/i18n/cs.po @@ -0,0 +1,39 @@ +# Czech translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-03-04 12:08+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Czech \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-05 04:53+0000\n" +"X-Generator: Launchpad (build 14900)\n" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:11 +msgid "Calendar" +msgstr "" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:466 +msgid "Responsible" +msgstr "" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:504 +msgid "Navigator" +msgstr "" + +#. openerp-web +#: addons/web_calendar/static/src/xml/web_calendar.xml:5 +#: addons/web_calendar/static/src/xml/web_calendar.xml:6 +msgid " " +msgstr "" diff --git a/addons/web_calendar/i18n/es_CR.po b/addons/web_calendar/i18n/es_CR.po index adef5d35aaf..1e5732e4906 100644 --- a/addons/web_calendar/i18n/es_CR.po +++ b/addons/web_calendar/i18n/es_CR.po @@ -8,15 +8,16 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2012-02-06 17:33+0100\n" -"PO-Revision-Date: 2012-02-08 02:18-0600\n" -"Last-Translator: Carlos Vásquez - CLEARCORP \n" +"PO-Revision-Date: 2012-02-16 21:34+0000\n" +"Last-Translator: Carlos Vásquez (CLEARCORP) " +"\n" "Language-Team: Spanish \n" -"Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-07 04:59+0000\n" -"X-Generator: Launchpad (build 14747)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" +"Language: es\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 @@ -38,4 +39,3 @@ msgstr "Navegador" #: addons/web_calendar/static/src/xml/web_calendar.xml:6 msgid " " msgstr " " - diff --git a/addons/web_calendar/i18n/fi.po b/addons/web_calendar/i18n/fi.po new file mode 100644 index 00000000000..5c4fa1871b8 --- /dev/null +++ b/addons/web_calendar/i18n/fi.po @@ -0,0 +1,41 @@ +# Finnish translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-03-19 12:03+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Finnish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-20 05:13+0000\n" +"X-Generator: Launchpad (build 14969)\n" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:11 +msgid "Calendar" +msgstr "kalenteri" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:466 +#: addons/web_calendar/static/src/js/calendar.js:467 +msgid "Responsible" +msgstr "Vastuuhenkilö" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:504 +#: addons/web_calendar/static/src/js/calendar.js:505 +msgid "Navigator" +msgstr "Navigaattori" + +#. openerp-web +#: addons/web_calendar/static/src/xml/web_calendar.xml:5 +#: addons/web_calendar/static/src/xml/web_calendar.xml:6 +msgid " " +msgstr " " diff --git a/addons/web_calendar/i18n/it.po b/addons/web_calendar/i18n/it.po index e78cf16db24..198a7e6dcac 100644 --- a/addons/web_calendar/i18n/it.po +++ b/addons/web_calendar/i18n/it.po @@ -8,29 +8,29 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-06 17:33+0100\n" -"PO-Revision-Date: 2011-10-08 13:39+0000\n" -"Last-Translator: Nicola Riolini - Micronaet \n" +"PO-Revision-Date: 2012-02-16 21:55+0000\n" +"Last-Translator: Davide Corio - agilebg.com \n" "Language-Team: Italian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-07 04:59+0000\n" -"X-Generator: Launchpad (build 14747)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 msgid "Calendar" -msgstr "" +msgstr "Calendario" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:466 msgid "Responsible" -msgstr "" +msgstr "Responsabile" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:504 msgid "Navigator" -msgstr "" +msgstr "Navigatore" #. openerp-web #: addons/web_calendar/static/src/xml/web_calendar.xml:5 diff --git a/addons/web_calendar/i18n/ja.po b/addons/web_calendar/i18n/ja.po new file mode 100644 index 00000000000..7743c359054 --- /dev/null +++ b/addons/web_calendar/i18n/ja.po @@ -0,0 +1,39 @@ +# Japanese translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-02-22 02:18+0000\n" +"Last-Translator: Masaki Yamaya \n" +"Language-Team: Japanese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-02-23 04:56+0000\n" +"X-Generator: Launchpad (build 14855)\n" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:11 +msgid "Calendar" +msgstr "カレンダー" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:466 +msgid "Responsible" +msgstr "責任担当" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:504 +msgid "Navigator" +msgstr "ナビゲータ" + +#. openerp-web +#: addons/web_calendar/static/src/xml/web_calendar.xml:5 +#: addons/web_calendar/static/src/xml/web_calendar.xml:6 +msgid " " +msgstr " " diff --git a/addons/web_calendar/i18n/ka.po b/addons/web_calendar/i18n/ka.po new file mode 100644 index 00000000000..928de2da04d --- /dev/null +++ b/addons/web_calendar/i18n/ka.po @@ -0,0 +1,41 @@ +# Georgian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-03-15 18:25+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Georgian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-16 05:14+0000\n" +"X-Generator: Launchpad (build 14951)\n" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:11 +msgid "Calendar" +msgstr "კალენდარი" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:466 +#: addons/web_calendar/static/src/js/calendar.js:467 +msgid "Responsible" +msgstr "პასუხისმგებელი" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:504 +#: addons/web_calendar/static/src/js/calendar.js:505 +msgid "Navigator" +msgstr "ნავიგატორი" + +#. openerp-web +#: addons/web_calendar/static/src/xml/web_calendar.xml:5 +#: addons/web_calendar/static/src/xml/web_calendar.xml:6 +msgid " " +msgstr "" diff --git a/addons/web_calendar/i18n/nl.po b/addons/web_calendar/i18n/nl.po index f38ef780bfa..a1129f40dad 100644 --- a/addons/web_calendar/i18n/nl.po +++ b/addons/web_calendar/i18n/nl.po @@ -8,19 +8,19 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-06 17:33+0100\n" -"PO-Revision-Date: 2012-02-15 14:37+0000\n" +"PO-Revision-Date: 2012-02-16 14:02+0000\n" "Last-Translator: Erwin \n" "Language-Team: Dutch \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-16 05:21+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:11 msgid "Calendar" -msgstr "Kalender" +msgstr "Agenda" #. openerp-web #: addons/web_calendar/static/src/js/calendar.js:466 diff --git a/addons/web_calendar/i18n/ro.po b/addons/web_calendar/i18n/ro.po new file mode 100644 index 00000000000..447d26aa435 --- /dev/null +++ b/addons/web_calendar/i18n/ro.po @@ -0,0 +1,41 @@ +# Romanian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-03-10 13:17+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Romanian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-11 04:56+0000\n" +"X-Generator: Launchpad (build 14914)\n" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:11 +msgid "Calendar" +msgstr "Calendar" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:466 +#: addons/web_calendar/static/src/js/calendar.js:467 +msgid "Responsible" +msgstr "Responsabil" + +#. openerp-web +#: addons/web_calendar/static/src/js/calendar.js:504 +#: addons/web_calendar/static/src/js/calendar.js:505 +msgid "Navigator" +msgstr "Navigator" + +#. openerp-web +#: addons/web_calendar/static/src/xml/web_calendar.xml:5 +#: addons/web_calendar/static/src/xml/web_calendar.xml:6 +msgid " " +msgstr " " diff --git a/addons/web_calendar/static/src/js/calendar.js b/addons/web_calendar/static/src/js/calendar.js index 58e92d0b14a..1c2fb52ca74 100644 --- a/addons/web_calendar/static/src/js/calendar.js +++ b/addons/web_calendar/static/src/js/calendar.js @@ -42,7 +42,7 @@ openerp.web_calendar.CalendarView = openerp.web.View.extend({ this._super(); return this.rpc("/web/view/load", {"model": this.model, "view_id": this.view_id, "view_type":"calendar", 'toolbar': true}, this.on_loaded); }, - stop: function() { + destroy: function() { scheduler.clearAll(); this._super(); }, @@ -66,6 +66,8 @@ openerp.web_calendar.CalendarView = openerp.web.View.extend({ this.day_length = this.fields_view.arch.attrs.day_length || 8; this.color_field = this.fields_view.arch.attrs.color; + this.color_string = this.fields_view.fields[this.color_field] ? + this.fields_view.fields[this.color_field].string : _t("Filter"); if (this.color_field && this.selected_filters.length === 0) { var default_filter; @@ -463,8 +465,9 @@ openerp.web_calendar.CalendarFormDialog = openerp.web.Dialog.extend({ }); openerp.web_calendar.SidebarResponsible = openerp.web.OldWidget.extend({ + // TODO: fme: in trunk, rename this class to SidebarFilter init: function(parent, view) { - var $section = parent.add_section(_t('Responsible'), 'responsible'); + var $section = parent.add_section(view.color_string, 'responsible'); this.$div = $('
    '); $section.append(this.$div); this._super(parent, $section.attr('id')); diff --git a/addons/web_dashboard/__openerp__.py b/addons/web_dashboard/__openerp__.py index 5f8be2b4e51..b739326e140 100644 --- a/addons/web_dashboard/__openerp__.py +++ b/addons/web_dashboard/__openerp__.py @@ -14,5 +14,5 @@ 'qweb' : [ "static/src/xml/*.xml", ], - 'active': True + 'auto_install': True } diff --git a/addons/web_dashboard/i18n/cs.po b/addons/web_dashboard/i18n/cs.po new file mode 100644 index 00000000000..7665034dc41 --- /dev/null +++ b/addons/web_dashboard/i18n/cs.po @@ -0,0 +1,111 @@ +# Czech translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-03-04 12:09+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Czech \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-05 04:53+0000\n" +"X-Generator: Launchpad (build 14900)\n" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:63 +msgid "Edit Layout" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:109 +msgid "Are you sure you want to remove this item ?" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:316 +msgid "Uncategorized" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:324 +#, python-format +msgid "Execute task \"%s\"" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:325 +msgid "Mark this task as done" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:4 +msgid "Reset Layout.." +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:6 +msgid "Reset" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:8 +msgid "Change Layout.." +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:10 +msgid "Change Layout" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:27 +msgid " " +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:28 +msgid "Create" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:39 +msgid "Choose dashboard layout" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:62 +msgid "progress:" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:67 +msgid "" +"Click on the functionalites listed below to launch them and configure your " +"system" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:110 +msgid "Welcome to OpenERP" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:118 +msgid "Remember to bookmark" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:119 +msgid "This url" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:121 +msgid "Your login:" +msgstr "" diff --git a/addons/web_dashboard/i18n/es.po b/addons/web_dashboard/i18n/es.po index 24d9f9662f8..0c8c74f5ff2 100644 --- a/addons/web_dashboard/i18n/es.po +++ b/addons/web_dashboard/i18n/es.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-14 15:27+0100\n" -"PO-Revision-Date: 2012-02-13 17:56+0000\n" -"Last-Translator: Amós Oviedo \n" +"PO-Revision-Date: 2012-02-22 10:34+0000\n" +"Last-Translator: Jorge L Tupac-Yupanqui \n" "Language-Team: Spanish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-15 05:43+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-23 04:56+0000\n" +"X-Generator: Launchpad (build 14855)\n" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:63 @@ -36,12 +36,12 @@ msgstr "Sin categoría" #: addons/web_dashboard/static/src/js/dashboard.js:324 #, python-format msgid "Execute task \"%s\"" -msgstr "" +msgstr "Ejecutar tarea \"%s\"" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:325 msgid "Mark this task as done" -msgstr "" +msgstr "Marcar esta tarea como terminada" #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:4 diff --git a/addons/web_dashboard/i18n/es_CR.po b/addons/web_dashboard/i18n/es_CR.po index c34db0cc2f6..ff0010c17b4 100644 --- a/addons/web_dashboard/i18n/es_CR.po +++ b/addons/web_dashboard/i18n/es_CR.po @@ -7,16 +7,16 @@ msgid "" msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2012-02-07 10:13+0100\n" -"PO-Revision-Date: 2012-02-08 02:25-0600\n" -"Last-Translator: Carlos Vásquez - CLEARCORP \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-02-16 22:16+0000\n" +"Last-Translator: Freddy Gonzalez \n" "Language-Team: Spanish \n" -"Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-08 06:39+0000\n" -"X-Generator: Launchpad (build 14747)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" +"Language: es\n" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:63 @@ -33,6 +33,17 @@ msgstr "¿Está seguro/a que desea eliminar este elemento?" msgid "Uncategorized" msgstr "Sin categoría" +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:324 +#, python-format +msgid "Execute task \"%s\"" +msgstr "Ejecutar tarea \"%s\"" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:325 +msgid "Mark this task as done" +msgstr "Marcar esta tarea como terminada" + #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:4 msgid "Reset Layout.." @@ -75,8 +86,12 @@ msgstr "progreso:" #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:67 -msgid "Click on the functionalites listed below to launch them and configure your system" -msgstr "Haga clic en las funcionalidades enumeradas abajo para lanzarlas y configurar su sistema" +msgid "" +"Click on the functionalites listed below to launch them and configure your " +"system" +msgstr "" +"Haga clic en las funcionalidades enumeradas abajo para lanzarlas y " +"configurar su sistema" #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:110 @@ -97,4 +112,3 @@ msgstr "Esta dirección" #: addons/web_dashboard/static/src/xml/web_dashboard.xml:121 msgid "Your login:" msgstr "Su usuario:" - diff --git a/addons/web_dashboard/i18n/fi.po b/addons/web_dashboard/i18n/fi.po new file mode 100644 index 00000000000..81bce74ce7b --- /dev/null +++ b/addons/web_dashboard/i18n/fi.po @@ -0,0 +1,113 @@ +# Finnish translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-03-19 12:00+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Finnish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-20 05:13+0000\n" +"X-Generator: Launchpad (build 14969)\n" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:63 +msgid "Edit Layout" +msgstr "Muokkaa näkymää" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:109 +msgid "Are you sure you want to remove this item ?" +msgstr "Oletko varma että haluat poistaa tämän osan ?" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:316 +msgid "Uncategorized" +msgstr "Luokittelemattomat" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:324 +#, python-format +msgid "Execute task \"%s\"" +msgstr "Suorita tehtävä \"%s\"" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:325 +msgid "Mark this task as done" +msgstr "Merkitse tämä tehtävä valmiiksi" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:4 +msgid "Reset Layout.." +msgstr "Palauta asettelu.." + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:6 +msgid "Reset" +msgstr "Palauta" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:8 +msgid "Change Layout.." +msgstr "Muuta asettelu.." + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:10 +msgid "Change Layout" +msgstr "Muuta asettelu" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:27 +msgid " " +msgstr " " + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:28 +msgid "Create" +msgstr "Luo" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:39 +msgid "Choose dashboard layout" +msgstr "Valitse työpöydän asetttelu" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:62 +msgid "progress:" +msgstr "edistyminen:" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:67 +msgid "" +"Click on the functionalites listed below to launch them and configure your " +"system" +msgstr "" +"Klikkaa allalistattuja toimintoja käynnistääksesi ne ja määritelläksesi " +"järjestelmäsi" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:110 +msgid "Welcome to OpenERP" +msgstr "Tervetuloa OpenERP järjestelmään" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:118 +msgid "Remember to bookmark" +msgstr "Muista luoda kirjainmerkki" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:119 +msgid "This url" +msgstr "Tämä osoite" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:121 +msgid "Your login:" +msgstr "Käyttäjätunnuksesi:" diff --git a/addons/web_dashboard/i18n/gl.po b/addons/web_dashboard/i18n/gl.po index 51aebc32968..7ef6b6b7ed5 100644 --- a/addons/web_dashboard/i18n/gl.po +++ b/addons/web_dashboard/i18n/gl.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-14 15:27+0100\n" -"PO-Revision-Date: 2012-02-13 23:18+0000\n" -"Last-Translator: Amós Oviedo \n" +"PO-Revision-Date: 2012-02-16 09:13+0000\n" +"Last-Translator: Vicente \n" "Language-Team: Galician \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-15 05:43+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:63 @@ -36,12 +36,12 @@ msgstr "Sen categorizar" #: addons/web_dashboard/static/src/js/dashboard.js:324 #, python-format msgid "Execute task \"%s\"" -msgstr "" +msgstr "Executar Tarefa \"%s\"" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:325 msgid "Mark this task as done" -msgstr "" +msgstr "Marcar esta tarefa como feita" #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:4 diff --git a/addons/web_dashboard/i18n/hr.po b/addons/web_dashboard/i18n/hr.po index 3f7b1aea322..da8a6b51116 100644 --- a/addons/web_dashboard/i18n/hr.po +++ b/addons/web_dashboard/i18n/hr.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-14 15:27+0100\n" -"PO-Revision-Date: 2012-02-08 08:52+0000\n" -"Last-Translator: Marijan Rajic \n" +"PO-Revision-Date: 2012-02-22 10:13+0000\n" +"Last-Translator: Goran Kliska \n" "Language-Team: Croatian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-15 05:43+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-23 04:56+0000\n" +"X-Generator: Launchpad (build 14855)\n" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:63 @@ -36,12 +36,12 @@ msgstr "Nekategorizirano" #: addons/web_dashboard/static/src/js/dashboard.js:324 #, python-format msgid "Execute task \"%s\"" -msgstr "" +msgstr "Izvrši zadatak \"%s\"" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:325 msgid "Mark this task as done" -msgstr "" +msgstr "Označi ovaj zadatak kao obavljen" #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:4 diff --git a/addons/web_dashboard/i18n/it.po b/addons/web_dashboard/i18n/it.po index a1659131545..0e87b0dd0e4 100644 --- a/addons/web_dashboard/i18n/it.po +++ b/addons/web_dashboard/i18n/it.po @@ -8,45 +8,45 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-14 15:27+0100\n" -"PO-Revision-Date: 2011-10-07 09:00+0000\n" +"PO-Revision-Date: 2012-02-16 21:54+0000\n" "Last-Translator: Davide Corio - agilebg.com \n" "Language-Team: Italian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-15 05:43+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:63 msgid "Edit Layout" -msgstr "" +msgstr "Modifica Layour" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:109 msgid "Are you sure you want to remove this item ?" -msgstr "" +msgstr "Sicuro di voler cancellare questo elemento?" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:316 msgid "Uncategorized" -msgstr "" +msgstr "Non categorizzato" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:324 #, python-format msgid "Execute task \"%s\"" -msgstr "" +msgstr "Esegui task \"%s\"" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:325 msgid "Mark this task as done" -msgstr "" +msgstr "Marca questa attività come completata" #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:4 msgid "Reset Layout.." -msgstr "" +msgstr "Reimposta Layout.." #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:6 @@ -56,22 +56,22 @@ msgstr "Ripristina" #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:8 msgid "Change Layout.." -msgstr "" +msgstr "Cambia Layout.." #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:10 msgid "Change Layout" -msgstr "" +msgstr "Cambia Layout" #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:27 msgid " " -msgstr "" +msgstr " " #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:28 msgid "Create" -msgstr "" +msgstr "Crea" #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:39 @@ -89,23 +89,25 @@ msgid "" "Click on the functionalites listed below to launch them and configure your " "system" msgstr "" +"Clicca sulla lista di funzionalità seguenti per eseguirle e configurare il " +"sistema" #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:110 msgid "Welcome to OpenERP" -msgstr "" +msgstr "Benvenuto su OpenERP" #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:118 msgid "Remember to bookmark" -msgstr "" +msgstr "Salva nei bookmark" #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:119 msgid "This url" -msgstr "" +msgstr "Questo url" #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:121 msgid "Your login:" -msgstr "" +msgstr "Il tuo login:" diff --git a/addons/web_dashboard/i18n/ja.po b/addons/web_dashboard/i18n/ja.po new file mode 100644 index 00000000000..177be1cc222 --- /dev/null +++ b/addons/web_dashboard/i18n/ja.po @@ -0,0 +1,111 @@ +# Japanese translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-03-06 06:40+0000\n" +"Last-Translator: Masaki Yamaya \n" +"Language-Team: Japanese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-07 05:38+0000\n" +"X-Generator: Launchpad (build 14907)\n" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:63 +msgid "Edit Layout" +msgstr "レイアウトを編集" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:109 +msgid "Are you sure you want to remove this item ?" +msgstr "この項目を取り除きますか?" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:316 +msgid "Uncategorized" +msgstr "未分類" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:324 +#, python-format +msgid "Execute task \"%s\"" +msgstr "タスク \"%s\" を実行" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:325 +msgid "Mark this task as done" +msgstr "このタスクを完了" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:4 +msgid "Reset Layout.." +msgstr "レイアウトをリセット" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:6 +msgid "Reset" +msgstr "リセット" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:8 +msgid "Change Layout.." +msgstr "レイアウトを変更…" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:10 +msgid "Change Layout" +msgstr "レイアウトを変更" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:27 +msgid " " +msgstr " " + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:28 +msgid "Create" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:39 +msgid "Choose dashboard layout" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:62 +msgid "progress:" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:67 +msgid "" +"Click on the functionalites listed below to launch them and configure your " +"system" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:110 +msgid "Welcome to OpenERP" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:118 +msgid "Remember to bookmark" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:119 +msgid "This url" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:121 +msgid "Your login:" +msgstr "" diff --git a/addons/web_dashboard/i18n/ka.po b/addons/web_dashboard/i18n/ka.po new file mode 100644 index 00000000000..d63c5c892cf --- /dev/null +++ b/addons/web_dashboard/i18n/ka.po @@ -0,0 +1,112 @@ +# Georgian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-03-15 18:30+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Georgian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-16 05:14+0000\n" +"X-Generator: Launchpad (build 14951)\n" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:63 +msgid "Edit Layout" +msgstr "განლაგების შეცვლა" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:109 +msgid "Are you sure you want to remove this item ?" +msgstr "დარწმუნებული ხართ რომ გსურთ ამ კომპონენტის წაშლა?" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:316 +msgid "Uncategorized" +msgstr "კატეგორიის გარეშე" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:324 +#, python-format +msgid "Execute task \"%s\"" +msgstr "შეასრულე ამოცანა \"%s\"" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:325 +msgid "Mark this task as done" +msgstr "მონიშნე ეს ამოცანა როგორც დასრულებული" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:4 +msgid "Reset Layout.." +msgstr "საწყისი განლაგება" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:6 +msgid "Reset" +msgstr "ხელახალი კონფიგურაცია" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:8 +msgid "Change Layout.." +msgstr "განლაგების შეცვლა.." + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:10 +msgid "Change Layout" +msgstr "განლაგების შეცვლა" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:27 +msgid " " +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:28 +msgid "Create" +msgstr "შექმნა" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:39 +msgid "Choose dashboard layout" +msgstr "აირჩიეთ საინფორმაციო დაფის განლაგება" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:62 +msgid "progress:" +msgstr "პროგრესი:" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:67 +msgid "" +"Click on the functionalites listed below to launch them and configure your " +"system" +msgstr "" +"დააწკაპუნეთ ქვემოთ ჩამოთვლილ ფუნქციონალზე რათა გაააქტიუროთ და დააკონფიგურიროთ" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:110 +msgid "Welcome to OpenERP" +msgstr "მოგესალმებით!" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:118 +msgid "Remember to bookmark" +msgstr "ჩაინიშნე ფავორიტებში" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:119 +msgid "This url" +msgstr "ეს URL" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:121 +msgid "Your login:" +msgstr "თქვენი მოხმარებელი:" diff --git a/addons/web_dashboard/i18n/nl.po b/addons/web_dashboard/i18n/nl.po index dd95b9d3ac6..591d41e22eb 100644 --- a/addons/web_dashboard/i18n/nl.po +++ b/addons/web_dashboard/i18n/nl.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-14 15:27+0100\n" -"PO-Revision-Date: 2012-02-15 14:38+0000\n" +"PO-Revision-Date: 2012-03-19 08:25+0000\n" "Last-Translator: Erwin \n" "Language-Team: Dutch \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-16 05:21+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-03-20 05:13+0000\n" +"X-Generator: Launchpad (build 14969)\n" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:63 @@ -100,14 +100,14 @@ msgstr "Welkom bij OpenERP" #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:118 msgid "Remember to bookmark" -msgstr "Bookmark maken" +msgstr "Vergeet niet een bladwijzer aan te maken van" #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:119 msgid "This url" -msgstr "Deze URL" +msgstr "Deze pagina" #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:121 msgid "Your login:" -msgstr "U login:" +msgstr "Uw login:" diff --git a/addons/web_dashboard/i18n/pt.po b/addons/web_dashboard/i18n/pt.po index 764fc53b6cc..2a7880b4cd9 100644 --- a/addons/web_dashboard/i18n/pt.po +++ b/addons/web_dashboard/i18n/pt.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-16 05:21+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:63 diff --git a/addons/web_dashboard/i18n/pt_BR.po b/addons/web_dashboard/i18n/pt_BR.po index 9cdc7dd4c21..24d2a5e194c 100644 --- a/addons/web_dashboard/i18n/pt_BR.po +++ b/addons/web_dashboard/i18n/pt_BR.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-16 05:21+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:63 diff --git a/addons/web_dashboard/i18n/ro.po b/addons/web_dashboard/i18n/ro.po new file mode 100644 index 00000000000..fc4743eae26 --- /dev/null +++ b/addons/web_dashboard/i18n/ro.po @@ -0,0 +1,111 @@ +# Romanian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-03-10 13:19+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Romanian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-11 04:56+0000\n" +"X-Generator: Launchpad (build 14914)\n" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:63 +msgid "Edit Layout" +msgstr "Editare aspect" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:109 +msgid "Are you sure you want to remove this item ?" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:316 +msgid "Uncategorized" +msgstr "Fără categorie" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:324 +#, python-format +msgid "Execute task \"%s\"" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/js/dashboard.js:325 +msgid "Mark this task as done" +msgstr "Marchează acestă sarcină ca realizată" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:4 +msgid "Reset Layout.." +msgstr "Restează aspect ..." + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:6 +msgid "Reset" +msgstr "Resetare" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:8 +msgid "Change Layout.." +msgstr "Schimbare aspect..." + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:10 +msgid "Change Layout" +msgstr "Modificare aspect" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:27 +msgid " " +msgstr " " + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:28 +msgid "Create" +msgstr "Crează" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:39 +msgid "Choose dashboard layout" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:62 +msgid "progress:" +msgstr "progres:" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:67 +msgid "" +"Click on the functionalites listed below to launch them and configure your " +"system" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:110 +msgid "Welcome to OpenERP" +msgstr "Bun venit in OpenERP" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:118 +msgid "Remember to bookmark" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:119 +msgid "This url" +msgstr "" + +#. openerp-web +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:121 +msgid "Your login:" +msgstr "" diff --git a/addons/web_dashboard/i18n/ru.po b/addons/web_dashboard/i18n/ru.po index 524a97f767e..bb857b9d478 100644 --- a/addons/web_dashboard/i18n/ru.po +++ b/addons/web_dashboard/i18n/ru.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-14 15:27+0100\n" -"PO-Revision-Date: 2012-02-08 07:12+0000\n" +"PO-Revision-Date: 2012-02-17 07:37+0000\n" "Last-Translator: Aleksei Motsik \n" "Language-Team: Russian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-15 05:43+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-18 05:18+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:63 @@ -36,12 +36,12 @@ msgstr "Без категории" #: addons/web_dashboard/static/src/js/dashboard.js:324 #, python-format msgid "Execute task \"%s\"" -msgstr "" +msgstr "Выполнить задачу \"%s\"" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:325 msgid "Mark this task as done" -msgstr "" +msgstr "Отметить завершенной" #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:4 diff --git a/addons/web_dashboard/i18n/tr.po b/addons/web_dashboard/i18n/tr.po index 1c953938fce..6cb6ed74d6c 100644 --- a/addons/web_dashboard/i18n/tr.po +++ b/addons/web_dashboard/i18n/tr.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-14 15:27+0100\n" -"PO-Revision-Date: 2012-02-09 20:10+0000\n" +"PO-Revision-Date: 2012-02-24 11:28+0000\n" "Last-Translator: Ahmet Altınışık \n" "Language-Team: Turkish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-15 05:43+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-25 05:30+0000\n" +"X-Generator: Launchpad (build 14860)\n" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:63 @@ -36,12 +36,12 @@ msgstr "Sınıflandırılmamış" #: addons/web_dashboard/static/src/js/dashboard.js:324 #, python-format msgid "Execute task \"%s\"" -msgstr "" +msgstr "Görevi Çalıştır \"%s\"" #. openerp-web #: addons/web_dashboard/static/src/js/dashboard.js:325 msgid "Mark this task as done" -msgstr "" +msgstr "Bu görevi yapıldı olarak işaretle" #. openerp-web #: addons/web_dashboard/static/src/xml/web_dashboard.xml:4 diff --git a/addons/web_dashboard/static/src/js/dashboard.js b/addons/web_dashboard/static/src/js/dashboard.js index 1ebc987c9f6..bae74276a24 100644 --- a/addons/web_dashboard/static/src/js/dashboard.js +++ b/addons/web_dashboard/static/src/js/dashboard.js @@ -10,7 +10,7 @@ if (!openerp.web_dashboard) { openerp.web.form.DashBoard = openerp.web.form.Widget.extend({ init: function(view, node) { this._super(view, node); - this.template = 'DashBoard'; + this.form_template = 'DashBoard'; this.actions_attrs = {}; this.action_managers = []; }, @@ -31,18 +31,16 @@ openerp.web.form.DashBoard = openerp.web.form.Widget.extend({ this.$element.delegate('.oe-dashboard-column .oe-dashboard-fold', 'click', this.on_fold_action); this.$element.delegate('.oe-dashboard-column .ui-icon-closethick', 'click', this.on_close_action); - this.actions_attrs = {}; // Init actions _.each(this.node.children, function(column, column_index) { _.each(column.children, function(action, action_index) { delete(action.attrs.width); delete(action.attrs.height); delete(action.attrs.colspan); - self.actions_attrs[action.attrs.name] = action.attrs; self.rpc('/web/action/load', { action_id: parseInt(action.attrs.name, 10) }, function(result) { - self.on_load_action(result, column_index + '_' + action_index); + self.on_load_action(result, column_index + '_' + action_index, action.attrs); }); }); }); @@ -58,7 +56,7 @@ openerp.web.form.DashBoard = openerp.web.form.Widget.extend({ var qdict = { current_layout : this.$element.find('.oe-dashboard').attr('data-layout') }; - var $dialog = $('
    ').dialog({ + var $dialog = openerp.web.dialog($('
    '), { modal: true, title: _t("Edit Layout"), width: 'auto', @@ -97,9 +95,9 @@ openerp.web.form.DashBoard = openerp.web.form.Widget.extend({ $action = $e.parents('.oe-dashboard-action:first'), id = parseInt($action.attr('data-id'), 10); if ($e.is('.ui-icon-minusthick')) { - this.actions_attrs[id].fold = '1'; + $action.data('action_attrs').fold = '1'; } else { - delete(this.actions_attrs[id].fold); + delete($action.data('action_attrs').fold); } $e.toggleClass('ui-icon-minusthick ui-icon-plusthick'); $action.find('.oe-dashboard-action-content').toggle(); @@ -122,7 +120,7 @@ openerp.web.form.DashBoard = openerp.web.form.Widget.extend({ var actions = []; $(this).find('.oe-dashboard-action').each(function() { var action_id = $(this).attr('data-id'), - new_attrs = _.clone(self.actions_attrs[action_id]); + new_attrs = _.clone($(this).data('action_attrs')); if (new_attrs.domain) { new_attrs.domain = new_attrs.domain_string; delete(new_attrs.domain_string); @@ -143,19 +141,25 @@ openerp.web.form.DashBoard = openerp.web.form.Widget.extend({ self.$element.find('.oe-dashboard-link-reset').show(); }); }, - on_load_action: function(result, index) { + on_load_action: function(result, index, action_attrs) { var self = this, action = result.result, - action_attrs = this.actions_attrs[action.id], view_mode = action_attrs.view_mode; - if (action_attrs.context) { - action.context = _.extend((action.context || {}), action_attrs.context); - } - if (action_attrs.domain) { - action.domain = action.domain || []; - action.domain.unshift.apply(action.domain, action_attrs.domain); + if (action_attrs.context && action_attrs.context['dashboard_merge_domains_contexts'] === false) { + // TODO: replace this 6.1 workaround by attribute on + action.context = action_attrs.context || {}; + action.domain = action_attrs.domain || []; + } else { + if (action_attrs.context) { + action.context = _.extend((action.context || {}), action_attrs.context); + } + if (action_attrs.domain) { + action.domain = action.domain || []; + action.domain.unshift.apply(action.domain, action_attrs.domain); + } } + var action_orig = _.extend({ flags : {} }, action); if (view_mode && view_mode != action.view_mode) { @@ -187,6 +191,7 @@ openerp.web.form.DashBoard = openerp.web.form.Widget.extend({ var am = new openerp.web.ActionManager(this), // FIXME: ideally the dashboard view shall be refactored like kanban. $action = $('#' + this.view.element_id + '_action_' + index); + $action.parent().data('action_attrs', action_attrs); this.action_managers.push(am); am.appendTo($action); am.do_action(action); @@ -225,7 +230,7 @@ openerp.web.form.DashBoard = openerp.web.form.Widget.extend({ }); } }, - render: function() { + renderElement: function() { // We should start with three columns available for (var i = this.node.children.length; i < 3; i++) { this.node.children.push({ @@ -234,17 +239,18 @@ openerp.web.form.DashBoard = openerp.web.form.Widget.extend({ children: [] }); } - return QWeb.render(this.template, this); + var rendered = QWeb.render(this.form_template, this); + this.$element.html(rendered); }, do_reload: function() { - var view_manager = this.view.widget_parent, - action_manager = view_manager.widget_parent; - this.view.stop(); + var view_manager = this.view.getParent(), + action_manager = view_manager.getParent(); + this.view.destroy(); action_manager.do_action(view_manager.action); } }); openerp.web.form.DashBoardLegacy = openerp.web.form.DashBoard.extend({ - render: function() { + renderElement: function() { if (this.node.tag == 'hpaned') { this.node.attrs.style = '2-1'; } else if (this.node.tag == 'vpaned') { @@ -263,7 +269,7 @@ openerp.web.form.DashBoardLegacy = openerp.web.form.DashBoard.extend({ } } }); - return this._super(this, arguments); + this._super(this); } }); @@ -340,7 +346,7 @@ openerp.web_dashboard.ConfigOverview = openerp.web.View.extend({ }); }) .delegate('li:not(.oe-done)', 'click', function () { - self.widget_parent.widget_parent.widget_parent.do_execute_action({ + self.getParent().getParent().getParent().do_execute_action({ type: 'object', name: 'action_launch' }, self.dataset, @@ -405,7 +411,6 @@ openerp.web_dashboard.ApplicationTiles = openerp.web.OldWidget.extend({ }, start: function() { var self = this; - openerp.webclient.menu.do_hide_secondary(); var domain = [['application','=',true], ['state','=','installed'], ['name', '!=', 'base']]; var ds = new openerp.web.DataSetSearch(this, 'ir.module.module',{},domain); ds.read_slice(['id']).then(function(result) { @@ -462,8 +467,8 @@ openerp.web_dashboard.ApplicationInstaller = openerp.web.OldWidget.extend({ }); return r; }, - stop: function() { - this.action_manager.stop(); + destroy: function() { + this.action_manager.destroy(); return this._super(); } }); diff --git a/addons/web_diagram/__openerp__.py b/addons/web_diagram/__openerp__.py index f46b17614b4..512c36d60e3 100644 --- a/addons/web_diagram/__openerp__.py +++ b/addons/web_diagram/__openerp__.py @@ -5,11 +5,11 @@ "version" : "2.0", "depends" : ["web"], "js": [ - 'static/lib/js/raphael-min.js', - 'static/lib/js/dracula_graffle.js', - 'static/lib/js/dracula_graph.js', - 'static/lib/js/dracula_algorithms.js', - 'static/src/js/diagram.js' + 'static/lib/js/raphael.js', + 'static/lib/js/jquery.mousewheel.js', + 'static/src/js/vec2.js', + 'static/src/js/graph.js', + 'static/src/js/diagram.js', ], 'css' : [ "static/src/css/base_diagram.css", @@ -17,5 +17,5 @@ 'qweb' : [ "static/src/xml/*.xml", ], - 'active': True, + 'auto_install': True, } diff --git a/addons/web_diagram/controllers/main.py b/addons/web_diagram/controllers/main.py index 3a8bd0c40e1..e3d626ad48b 100644 --- a/addons/web_diagram/controllers/main.py +++ b/addons/web_diagram/controllers/main.py @@ -115,8 +115,8 @@ class DiagramView(View): for i, fld in enumerate(visible_node_fields): n['options'][node_fields_string[i]] = act[fld] - id_model = req.session.model(model).read([id],['name'], req.session.context)[0]['name'] + _id, name = req.session.model(model).name_get([id], req.session.context)[0] return dict(nodes=nodes, conn=connectors, - id_model=id_model, + name=name, parent_field=graphs['node_parent_field']) diff --git a/addons/web_diagram/i18n/es_CR.po b/addons/web_diagram/i18n/es_CR.po index 52f18170821..3c229025f87 100644 --- a/addons/web_diagram/i18n/es_CR.po +++ b/addons/web_diagram/i18n/es_CR.po @@ -8,15 +8,16 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2012-02-06 17:33+0100\n" -"PO-Revision-Date: 2012-02-08 02:25-0600\n" -"Last-Translator: Carlos Vásquez - CLEARCORP \n" +"PO-Revision-Date: 2012-02-16 21:35+0000\n" +"Last-Translator: Carlos Vásquez (CLEARCORP) " +"\n" "Language-Team: Spanish \n" -"Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-07 04:59+0000\n" -"X-Generator: Launchpad (build 14747)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" +"Language: es\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 @@ -41,10 +42,9 @@ msgstr "Crear:" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:231 msgid "Open: " -msgstr "Abrir:" +msgstr "Abrir: " #. openerp-web #: addons/web_diagram/static/src/xml/base_diagram.xml:5 msgid "New Node" msgstr "Nuevo Nodo" - diff --git a/addons/web_diagram/i18n/fi.po b/addons/web_diagram/i18n/fi.po new file mode 100644 index 00000000000..e854ea43729 --- /dev/null +++ b/addons/web_diagram/i18n/fi.po @@ -0,0 +1,57 @@ +# Finnish translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-03-19 11:59+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Finnish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-20 05:13+0000\n" +"X-Generator: Launchpad (build 14969)\n" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:11 +msgid "Diagram" +msgstr "Kaavio" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:208 +#: addons/web_diagram/static/src/js/diagram.js:224 +#: addons/web_diagram/static/src/js/diagram.js:257 +msgid "Activity" +msgstr "Aktiviteetti" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:208 +#: addons/web_diagram/static/src/js/diagram.js:289 +#: addons/web_diagram/static/src/js/diagram.js:308 +msgid "Transition" +msgstr "Siirtyminen" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:214 +#: addons/web_diagram/static/src/js/diagram.js:262 +#: addons/web_diagram/static/src/js/diagram.js:314 +msgid "Create:" +msgstr "Luo:" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:231 +#: addons/web_diagram/static/src/js/diagram.js:232 +#: addons/web_diagram/static/src/js/diagram.js:296 +msgid "Open: " +msgstr "Avaa: " + +#. openerp-web +#: addons/web_diagram/static/src/xml/base_diagram.xml:5 +#: addons/web_diagram/static/src/xml/base_diagram.xml:6 +msgid "New Node" +msgstr "Uusi Noodi" diff --git a/addons/web_diagram/i18n/it.po b/addons/web_diagram/i18n/it.po index ef8a8f5a847..8930ef24f24 100644 --- a/addons/web_diagram/i18n/it.po +++ b/addons/web_diagram/i18n/it.po @@ -8,39 +8,39 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-06 17:33+0100\n" -"PO-Revision-Date: 2011-10-08 13:41+0000\n" -"Last-Translator: Nicola Riolini - Micronaet \n" +"PO-Revision-Date: 2012-02-16 21:55+0000\n" +"Last-Translator: Davide Corio - agilebg.com \n" "Language-Team: Italian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-07 04:59+0000\n" -"X-Generator: Launchpad (build 14747)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:11 msgid "Diagram" -msgstr "" +msgstr "Diagramma" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:208 msgid "Activity" -msgstr "" +msgstr "Attività" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:208 msgid "Transition" -msgstr "" +msgstr "Transizione" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:214 msgid "Create:" -msgstr "" +msgstr "Crea:" #. openerp-web #: addons/web_diagram/static/src/js/diagram.js:231 msgid "Open: " -msgstr "" +msgstr "Apri: " #. openerp-web #: addons/web_diagram/static/src/xml/base_diagram.xml:5 diff --git a/addons/web_diagram/i18n/ka.po b/addons/web_diagram/i18n/ka.po new file mode 100644 index 00000000000..9799633a9c8 --- /dev/null +++ b/addons/web_diagram/i18n/ka.po @@ -0,0 +1,57 @@ +# Georgian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-03-15 19:00+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Georgian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-16 05:14+0000\n" +"X-Generator: Launchpad (build 14951)\n" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:11 +msgid "Diagram" +msgstr "დიაგრამა" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:208 +#: addons/web_diagram/static/src/js/diagram.js:224 +#: addons/web_diagram/static/src/js/diagram.js:257 +msgid "Activity" +msgstr "აქტივობა" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:208 +#: addons/web_diagram/static/src/js/diagram.js:289 +#: addons/web_diagram/static/src/js/diagram.js:308 +msgid "Transition" +msgstr "გარდაქმნა" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:214 +#: addons/web_diagram/static/src/js/diagram.js:262 +#: addons/web_diagram/static/src/js/diagram.js:314 +msgid "Create:" +msgstr "შექმნა:" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:231 +#: addons/web_diagram/static/src/js/diagram.js:232 +#: addons/web_diagram/static/src/js/diagram.js:296 +msgid "Open: " +msgstr "ღია: " + +#. openerp-web +#: addons/web_diagram/static/src/xml/base_diagram.xml:5 +#: addons/web_diagram/static/src/xml/base_diagram.xml:6 +msgid "New Node" +msgstr "ახალი კვანძი" diff --git a/addons/web_diagram/i18n/ro.po b/addons/web_diagram/i18n/ro.po new file mode 100644 index 00000000000..050bb6837ce --- /dev/null +++ b/addons/web_diagram/i18n/ro.po @@ -0,0 +1,57 @@ +# Romanian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-03-19 23:14+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Romanian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-21 05:21+0000\n" +"X-Generator: Launchpad (build 14981)\n" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:11 +msgid "Diagram" +msgstr "Diagramă" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:208 +#: addons/web_diagram/static/src/js/diagram.js:224 +#: addons/web_diagram/static/src/js/diagram.js:257 +msgid "Activity" +msgstr "Activitate" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:208 +#: addons/web_diagram/static/src/js/diagram.js:289 +#: addons/web_diagram/static/src/js/diagram.js:308 +msgid "Transition" +msgstr "Tranziție" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:214 +#: addons/web_diagram/static/src/js/diagram.js:262 +#: addons/web_diagram/static/src/js/diagram.js:314 +msgid "Create:" +msgstr "" + +#. openerp-web +#: addons/web_diagram/static/src/js/diagram.js:231 +#: addons/web_diagram/static/src/js/diagram.js:232 +#: addons/web_diagram/static/src/js/diagram.js:296 +msgid "Open: " +msgstr "Deschide: " + +#. openerp-web +#: addons/web_diagram/static/src/xml/base_diagram.xml:5 +#: addons/web_diagram/static/src/xml/base_diagram.xml:6 +msgid "New Node" +msgstr "Nod Nou" diff --git a/addons/web_diagram/static/lib/js/jquery.mousewheel.js b/addons/web_diagram/static/lib/js/jquery.mousewheel.js new file mode 100644 index 00000000000..38b60951b20 --- /dev/null +++ b/addons/web_diagram/static/lib/js/jquery.mousewheel.js @@ -0,0 +1,84 @@ +/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net) + * Licensed under the MIT License (LICENSE.txt). + * + * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. + * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. + * Thanks to: Seamus Leahy for adding deltaX and deltaY + * + * Version: 3.0.6 + * + * Requires: 1.2.2+ + */ + +(function($) { + +var types = ['DOMMouseScroll', 'mousewheel']; + +if ($.event.fixHooks) { + for ( var i=types.length; i; ) { + $.event.fixHooks[ types[--i] ] = $.event.mouseHooks; + } +} + +$.event.special.mousewheel = { + setup: function() { + if ( this.addEventListener ) { + for ( var i=types.length; i; ) { + this.addEventListener( types[--i], handler, false ); + } + } else { + this.onmousewheel = handler; + } + }, + + teardown: function() { + if ( this.removeEventListener ) { + for ( var i=types.length; i; ) { + this.removeEventListener( types[--i], handler, false ); + } + } else { + this.onmousewheel = null; + } + } +}; + +$.fn.extend({ + mousewheel: function(fn) { + return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel"); + }, + + unmousewheel: function(fn) { + return this.unbind("mousewheel", fn); + } +}); + + +function handler(event) { + var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0; + event = $.event.fix(orgEvent); + event.type = "mousewheel"; + + // Old school scrollwheel delta + if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta/120; } + if ( orgEvent.detail ) { delta = -orgEvent.detail/3; } + + // New school multidimensional scroll (touchpads) deltas + deltaY = delta; + + // Gecko + if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) { + deltaY = 0; + deltaX = -1*delta; + } + + // Webkit + if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; } + if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; } + + // Add event and delta to the front of the arguments + args.unshift(event, delta, deltaX, deltaY); + + return ($.event.dispatch || $.event.handle).apply(this, args); +} + +})(jQuery); diff --git a/addons/web_diagram/static/lib/js/raphael-min.js b/addons/web_diagram/static/lib/js/raphael-min.js deleted file mode 100644 index e69ea16a809..00000000000 --- a/addons/web_diagram/static/lib/js/raphael-min.js +++ /dev/null @@ -1,8 +0,0 @@ -// ┌─────────────────────────────────────────────────────────────────────┐ \\ -// │ Raphaël 2.0 - JavaScript Vector Library │ \\ -// ├─────────────────────────────────────────────────────────────────────┤ \\ -// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ -// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ -// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ -// └─────────────────────────────────────────────────────────────────────┘ \\ -(function(a){var b="0.3.2",c="hasOwnProperty",d=/[\.\/]/,e="*",f=function(){},g=function(a,b){return a-b},h,i,j={n:{}},k=function(a,b){var c=j,d=i,e=Array.prototype.slice.call(arguments,2),f=k.listeners(a),l=0,m=!1,n,o=[],p={},q=[],r=[];h=a,i=0;for(var s=0,t=f.length;sf*b.top){e=b.percents[y],p=b.percents[y-1]||0,t=t/b.top*(e-p),o=b.percents[y+1],j=b.anim[e];break}f&&d.attr(b.anim[b.percents[y]])}if(!!j){if(!k){for(attr in j)if(j[g](attr))if(U[g](attr)||d.paper.customAttributes[g](attr)){u[attr]=d.attr(attr),u[attr]==null&&(u[attr]=T[attr]),v[attr]=j[attr];switch(U[attr]){case C:w[attr]=(v[attr]-u[attr])/t;break;case"colour":u[attr]=a.getRGB(u[attr]);var A=a.getRGB(v[attr]);w[attr]={r:(A.r-u[attr].r)/t,g:(A.g-u[attr].g)/t,b:(A.b-u[attr].b)/t};break;case"path":var B=bG(u[attr],v[attr]),D=B[1];u[attr]=B[0],w[attr]=[];for(y=0,z=u[attr].length;yd)return d;while(cf?c=e:d=e,e=(d-c)/2+c}return e}function n(a,b){var c=o(a,b);return((l*c+k)*c+j)*c}function m(a){return((i*a+h)*a+g)*a}var g=3*b,h=3*(d-b)-g,i=1-g-h,j=3*c,k=3*(e-c)-j,l=1-j-k;return n(a,1/(200*f))}function cd(){return this.x+q+this.y+q+this.width+" × "+this.height}function cc(){return this.x+q+this.y}function bR(a,b,c,d,e,f){a!=null?(this.a=+a,this.b=+b,this.c=+c,this.d=+d,this.e=+e,this.f=+f):(this.a=1,this.b=0,this.c=0,this.d=1,this.e=0,this.f=0)}function bw(a){var b=[];for(var c=0,d=a.length;d-2>c;c+=2){var e=[{x:+a[c],y:+a[c+1]},{x:+a[c],y:+a[c+1]},{x:+a[c+2],y:+a[c+3]},{x:+a[c+4],y:+a[c+5]}];d-4==c?(e[0]={x:+a[c-2],y:+a[c-1]},e[3]=e[2]):c&&(e[0]={x:+a[c-2],y:+a[c-1]}),b.push(["C",(-e[0].x+6*e[1].x+e[2].x)/6,(-e[0].y+6*e[1].y+e[2].y)/6,(e[1].x+6*e[2].x-e[3].x)/6,(e[1].y+6*e[2].y-e[3].y)/6,e[2].x,e[2].y])}return b}function bv(){return this.hex}function bt(a,b,c){function d(){var e=Array.prototype.slice.call(arguments,0),f=e.join("␀"),h=d.cache=d.cache||{},i=d.count=d.count||[];if(h[g](f)){bs(i,f);return c?c(h[f]):h[f]}i.length>=1e3&&delete h[i.shift()],i.push(f),h[f]=a[m](b,e);return c?c(h[f]):h[f]}return d}function bs(a,b){for(var c=0,d=a.length;c',bk=bj.firstChild,bk.style.behavior="url(#default#VML)";if(!bk||typeof bk.adj!="object")return a.type=p;bj=null}a.svg=!(a.vml=a.type=="VML"),a._Paper=j,a.fn=k=j.prototype=a.prototype,a._id=0,a._oid=0,a.is=function(a,b){b=v.call(b);if(b=="finite")return!M[g](+a);if(b=="array")return a instanceof Array;return b=="null"&&a===null||b==typeof a&&a!==null||b=="object"&&a===Object(a)||b=="array"&&Array.isArray&&Array.isArray(a)||H.call(a).slice(8,-1).toLowerCase()==b},a.angle=function(b,c,d,e,f,g){if(f==null){var h=b-d,i=c-e;if(!h&&!i)return 0;return(180+w.atan2(-i,-h)*180/B+360)%360}return a.angle(b,c,f,g)-a.angle(d,e,f,g)},a.rad=function(a){return a%360*B/180},a.deg=function(a){return a*180/B%360},a.snapTo=function(b,c,d){d=a.is(d,"finite")?d:10;if(a.is(b,E)){var e=b.length;while(e--)if(z(b[e]-c)<=d)return b[e]}else{b=+b;var f=c%b;if(fb-d)return c-f+b}return c};var bl=a.createUUID=function(a,b){return function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(a,b).toUpperCase()}}(/[xy]/g,function(a){var b=w.random()*16|0,c=a=="x"?b:b&3|8;return c.toString(16)});a.setWindow=function(b){eve("setWindow",a,h.win,b),h.win=b,h.doc=h.win.document,initWin&&initWin(h.win)};var bm=function(b){if(a.vml){var c=/^\s+|\s+$/g,d;try{var e=new ActiveXObject("htmlfile");e.write(""),e.close(),d=e.body}catch(f){d=createPopup().document.body}var g=d.createTextRange();bm=bt(function(a){try{d.style.color=r(a).replace(c,p);var b=g.queryCommandValue("ForeColor");b=(b&255)<<16|b&65280|(b&16711680)>>>16;return"#"+("000000"+b.toString(16)).slice(-6)}catch(e){return"none"}})}else{var i=h.doc.createElement("i");i.title="Raphaël Colour Picker",i.style.display="none",h.doc.body.appendChild(i),bm=bt(function(a){i.style.color=a;return h.doc.defaultView.getComputedStyle(i,p).getPropertyValue("color")})}return bm(b)},bn=function(){return"hsb("+[this.h,this.s,this.b]+")"},bo=function(){return"hsl("+[this.h,this.s,this.l]+")"},bp=function(){return this.hex},bq=function(b,c,d){c==null&&a.is(b,"object")&&"r"in b&&"g"in b&&"b"in b&&(d=b.b,c=b.g,b=b.r);if(c==null&&a.is(b,D)){var e=a.getRGB(b);b=e.r,c=e.g,d=e.b}if(b>1||c>1||d>1)b/=255,c/=255,d/=255;return[b,c,d]},br=function(b,c,d,e){b*=255,c*=255,d*=255;var f={r:b,g:c,b:d,hex:a.rgb(b,c,d),toString:bp};a.is(e,"finite")&&(f.opacity=e);return f};a.color=function(b){var c;a.is(b,"object")&&"h"in b&&"s"in b&&"b"in b?(c=a.hsb2rgb(b),b.r=c.r,b.g=c.g,b.b=c.b,b.hex=c.hex):a.is(b,"object")&&"h"in b&&"s"in b&&"l"in b?(c=a.hsl2rgb(b),b.r=c.r,b.g=c.g,b.b=c.b,b.hex=c.hex):(a.is(b,"string")&&(b=a.getRGB(b)),a.is(b,"object")&&"r"in b&&"g"in b&&"b"in b?(c=a.rgb2hsl(b),b.h=c.h,b.s=c.s,b.l=c.l,c=a.rgb2hsb(b),b.v=c.b):(b={hex:"none"},crl.r=b.g=b.b=b.h=b.s=b.v=b.l=-1)),b.toString=bp;return b},a.hsb2rgb=function(a,b,c,d){this.is(a,"object")&&"h"in a&&"s"in a&&"b"in a&&(c=a.b,b=a.s,a=a.h,d=a.o),a*=360;var e,f,g,h,i;a=a%360/60,i=c*b,h=i*(1-z(a%2-1)),e=f=g=c-i,a=~~a,e+=[i,h,0,0,h,i][a],f+=[h,i,i,h,0,0][a],g+=[0,0,h,i,i,h][a];return br(e,f,g,d)},a.hsl2rgb=function(a,b,c,d){this.is(a,"object")&&"h"in a&&"s"in a&&"l"in a&&(c=a.l,b=a.s,a=a.h);if(a>1||b>1||c>1)a/=360,b/=100,c/=100;a*=360;var e,f,g,h,i;a=a%360/60,i=2*b*(c<.5?c:1-c),h=i*(1-z(a%2-1)),e=f=g=c-i/2,a=~~a,e+=[i,h,0,0,h,i][a],f+=[h,i,i,h,0,0][a],g+=[0,0,h,i,i,h][a];return br(e,f,g,d)},a.rgb2hsb=function(a,b,c){c=bq(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g;f=x(a,b,c),g=f-y(a,b,c),d=g==0?null:f==a?(b-c)/g:f==b?(c-a)/g+2:(a-b)/g+4,d=(d+360)%6*60/360,e=g==0?0:g/f;return{h:d,s:e,b:f,toString:bn}},a.rgb2hsl=function(a,b,c){c=bq(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g,h,i;g=x(a,b,c),h=y(a,b,c),i=g-h,d=i==0?null:g==a?(b-c)/i:g==b?(c-a)/i+2:(a-b)/i+4,d=(d+360)%6*60/360,f=(g+h)/2,e=i==0?0:f<.5?i/(2*f):i/(2-2*f);return{h:d,s:e,l:f,toString:bo}},a._path2string=function(){return this.join(",").replace(X,"$1")};var bu=a._preload=function(a,b){var c=h.doc.createElement("img");c.style.cssText="position:absolute;left:-9999em;top-9999em",c.onload=function(){b.call(this),this.onload=null,h.doc.body.removeChild(this)},c.onerror=function(){h.doc.body.removeChild(this)},h.doc.body.appendChild(c),c.src=a};a.getRGB=bt(function(b){if(!b||!!((b=r(b)).indexOf("-")+1))return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:bv};if(b=="none")return{r:-1,g:-1,b:-1,hex:"none",toString:bv};!W[g](b.toLowerCase().substring(0,2))&&b.charAt()!="#"&&(b=bm(b));var c,d,e,f,h,i,j,k=b.match(L);if(k){k[2]&&(f=R(k[2].substring(5),16),e=R(k[2].substring(3,5),16),d=R(k[2].substring(1,3),16)),k[3]&&(f=R((i=k[3].charAt(3))+i,16),e=R((i=k[3].charAt(2))+i,16),d=R((i=k[3].charAt(1))+i,16)),k[4]&&(j=k[4][s](V),d=Q(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)=="%"&&(f*=2.55),k[1].toLowerCase().slice(0,4)=="rgba"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100));if(k[5]){j=k[5][s](V),d=Q(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)=="%"&&(f*=2.55),(j[0].slice(-3)=="deg"||j[0].slice(-1)=="°")&&(d/=360),k[1].toLowerCase().slice(0,4)=="hsba"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100);return a.hsb2rgb(d,e,f,h)}if(k[6]){j=k[6][s](V),d=Q(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)=="%"&&(f*=2.55),(j[0].slice(-3)=="deg"||j[0].slice(-1)=="°")&&(d/=360),k[1].toLowerCase().slice(0,4)=="hsla"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100);return a.hsl2rgb(d,e,f,h)}k={r:d,g:e,b:f,toString:bv},k.hex="#"+(16777216|f|e<<8|d<<16).toString(16).slice(1),a.is(h,"finite")&&(k.opacity=h);return k}return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:bv}},a),a.hsb=bt(function(b,c,d){return a.hsb2rgb(b,c,d).hex}),a.hsl=bt(function(b,c,d){return a.hsl2rgb(b,c,d).hex}),a.rgb=bt(function(a,b,c){return"#"+(16777216|c|b<<8|a<<16).toString(16).slice(1)}),a.getColor=function(a){var b=this.getColor.start=this.getColor.start||{h:0,s:1,b:a||.75},c=this.hsb2rgb(b.h,b.s,b.b);b.h+=.075,b.h>1&&(b.h=0,b.s-=.2,b.s<=0&&(this.getColor.start={h:0,s:1,b:b.b}));return c.hex},a.getColor.reset=function(){delete this.start},a.parsePathString=bt(function(b){if(!b)return null;var c={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0},d=[];a.is(b,E)&&a.is(b[0],E)&&(d=by(b)),d.length||r(b).replace(Y,function(a,b,e){var f=[],g=b.toLowerCase();e.replace($,function(a,b){b&&f.push(+b)}),g=="m"&&f.length>2&&(d.push([b][n](f.splice(0,2))),g="l",b=b=="m"?"l":"L");if(g=="r")d.push([b][n](f));else while(f.length>=c[g]){d.push([b][n](f.splice(0,c[g])));if(!c[g])break}}),d.toString=a._path2string;return d}),a.parseTransformString=bt(function(b){if(!b)return null;var c={r:3,s:4,t:2,m:6},d=[];a.is(b,E)&&a.is(b[0],E)&&(d=by(b)),d.length||r(b).replace(Z,function(a,b,c){var e=[],f=v.call(b);c.replace($,function(a,b){b&&e.push(+b)}),d.push([b][n](e))}),d.toString=a._path2string;return d}),a.findDotsAtSegment=function(a,b,c,d,e,f,g,h,i){var j=1-i,k=A(j,3),l=A(j,2),m=i*i,n=m*i,o=k*a+l*3*i*c+j*3*i*i*e+n*g,p=k*b+l*3*i*d+j*3*i*i*f+n*h,q=a+2*i*(c-a)+m*(e-2*c+a),r=b+2*i*(d-b)+m*(f-2*d+b),s=c+2*i*(e-c)+m*(g-2*e+c),t=d+2*i*(f-d)+m*(h-2*f+d),u=j*a+i*c,v=j*b+i*d,x=j*e+i*g,y=j*f+i*h,z=90-w.atan2(q-s,r-t)*180/B;(q>s||r1&&(v=w.sqrt(v),c=v*c,d=v*d);var x=c*c,y=d*d,A=(f==g?-1:1)*w.sqrt(z((x*y-x*u*u-y*t*t)/(x*u*u+y*t*t))),C=A*c*u/d+(a+h)/2,D=A*-d*t/c+(b+i)/2,E=w.asin(((b-D)/d).toFixed(9)),F=w.asin(((i-D)/d).toFixed(9));E=aF&&(E=E-B*2),!g&&F>E&&(F=F-B*2)}else E=j[0],F=j[1],C=j[2],D=j[3];var G=F-E;if(z(G)>k){var H=F,I=h,J=i;F=E+k*(g&&F>E?1:-1),h=C+c*w.cos(F),i=D+d*w.sin(F),m=bD(h,i,c,d,e,0,g,I,J,[F,H,C,D])}G=F-E;var K=w.cos(E),L=w.sin(E),M=w.cos(F),N=w.sin(F),O=w.tan(G/4),P=4/3*c*O,Q=4/3*d*O,R=[a,b],S=[a+P*L,b-Q*K],T=[h+P*N,i-Q*M],U=[h,i];S[0]=2*R[0]-S[0],S[1]=2*R[1]-S[1];if(j)return[S,T,U][n](m);m=[S,T,U][n](m).join()[s](",");var V=[];for(var W=0,X=m.length;W"1e12"&&(l=.5),z(n)>"1e12"&&(n=.5),l>0&&l<1&&(q=bE(a,b,c,d,e,f,g,h,l),p.push(q.x),o.push(q.y)),n>0&&n<1&&(q=bE(a,b,c,d,e,f,g,h,n),p.push(q.x),o.push(q.y)),i=f-2*d+b-(h-2*f+d),j=2*(d-b)-2*(f-d),k=b-d,l=(-j+w.sqrt(j*j-4*i*k))/2/i,n=(-j-w.sqrt(j*j-4*i*k))/2/i,z(l)>"1e12"&&(l=.5),z(n)>"1e12"&&(n=.5),l>0&&l<1&&(q=bE(a,b,c,d,e,f,g,h,l),p.push(q.x),o.push(q.y)),n>0&&n<1&&(q=bE(a,b,c,d,e,f,g,h,n),p.push(q.x),o.push(q.y));return{min:{x:y[m](0,p),y:y[m](0,o)},max:{x:x[m](0,p),y:x[m](0,o)}}}),bG=a._path2curve=bt(function(a,b){var c=bA(a),d=b&&bA(b),e={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},f={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},g=function(a,b){var c,d;if(!a)return["C",b.x,b.y,b.x,b.y,b.x,b.y];!(a[0]in{T:1,Q:1})&&(b.qx=b.qy=null);switch(a[0]){case"M":b.X=a[1],b.Y=a[2];break;case"A":a=["C"][n](bD[m](0,[b.x,b.y][n](a.slice(1))));break;case"S":c=b.x+(b.x-(b.bx||b.x)),d=b.y+(b.y-(b.by||b.y)),a=["C",c,d][n](a.slice(1));break;case"T":b.qx=b.x+(b.x-(b.qx||b.x)),b.qy=b.y+(b.y-(b.qy||b.y)),a=["C"][n](bC(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case"Q":b.qx=a[1],b.qy=a[2],a=["C"][n](bC(b.x,b.y,a[1],a[2],a[3],a[4]));break;case"L":a=["C"][n](bB(b.x,b.y,a[1],a[2]));break;case"H":a=["C"][n](bB(b.x,b.y,a[1],b.y));break;case"V":a=["C"][n](bB(b.x,b.y,b.x,a[1]));break;case"Z":a=["C"][n](bB(b.x,b.y,b.X,b.Y))}return a},h=function(a,b){if(a[b].length>7){a[b].shift();var e=a[b];while(e.length)a.splice(b++,0,["C"][n](e.splice(0,6)));a.splice(b,1),k=x(c.length,d&&d.length||0)}},i=function(a,b,e,f,g){a&&b&&a[g][0]=="M"&&b[g][0]!="M"&&(b.splice(g,0,["M",f.x,f.y]),e.bx=0,e.by=0,e.x=a[g][1],e.y=a[g][2],k=x(c.length,d&&d.length||0))};for(var j=0,k=x(c.length,d&&d.length||0);j=j)return p;o=p}if(j==null)return k},cg=function(b,c){return function(d,e,f){d=bG(d);var g,h,i,j,k="",l={},m,n=0;for(var o=0,p=d.length;oe){if(c&&!l.start){m=cf(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n),k+=["C"+m.start.x,m.start.y,m.m.x,m.m.y,m.x,m.y];if(f)return k;l.start=k,k=["M"+m.x,m.y+"C"+m.n.x,m.n.y,m.end.x,m.end.y,i[5],i[6]].join(),n+=j,g=+i[5],h=+i[6];continue}if(!b&&!c){m=cf(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n);return{x:m.x,y:m.y,alpha:m.alpha}}}n+=j,g=+i[5],h=+i[6]}k+=i.shift()+i}l.end=k,m=b?n:c?l:a.findDotsAtSegment(g,h,i[0],i[1],i[2],i[3],i[4],i[5],1),m.alpha&&(m={x:m.x,y:m.y,alpha:m.alpha});return m}},ch=cg(1),ci=cg(),cj=cg(0,1);a.getTotalLength=ch,a.getPointAtLength=ci,a.getSubpath=function(a,b,c){if(this.getTotalLength(a)-c<1e-6)return cj(a,b).end;var d=cj(a,c,1);return b?cj(d,b).end:d},b_.getTotalLength=function(){if(this.type=="path"){if(this.node.getTotalLength)return this.node.getTotalLength();return ch(this.attrs.path)}},b_.getPointAtLength=function(a){if(this.type=="path")return ci(this.attrs.path,a)},b_.getSubpath=function(b,c){if(this.type=="path")return a.getSubpath(this.attrs.path,b,c)};var ck=a.easing_formulas={linear:function(a){return a},"<":function(a){return A(a,1.7)},">":function(a){return A(a,.48)},"<>":function(a){var b=.48-a/1.04,c=w.sqrt(.1734+b*b),d=c-b,e=A(z(d),1/3)*(d<0?-1:1),f=-c-b,g=A(z(f),1/3)*(f<0?-1:1),h=e+g+.5;return(1-h)*3*h*h+h*h*h},backIn:function(a){var b=1.70158;return a*a*((b+1)*a-b)},backOut:function(a){a=a-1;var b=1.70158;return a*a*((b+1)*a+b)+1},elastic:function(a){if(a==!!a)return a;return A(2,-10*a)*w.sin((a-.075)*2*B/.3)+1},bounce:function(a){var b=7.5625,c=2.75,d;a<1/c?d=b*a*a:a<2/c?(a-=1.5/c,d=b*a*a+.75):a<2.5/c?(a-=2.25/c,d=b*a*a+.9375):(a-=2.625/c,d=b*a*a+.984375);return d}};ck.easeIn=ck["ease-in"]=ck["<"],ck.easeOut=ck["ease-out"]=ck[">"],ck.easeInOut=ck["ease-in-out"]=ck["<>"],ck["back-in"]=ck.backIn,ck["back-out"]=ck.backOut;var cl=[],cm=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){setTimeout(a,16)},cn=function(){var b=+(new Date),c=0;for(;c1&&!d.next){for(s in k)k[g](s)&&(r[s]=d.totalOrigin[s]);d.el.attr(r),cr(d.anim,d.el,d.anim.percents[0],null,d.totalOrigin,d.repeat-1)}d.next&&!d.stop&&cr(d.anim,d.el,d.next,null,d.totalOrigin,d.repeat)}}a.svg&&m&&m.paper&&m.paper.safari(),cl.length&&cm(cn)},co=function(a){return a>255?255:a<0?0:a};b_.animateWith=function(b,c,d,e,f,g){var h=d?a.animation(d,e,f,g):c;status=b.status(c);return this.animate(h).status(h,status*c.ms/h.ms)},b_.onAnimation=function(a){a?eve.on("anim.frame."+this.id,a):eve.unbind("anim.frame."+this.id);return this},cq.prototype.delay=function(a){var b=new cq(this.anim,this.ms);b.times=this.times,b.del=+a||0;return b},cq.prototype.repeat=function(a){var b=new cq(this.anim,this.ms);b.del=this.del,b.times=w.floor(x(a,0))||1;return b},a.animation=function(b,c,d,e){if(b instanceof cq)return b;if(a.is(d,"function")||!d)e=e||d||null,d=null;b=Object(b),c=+c||0;var f={},h,i;for(i in b)b[g](i)&&Q(i)!=i&&Q(i)+"%"!=i&&(h=!0,f[i]=b[i]);if(!h)return new cq(b,c);d&&(f.easing=d),e&&(f.callback=e);return new cq({100:f},c)},b_.animate=function(b,c,d,e){var f=this;if(f.removed){e&&e.call(f);return f}var g=b instanceof cq?b:a.animation(b,c,d,e);cr(g,f,g.percents[0],null,f.attr());return f},b_.setTime=function(a,b){a&&b!=null&&this.status(a,y(b,a.ms)/a.ms);return this},b_.status=function(a,b){var c=[],d=0,e,f;if(b!=null){cr(a,this,-1,y(b,1));return this}e=cl.length;for(;d.5)*2-1;i(m-.5,2)+i(n-.5,2)>.25&&(n=f.sqrt(.25-i(m-.5,2))*e+.5)&&n!=.5&&(n=n.toFixed(5)-1e-5*e)}return l}),e=e.split(/\s*\-\s*/);if(j=="linear"){var t=e.shift();t=-d(t);if(isNaN(t))return null;var u=[0,0,f.cos(a.rad(t)),f.sin(a.rad(t))],v=1/(g(h(u[2]),h(u[3]))||1);u[2]*=v,u[3]*=v,u[2]<0&&(u[0]=-u[2],u[2]=0),u[3]<0&&(u[1]=-u[3],u[3]=0)}var w=a._parseDots(e);if(!w)return null;b.gradient&&(p.defs.removeChild(b.gradient),delete b.gradient),k=k.replace(/[\(\)\s,\xb0#]/g,"-"),s=q(j+"Gradient",{id:k}),b.gradient=s,q(s,j=="radial"?{fx:m,fy:n}:{x1:u[0],y1:u[1],x2:u[2],y2:u[3],gradientTransform:b.matrix.invert()}),p.defs.appendChild(s);for(var x=0,y=w.length;x1?E.opacity/100:E.opacity});case"stroke":E=a.getRGB(p),i.setAttribute(o,E.hex),o=="stroke"&&E[b]("opacity")&&q(i,{"stroke-opacity":E.opacity>1?E.opacity/100:E.opacity}),o=="stroke"&&d._.arrows&&("startString"in d._.arrows&&w(d,d._.arrows.startString),"endString"in d._.arrows&&w(d,d._.arrows.endString,1));break;case"gradient":(d.type=="circle"||d.type=="ellipse"||c(p).charAt()!="r")&&u(d,p);break;case"opacity":k.gradient&&!k[b]("stroke-opacity")&&q(i,{"stroke-opacity":p>1?p/100:p});case"fill-opacity":if(k.gradient){F=a._g.doc.getElementById(i.getAttribute("fill").replace(/^url\(#|\)$/g,l)),F&&(G=F.getElementsByTagName("stop"),q(G[G.length-1],{"stop-opacity":p}));break};default:o=="font-size"&&(p=e(p,10)+"px");var H=o.replace(/(\-.)/g,function(a){return a.substring(1).toUpperCase()});i.style[H]=p,d._.dirty=1,i.setAttribute(o,p)}}B(d,f),i.style.visibility=m},A=1.2,B=function(d,f){if(d.type=="text"&&!!(f[b]("text")||f[b]("font")||f[b]("font-size")||f[b]("x")||f[b]("y"))){var g=d.attrs,h=d.node,i=h.firstChild?e(a._g.doc.defaultView.getComputedStyle(h.firstChild,l).getPropertyValue("font-size"),10):10;if(f[b]("text")){g.text=f.text;while(h.firstChild)h.removeChild(h.firstChild);var j=c(f.text).split("\n"),k=[],m;for(var n=0,o=j.length;n"));var Y=V.getBoundingClientRect();t.W=m.w=(Y.right-Y.left)/W,t.H=m.h=(Y.bottom-Y.top)/W,t.X=m.x,t.Y=m.y+t.H/2,("x"in i||"y"in i)&&(t.path.v=a.format("m{0},{1}l{2},{1}",f(m.x*u),f(m.y*u),f(m.x*u)+1));var Z=["x","y","text","font","font-family","font-weight","font-style","font-size"];for(var $=0,_=Z.length;$<_;$++)if(Z[$]in i){t._.dirty=1;break}switch(m["text-anchor"]){case"start":t.textpath.style["v-text-align"]="left",t.bbx=t.W/2;break;case"end":t.textpath.style["v-text-align"]="right",t.bbx=-t.W/2;break;default:t.textpath.style["v-text-align"]="center",t.bbx=0}t.textpath.style["v-text-kern"]=!0}},addGradientFill=function(b,f,g){b.attrs=b.attrs||{};var h=b.attrs,i=Math.pow,j,k,l="linear",m=".5 .5";b.attrs.gradient=f,f=c(f).replace(a._radial_gradient,function(a,b,c){l="radial",b&&c&&(b=d(b),c=d(c),i(b-.5,2)+i(c-.5,2)>.25&&(c=e.sqrt(.25-i(b-.5,2))*((c>.5)*2-1)+.5),m=b+n+c);return o}),f=f.split(/\s*\-\s*/);if(l=="linear"){var p=f.shift();p=-d(p);if(isNaN(p))return null}var q=a._parseDots(f);if(!q)return null;b=b.shape||b.node;if(q.length){b.removeChild(g),g.on=!0,g.method="none",g.color=q[0].color,g.color2=q[q.length-1].color;var r=[];for(var s=0,t=q.length;s')}}catch(c){B=function(a){return b.createElement("<"+a+' xmlns="urn:schemas-microsoft.com:vml" class="rvml">')}}};C(a._g.win),a._engine.create=function(){var b=a._getContainer.apply(0,arguments),c=b.container,d=b.height,e,f=b.width,g=b.x,h=b.y;if(!c)throw new Error("VML container not found.");var i=new a._Paper,j=i.canvas=a._g.doc.createElement("div"),k=j.style;g=g||0,h=h||0,f=f||512,d=d||342,i.width=f,i.height=d,f==+f&&(f+="px"),d==+d&&(d+="px"),i.coordsize=u*1e3+n+u*1e3,i.coordorigin="0 0",i.span=a._g.doc.createElement("span"),i.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;",j.appendChild(i.span),k.cssText=a.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden",f,d),c==1?(a._g.doc.body.appendChild(j),k.left=g+"px",k.top=h+"px",k.position="absolute"):c.firstChild?c.insertBefore(j,c.firstChild):c.appendChild(j),i.renderfix=function(){};return i},a.prototype.clear=function(){a.eve("clear",this),this.canvas.innerHTML=o,this.span=a._g.doc.createElement("span"),this.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;",this.canvas.appendChild(this.span),this.bottom=this.top=null},a.prototype.remove=function(){a.eve("remove",this),this.canvas.parentNode.removeChild(this.canvas);for(var b in this)this[b]=removed(b);return!0};var D=a.st;for(var E in A)A[b](E)&&!D[b](E)&&(D[E]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a].apply(c,b)})}}(E))}(window.Raphael) \ No newline at end of file diff --git a/addons/web_diagram/static/lib/js/raphael.js b/addons/web_diagram/static/lib/js/raphael.js new file mode 100644 index 00000000000..0081b8a6ea2 --- /dev/null +++ b/addons/web_diagram/static/lib/js/raphael.js @@ -0,0 +1,5501 @@ +// ┌────────────────────────────────────────────────────────────────────┐ \\ +// │ Raphaël 2.0.2 - JavaScript Vector Library │ \\ +// ├────────────────────────────────────────────────────────────────────┤ \\ +// │ Copyright © 2008-2012 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ +// │ Copyright © 2008-2012 Sencha Labs (http://sencha.com) │ \\ +// ├────────────────────────────────────────────────────────────────────┤ \\ +// │ Licensed under the MIT (http://raphaeljs.com/license.html) license.│ \\ +// └────────────────────────────────────────────────────────────────────┘ \\ +// ┌──────────────────────────────────────────────────────────────────────────────────────┐ \\ +// │ Eve 0.3.4 - JavaScript Events Library │ \\ +// ├──────────────────────────────────────────────────────────────────────────────────────┤ \\ +// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\ +// │ Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. │ \\ +// └──────────────────────────────────────────────────────────────────────────────────────┘ \\ + +(function (glob) { + var version = "0.3.4", + has = "hasOwnProperty", + separator = /[\.\/]/, + wildcard = "*", + fun = function () {}, + numsort = function (a, b) { + return a - b; + }, + current_event, + stop, + events = {n: {}}, + + eve = function (name, scope) { + var e = events, + oldstop = stop, + args = Array.prototype.slice.call(arguments, 2), + listeners = eve.listeners(name), + z = 0, + f = false, + l, + indexed = [], + queue = {}, + out = [], + ce = current_event, + errors = []; + current_event = name; + stop = 0; + for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) { + indexed.push(listeners[i].zIndex); + if (listeners[i].zIndex < 0) { + queue[listeners[i].zIndex] = listeners[i]; + } + } + indexed.sort(numsort); + while (indexed[z] < 0) { + l = queue[indexed[z++]]; + out.push(l.apply(scope, args)); + if (stop) { + stop = oldstop; + return out; + } + } + for (i = 0; i < ii; i++) { + l = listeners[i]; + if ("zIndex" in l) { + if (l.zIndex == indexed[z]) { + out.push(l.apply(scope, args)); + if (stop) { + break; + } + do { + z++; + l = queue[indexed[z]]; + l && out.push(l.apply(scope, args)); + if (stop) { + break; + } + } while (l) + } else { + queue[l.zIndex] = l; + } + } else { + out.push(l.apply(scope, args)); + if (stop) { + break; + } + } + } + stop = oldstop; + current_event = ce; + return out.length ? out : null; + }; + + eve.listeners = function (name) { + var names = name.split(separator), + e = events, + item, + items, + k, + i, + ii, + j, + jj, + nes, + es = [e], + out = []; + for (i = 0, ii = names.length; i < ii; i++) { + nes = []; + for (j = 0, jj = es.length; j < jj; j++) { + e = es[j].n; + items = [e[names[i]], e[wildcard]]; + k = 2; + while (k--) { + item = items[k]; + if (item) { + nes.push(item); + out = out.concat(item.f || []); + } + } + } + es = nes; + } + return out; + }; + + + eve.on = function (name, f) { + var names = name.split(separator), + e = events; + for (var i = 0, ii = names.length; i < ii; i++) { + e = e.n; + !e[names[i]] && (e[names[i]] = {n: {}}); + e = e[names[i]]; + } + e.f = e.f || []; + for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) { + return fun; + } + e.f.push(f); + return function (zIndex) { + if (+zIndex == +zIndex) { + f.zIndex = +zIndex; + } + }; + }; + + eve.stop = function () { + stop = 1; + }; + + eve.nt = function (subname) { + if (subname) { + return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event); + } + return current_event; + }; + + + eve.off = eve.unbind = function (name, f) { + var names = name.split(separator), + e, + key, + splice, + i, ii, j, jj, + cur = [events]; + for (i = 0, ii = names.length; i < ii; i++) { + for (j = 0; j < cur.length; j += splice.length - 2) { + splice = [j, 1]; + e = cur[j].n; + if (names[i] != wildcard) { + if (e[names[i]]) { + splice.push(e[names[i]]); + } + } else { + for (key in e) if (e[has](key)) { + splice.push(e[key]); + } + } + cur.splice.apply(cur, splice); + } + } + for (i = 0, ii = cur.length; i < ii; i++) { + e = cur[i]; + while (e.n) { + if (f) { + if (e.f) { + for (j = 0, jj = e.f.length; j < jj; j++) if (e.f[j] == f) { + e.f.splice(j, 1); + break; + } + !e.f.length && delete e.f; + } + for (key in e.n) if (e.n[has](key) && e.n[key].f) { + var funcs = e.n[key].f; + for (j = 0, jj = funcs.length; j < jj; j++) if (funcs[j] == f) { + funcs.splice(j, 1); + break; + } + !funcs.length && delete e.n[key].f; + } + } else { + delete e.f; + for (key in e.n) if (e.n[has](key) && e.n[key].f) { + delete e.n[key].f; + } + } + e = e.n; + } + } + }; + + eve.once = function (name, f) { + var f2 = function () { + var res = f.apply(this, arguments); + eve.unbind(name, f2); + return res; + }; + return eve.on(name, f2); + }; + + eve.version = version; + eve.toString = function () { + return "You are running Eve " + version; + }; + (typeof module != "undefined" && module.exports) ? (module.exports = eve) : (typeof define != "undefined" ? (define("eve", [], function() { return eve; })) : (glob.eve = eve)); +})(this); + + +// ┌─────────────────────────────────────────────────────────────────────┐ \\ +// │ "Raphaël 2.0.2" - JavaScript Vector Library │ \\ +// ├─────────────────────────────────────────────────────────────────────┤ \\ +// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ +// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ +// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ +// └─────────────────────────────────────────────────────────────────────┘ \\ +(function () { + + function R(first) { + if (R.is(first, "function")) { + return loaded ? first() : eve.on("DOMload", first); + } else if (R.is(first, array)) { + return R._engine.create[apply](R, first.splice(0, 3 + R.is(first[0], nu))).add(first); + } else { + var args = Array.prototype.slice.call(arguments, 0); + if (R.is(args[args.length - 1], "function")) { + var f = args.pop(); + return loaded ? f.call(R._engine.create[apply](R, args)) : eve.on("DOMload", function () { + f.call(R._engine.create[apply](R, args)); + }); + } else { + return R._engine.create[apply](R, arguments); + } + } + } + R.version = "2.0.2"; + R.eve = eve; + var loaded, + separator = /[, ]+/, + elements = {circle: 1, rect: 1, path: 1, ellipse: 1, text: 1, image: 1}, + formatrg = /\{(\d+)\}/g, + proto = "prototype", + has = "hasOwnProperty", + g = { + doc: document, + win: window + }, + oldRaphael = { + was: Object.prototype[has].call(g.win, "Raphael"), + is: g.win.Raphael + }, + Paper = function () { + + + this.ca = this.customAttributes = {}; + }, + paperproto, + appendChild = "appendChild", + apply = "apply", + concat = "concat", + supportsTouch = "createTouch" in g.doc, + E = "", + S = " ", + Str = String, + split = "split", + events = "click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel"[split](S), + touchMap = { + mousedown: "touchstart", + mousemove: "touchmove", + mouseup: "touchend" + }, + lowerCase = Str.prototype.toLowerCase, + math = Math, + mmax = math.max, + mmin = math.min, + abs = math.abs, + pow = math.pow, + PI = math.PI, + nu = "number", + string = "string", + array = "array", + toString = "toString", + fillString = "fill", + objectToString = Object.prototype.toString, + paper = {}, + push = "push", + ISURL = R._ISURL = /^url\(['"]?([^\)]+?)['"]?\)$/i, + colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\))\s*$/i, + isnan = {"NaN": 1, "Infinity": 1, "-Infinity": 1}, + bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/, + round = math.round, + setAttribute = "setAttribute", + toFloat = parseFloat, + toInt = parseInt, + upperCase = Str.prototype.toUpperCase, + availableAttrs = R._availableAttrs = { + "arrow-end": "none", + "arrow-start": "none", + blur: 0, + "clip-rect": "0 0 1e9 1e9", + cursor: "default", + cx: 0, + cy: 0, + fill: "#fff", + "fill-opacity": 1, + font: '10px "Arial"', + "font-family": '"Arial"', + "font-size": "10", + "font-style": "normal", + "font-weight": 400, + gradient: 0, + height: 0, + href: "http://raphaeljs.com/", + "letter-spacing": 0, + opacity: 1, + path: "M0,0", + r: 0, + rx: 0, + ry: 0, + src: "", + stroke: "#000", + "stroke-dasharray": "", + "stroke-linecap": "butt", + "stroke-linejoin": "butt", + "stroke-miterlimit": 0, + "stroke-opacity": 1, + "stroke-width": 1, + target: "_blank", + "text-anchor": "middle", + title: "Raphael", + transform: "", + width: 0, + x: 0, + y: 0 + }, + availableAnimAttrs = R._availableAnimAttrs = { + blur: nu, + "clip-rect": "csv", + cx: nu, + cy: nu, + fill: "colour", + "fill-opacity": nu, + "font-size": nu, + height: nu, + opacity: nu, + path: "path", + r: nu, + rx: nu, + ry: nu, + stroke: "colour", + "stroke-opacity": nu, + "stroke-width": nu, + transform: "transform", + width: nu, + x: nu, + y: nu + }, + whitespace = /[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]/g, + commaSpaces = /[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/, + hsrg = {hs: 1, rg: 1}, + p2s = /,?([achlmqrstvxz]),?/gi, + pathCommand = /([achlmrqstvz])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/ig, + tCommand = /([rstm])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/ig, + pathValues = /(-?\d*\.?\d*(?:e[\-+]?\d+)?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/ig, + radial_gradient = R._radial_gradient = /^r(?:\(([^,]+?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*([^\)]+?)\))?/, + eldata = {}, + sortByKey = function (a, b) { + return a.key - b.key; + }, + sortByNumber = function (a, b) { + return toFloat(a) - toFloat(b); + }, + fun = function () {}, + pipe = function (x) { + return x; + }, + rectPath = R._rectPath = function (x, y, w, h, r) { + if (r) { + return [["M", x + r, y], ["l", w - r * 2, 0], ["a", r, r, 0, 0, 1, r, r], ["l", 0, h - r * 2], ["a", r, r, 0, 0, 1, -r, r], ["l", r * 2 - w, 0], ["a", r, r, 0, 0, 1, -r, -r], ["l", 0, r * 2 - h], ["a", r, r, 0, 0, 1, r, -r], ["z"]]; + } + return [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]]; + }, + ellipsePath = function (x, y, rx, ry) { + if (ry == null) { + ry = rx; + } + return [["M", x, y], ["m", 0, -ry], ["a", rx, ry, 0, 1, 1, 0, 2 * ry], ["a", rx, ry, 0, 1, 1, 0, -2 * ry], ["z"]]; + }, + getPath = R._getPath = { + path: function (el) { + return el.attr("path"); + }, + circle: function (el) { + var a = el.attrs; + return ellipsePath(a.cx, a.cy, a.r); + }, + ellipse: function (el) { + var a = el.attrs; + return ellipsePath(a.cx, a.cy, a.rx, a.ry); + }, + rect: function (el) { + var a = el.attrs; + return rectPath(a.x, a.y, a.width, a.height, a.r); + }, + image: function (el) { + var a = el.attrs; + return rectPath(a.x, a.y, a.width, a.height); + }, + text: function (el) { + var bbox = el._getBBox(); + return rectPath(bbox.x, bbox.y, bbox.width, bbox.height); + } + }, + mapPath = R.mapPath = function (path, matrix) { + if (!matrix) { + return path; + } + var x, y, i, j, ii, jj, pathi; + path = path2curve(path); + for (i = 0, ii = path.length; i < ii; i++) { + pathi = path[i]; + for (j = 1, jj = pathi.length; j < jj; j += 2) { + x = matrix.x(pathi[j], pathi[j + 1]); + y = matrix.y(pathi[j], pathi[j + 1]); + pathi[j] = x; + pathi[j + 1] = y; + } + } + return path; + }; + + R._g = g; + + R.type = (g.win.SVGAngle || g.doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") ? "SVG" : "VML"); + if (R.type == "VML") { + var d = g.doc.createElement("div"), + b; + d.innerHTML = ''; + b = d.firstChild; + b.style.behavior = "url(#default#VML)"; + if (!(b && typeof b.adj == "object")) { + return (R.type = E); + } + d = null; + } + + + R.svg = !(R.vml = R.type == "VML"); + R._Paper = Paper; + + R.fn = paperproto = Paper.prototype = R.prototype; + R._id = 0; + R._oid = 0; + + R.is = function (o, type) { + type = lowerCase.call(type); + if (type == "finite") { + return !isnan[has](+o); + } + if (type == "array") { + return o instanceof Array; + } + return (type == "null" && o === null) || + (type == typeof o && o !== null) || + (type == "object" && o === Object(o)) || + (type == "array" && Array.isArray && Array.isArray(o)) || + objectToString.call(o).slice(8, -1).toLowerCase() == type; + }; + + R.angle = function (x1, y1, x2, y2, x3, y3) { + if (x3 == null) { + var x = x1 - x2, + y = y1 - y2; + if (!x && !y) { + return 0; + } + return (180 + math.atan2(-y, -x) * 180 / PI + 360) % 360; + } else { + return R.angle(x1, y1, x3, y3) - R.angle(x2, y2, x3, y3); + } + }; + + R.rad = function (deg) { + return deg % 360 * PI / 180; + }; + + R.deg = function (rad) { + return rad * 180 / PI % 360; + }; + + R.snapTo = function (values, value, tolerance) { + tolerance = R.is(tolerance, "finite") ? tolerance : 10; + if (R.is(values, array)) { + var i = values.length; + while (i--) if (abs(values[i] - value) <= tolerance) { + return values[i]; + } + } else { + values = +values; + var rem = value % values; + if (rem < tolerance) { + return value - rem; + } + if (rem > values - tolerance) { + return value - rem + values; + } + } + return value; + }; + + + var createUUID = R.createUUID = (function (uuidRegEx, uuidReplacer) { + return function () { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(uuidRegEx, uuidReplacer).toUpperCase(); + }; + })(/[xy]/g, function (c) { + var r = math.random() * 16 | 0, + v = c == "x" ? r : (r & 3 | 8); + return v.toString(16); + }); + + + R.setWindow = function (newwin) { + eve("setWindow", R, g.win, newwin); + g.win = newwin; + g.doc = g.win.document; + if (R._engine.initWin) { + R._engine.initWin(g.win); + } + }; + var toHex = function (color) { + if (R.vml) { + // http://dean.edwards.name/weblog/2009/10/convert-any-colour-value-to-hex-in-msie/ + var trim = /^\s+|\s+$/g; + var bod; + try { + var docum = new ActiveXObject("htmlfile"); + docum.write(""); + docum.close(); + bod = docum.body; + } catch(e) { + bod = createPopup().document.body; + } + var range = bod.createTextRange(); + toHex = cacher(function (color) { + try { + bod.style.color = Str(color).replace(trim, E); + var value = range.queryCommandValue("ForeColor"); + value = ((value & 255) << 16) | (value & 65280) | ((value & 16711680) >>> 16); + return "#" + ("000000" + value.toString(16)).slice(-6); + } catch(e) { + return "none"; + } + }); + } else { + var i = g.doc.createElement("i"); + i.title = "Rapha\xebl Colour Picker"; + i.style.display = "none"; + g.doc.body.appendChild(i); + toHex = cacher(function (color) { + i.style.color = color; + return g.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color"); + }); + } + return toHex(color); + }, + hsbtoString = function () { + return "hsb(" + [this.h, this.s, this.b] + ")"; + }, + hsltoString = function () { + return "hsl(" + [this.h, this.s, this.l] + ")"; + }, + rgbtoString = function () { + return this.hex; + }, + prepareRGB = function (r, g, b) { + if (g == null && R.is(r, "object") && "r" in r && "g" in r && "b" in r) { + b = r.b; + g = r.g; + r = r.r; + } + if (g == null && R.is(r, string)) { + var clr = R.getRGB(r); + r = clr.r; + g = clr.g; + b = clr.b; + } + if (r > 1 || g > 1 || b > 1) { + r /= 255; + g /= 255; + b /= 255; + } + + return [r, g, b]; + }, + packageRGB = function (r, g, b, o) { + r *= 255; + g *= 255; + b *= 255; + var rgb = { + r: r, + g: g, + b: b, + hex: R.rgb(r, g, b), + toString: rgbtoString + }; + R.is(o, "finite") && (rgb.opacity = o); + return rgb; + }; + + + R.color = function (clr) { + var rgb; + if (R.is(clr, "object") && "h" in clr && "s" in clr && "b" in clr) { + rgb = R.hsb2rgb(clr); + clr.r = rgb.r; + clr.g = rgb.g; + clr.b = rgb.b; + clr.hex = rgb.hex; + } else if (R.is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) { + rgb = R.hsl2rgb(clr); + clr.r = rgb.r; + clr.g = rgb.g; + clr.b = rgb.b; + clr.hex = rgb.hex; + } else { + if (R.is(clr, "string")) { + clr = R.getRGB(clr); + } + if (R.is(clr, "object") && "r" in clr && "g" in clr && "b" in clr) { + rgb = R.rgb2hsl(clr); + clr.h = rgb.h; + clr.s = rgb.s; + clr.l = rgb.l; + rgb = R.rgb2hsb(clr); + clr.v = rgb.b; + } else { + clr = {hex: "none"}; + clr.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1; + } + } + clr.toString = rgbtoString; + return clr; + }; + + R.hsb2rgb = function (h, s, v, o) { + if (this.is(h, "object") && "h" in h && "s" in h && "b" in h) { + v = h.b; + s = h.s; + h = h.h; + o = h.o; + } + h *= 360; + var R, G, B, X, C; + h = (h % 360) / 60; + C = v * s; + X = C * (1 - abs(h % 2 - 1)); + R = G = B = v - C; + + h = ~~h; + R += [C, X, 0, 0, X, C][h]; + G += [X, C, C, X, 0, 0][h]; + B += [0, 0, X, C, C, X][h]; + return packageRGB(R, G, B, o); + }; + + R.hsl2rgb = function (h, s, l, o) { + if (this.is(h, "object") && "h" in h && "s" in h && "l" in h) { + l = h.l; + s = h.s; + h = h.h; + } + if (h > 1 || s > 1 || l > 1) { + h /= 360; + s /= 100; + l /= 100; + } + h *= 360; + var R, G, B, X, C; + h = (h % 360) / 60; + C = 2 * s * (l < .5 ? l : 1 - l); + X = C * (1 - abs(h % 2 - 1)); + R = G = B = l - C / 2; + + h = ~~h; + R += [C, X, 0, 0, X, C][h]; + G += [X, C, C, X, 0, 0][h]; + B += [0, 0, X, C, C, X][h]; + return packageRGB(R, G, B, o); + }; + + R.rgb2hsb = function (r, g, b) { + b = prepareRGB(r, g, b); + r = b[0]; + g = b[1]; + b = b[2]; + + var H, S, V, C; + V = mmax(r, g, b); + C = V - mmin(r, g, b); + H = (C == 0 ? null : + V == r ? (g - b) / C : + V == g ? (b - r) / C + 2 : + (r - g) / C + 4 + ); + H = ((H + 360) % 6) * 60 / 360; + S = C == 0 ? 0 : C / V; + return {h: H, s: S, b: V, toString: hsbtoString}; + }; + + R.rgb2hsl = function (r, g, b) { + b = prepareRGB(r, g, b); + r = b[0]; + g = b[1]; + b = b[2]; + + var H, S, L, M, m, C; + M = mmax(r, g, b); + m = mmin(r, g, b); + C = M - m; + H = (C == 0 ? null : + M == r ? (g - b) / C : + M == g ? (b - r) / C + 2 : + (r - g) / C + 4); + H = ((H + 360) % 6) * 60 / 360; + L = (M + m) / 2; + S = (C == 0 ? 0 : + L < .5 ? C / (2 * L) : + C / (2 - 2 * L)); + return {h: H, s: S, l: L, toString: hsltoString}; + }; + R._path2string = function () { + return this.join(",").replace(p2s, "$1"); + }; + function repush(array, item) { + for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) { + return array.push(array.splice(i, 1)[0]); + } + } + function cacher(f, scope, postprocessor) { + function newf() { + var arg = Array.prototype.slice.call(arguments, 0), + args = arg.join("\u2400"), + cache = newf.cache = newf.cache || {}, + count = newf.count = newf.count || []; + if (cache[has](args)) { + repush(count, args); + return postprocessor ? postprocessor(cache[args]) : cache[args]; + } + count.length >= 1e3 && delete cache[count.shift()]; + count.push(args); + cache[args] = f[apply](scope, arg); + return postprocessor ? postprocessor(cache[args]) : cache[args]; + } + return newf; + } + + var preload = R._preload = function (src, f) { + var img = g.doc.createElement("img"); + img.style.cssText = "position:absolute;left:-9999em;top:-9999em"; + img.onload = function () { + f.call(this); + this.onload = null; + g.doc.body.removeChild(this); + }; + img.onerror = function () { + g.doc.body.removeChild(this); + }; + g.doc.body.appendChild(img); + img.src = src; + }; + + function clrToString() { + return this.hex; + } + + + R.getRGB = cacher(function (colour) { + if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) { + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: clrToString}; + } + if (colour == "none") { + return {r: -1, g: -1, b: -1, hex: "none", toString: clrToString}; + } + !(hsrg[has](colour.toLowerCase().substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour)); + var res, + red, + green, + blue, + opacity, + t, + values, + rgb = colour.match(colourRegExp); + if (rgb) { + if (rgb[2]) { + blue = toInt(rgb[2].substring(5), 16); + green = toInt(rgb[2].substring(3, 5), 16); + red = toInt(rgb[2].substring(1, 3), 16); + } + if (rgb[3]) { + blue = toInt((t = rgb[3].charAt(3)) + t, 16); + green = toInt((t = rgb[3].charAt(2)) + t, 16); + red = toInt((t = rgb[3].charAt(1)) + t, 16); + } + if (rgb[4]) { + values = rgb[4][split](commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red *= 2.55); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green *= 2.55); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue *= 2.55); + rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + } + if (rgb[5]) { + values = rgb[5][split](commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red *= 2.55); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green *= 2.55); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue *= 2.55); + (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); + rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + return R.hsb2rgb(red, green, blue, opacity); + } + if (rgb[6]) { + values = rgb[6][split](commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red *= 2.55); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green *= 2.55); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue *= 2.55); + (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); + rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + return R.hsl2rgb(red, green, blue, opacity); + } + rgb = {r: red, g: green, b: blue, toString: clrToString}; + rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1); + R.is(opacity, "finite") && (rgb.opacity = opacity); + return rgb; + } + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: clrToString}; + }, R); + + R.hsb = cacher(function (h, s, b) { + return R.hsb2rgb(h, s, b).hex; + }); + + R.hsl = cacher(function (h, s, l) { + return R.hsl2rgb(h, s, l).hex; + }); + + R.rgb = cacher(function (r, g, b) { + return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1); + }); + + R.getColor = function (value) { + var start = this.getColor.start = this.getColor.start || {h: 0, s: 1, b: value || .75}, + rgb = this.hsb2rgb(start.h, start.s, start.b); + start.h += .075; + if (start.h > 1) { + start.h = 0; + start.s -= .2; + start.s <= 0 && (this.getColor.start = {h: 0, s: 1, b: start.b}); + } + return rgb.hex; + }; + + R.getColor.reset = function () { + delete this.start; + }; + + // http://schepers.cc/getting-to-the-point + function catmullRom2bezier(crp, z) { + var d = []; + for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) { + var p = [ + {x: +crp[i - 2], y: +crp[i - 1]}, + {x: +crp[i], y: +crp[i + 1]}, + {x: +crp[i + 2], y: +crp[i + 3]}, + {x: +crp[i + 4], y: +crp[i + 5]} + ]; + if (z) { + if (!i) { + p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]}; + } else if (iLen - 4 == i) { + p[3] = {x: +crp[0], y: +crp[1]}; + } else if (iLen - 2 == i) { + p[2] = {x: +crp[0], y: +crp[1]}; + p[3] = {x: +crp[2], y: +crp[3]}; + } + } else { + if (iLen - 4 == i) { + p[3] = p[2]; + } else if (!i) { + p[0] = {x: +crp[i], y: +crp[i + 1]}; + } + } + d.push(["C", + (-p[0].x + 6 * p[1].x + p[2].x) / 6, + (-p[0].y + 6 * p[1].y + p[2].y) / 6, + (p[1].x + 6 * p[2].x - p[3].x) / 6, + (p[1].y + 6*p[2].y - p[3].y) / 6, + p[2].x, + p[2].y + ]); + } + + return d; + } + + R.parsePathString = cacher(function (pathString) { + if (!pathString) { + return null; + } + var paramCounts = {a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0}, + data = []; + if (R.is(pathString, array) && R.is(pathString[0], array)) { // rough assumption + data = pathClone(pathString); + } + if (!data.length) { + Str(pathString).replace(pathCommand, function (a, b, c) { + var params = [], + name = b.toLowerCase(); + c.replace(pathValues, function (a, b) { + b && params.push(+b); + }); + if (name == "m" && params.length > 2) { + data.push([b][concat](params.splice(0, 2))); + name = "l"; + b = b == "m" ? "l" : "L"; + } + if (name == "r") { + data.push([b][concat](params)); + } else while (params.length >= paramCounts[name]) { + data.push([b][concat](params.splice(0, paramCounts[name]))); + if (!paramCounts[name]) { + break; + } + } + }); + } + data.toString = R._path2string; + return data; + }); + + R.parseTransformString = cacher(function (TString) { + if (!TString) { + return null; + } + var paramCounts = {r: 3, s: 4, t: 2, m: 6}, + data = []; + if (R.is(TString, array) && R.is(TString[0], array)) { // rough assumption + data = pathClone(TString); + } + if (!data.length) { + Str(TString).replace(tCommand, function (a, b, c) { + var params = [], + name = lowerCase.call(b); + c.replace(pathValues, function (a, b) { + b && params.push(+b); + }); + data.push([b][concat](params)); + }); + } + data.toString = R._path2string; + return data; + }); + + R.findDotsAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { + var t1 = 1 - t, + t13 = pow(t1, 3), + t12 = pow(t1, 2), + t2 = t * t, + t3 = t2 * t, + x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x, + y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y, + mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x), + my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y), + nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x), + ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y), + ax = t1 * p1x + t * c1x, + ay = t1 * p1y + t * c1y, + cx = t1 * c2x + t * p2x, + cy = t1 * c2y + t * p2y, + alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI); + (mx > nx || my < ny) && (alpha += 180); + return { + x: x, + y: y, + m: {x: mx, y: my}, + n: {x: nx, y: ny}, + start: {x: ax, y: ay}, + end: {x: cx, y: cy}, + alpha: alpha + }; + }; + R._removedFactory = function (methodname) { + return function () { + throw new Error("Rapha\xebl: you are calling to method \u201c" + methodname + "\u201d of removed object"); + }; + }; + var pathDimensions = cacher(function (path) { + if (!path) { + return {x: 0, y: 0, width: 0, height: 0}; + } + path = path2curve(path); + var x = 0, + y = 0, + X = [], + Y = [], + p; + for (var i = 0, ii = path.length; i < ii; i++) { + p = path[i]; + if (p[0] == "M") { + x = p[1]; + y = p[2]; + X.push(x); + Y.push(y); + } else { + var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); + X = X[concat](dim.min.x, dim.max.x); + Y = Y[concat](dim.min.y, dim.max.y); + x = p[5]; + y = p[6]; + } + } + var xmin = mmin[apply](0, X), + ymin = mmin[apply](0, Y); + return { + x: xmin, + y: ymin, + width: mmax[apply](0, X) - xmin, + height: mmax[apply](0, Y) - ymin + }; + }, null, function (o) { + return { + x: o.x, + y: o.y, + width: o.width, + height: o.height + }; + }), + pathClone = function (pathArray) { + var res = []; + if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption + pathArray = R.parsePathString(pathArray); + } + for (var i = 0, ii = pathArray.length; i < ii; i++) { + res[i] = []; + for (var j = 0, jj = pathArray[i].length; j < jj; j++) { + res[i][j] = pathArray[i][j]; + } + } + res.toString = R._path2string; + return res; + }, + pathToRelative = R._pathToRelative = cacher(function (pathArray) { + if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption + pathArray = R.parsePathString(pathArray); + } + var res = [], + x = 0, + y = 0, + mx = 0, + my = 0, + start = 0; + if (pathArray[0][0] == "M") { + x = pathArray[0][1]; + y = pathArray[0][2]; + mx = x; + my = y; + start++; + res.push(["M", x, y]); + } + for (var i = start, ii = pathArray.length; i < ii; i++) { + var r = res[i] = [], + pa = pathArray[i]; + if (pa[0] != lowerCase.call(pa[0])) { + r[0] = lowerCase.call(pa[0]); + switch (r[0]) { + case "a": + r[1] = pa[1]; + r[2] = pa[2]; + r[3] = pa[3]; + r[4] = pa[4]; + r[5] = pa[5]; + r[6] = +(pa[6] - x).toFixed(3); + r[7] = +(pa[7] - y).toFixed(3); + break; + case "v": + r[1] = +(pa[1] - y).toFixed(3); + break; + case "m": + mx = pa[1]; + my = pa[2]; + default: + for (var j = 1, jj = pa.length; j < jj; j++) { + r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3); + } + } + } else { + r = res[i] = []; + if (pa[0] == "m") { + mx = pa[1] + x; + my = pa[2] + y; + } + for (var k = 0, kk = pa.length; k < kk; k++) { + res[i][k] = pa[k]; + } + } + var len = res[i].length; + switch (res[i][0]) { + case "z": + x = mx; + y = my; + break; + case "h": + x += +res[i][len - 1]; + break; + case "v": + y += +res[i][len - 1]; + break; + default: + x += +res[i][len - 2]; + y += +res[i][len - 1]; + } + } + res.toString = R._path2string; + return res; + }, 0, pathClone), + pathToAbsolute = R._pathToAbsolute = cacher(function (pathArray) { + if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption + pathArray = R.parsePathString(pathArray); + } + if (!pathArray || !pathArray.length) { + return [["M", 0, 0]]; + } + var res = [], + x = 0, + y = 0, + mx = 0, + my = 0, + start = 0; + if (pathArray[0][0] == "M") { + x = +pathArray[0][1]; + y = +pathArray[0][2]; + mx = x; + my = y; + start++; + res[0] = ["M", x, y]; + } + var crz = pathArray.length == 3 && pathArray[0][0] == "M" && pathArray[1][0].toUpperCase() == "R" && pathArray[2][0].toUpperCase() == "Z"; + for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) { + res.push(r = []); + pa = pathArray[i]; + if (pa[0] != upperCase.call(pa[0])) { + r[0] = upperCase.call(pa[0]); + switch (r[0]) { + case "A": + r[1] = pa[1]; + r[2] = pa[2]; + r[3] = pa[3]; + r[4] = pa[4]; + r[5] = pa[5]; + r[6] = +(pa[6] + x); + r[7] = +(pa[7] + y); + break; + case "V": + r[1] = +pa[1] + y; + break; + case "H": + r[1] = +pa[1] + x; + break; + case "R": + var dots = [x, y][concat](pa.slice(1)); + for (var j = 2, jj = dots.length; j < jj; j++) { + dots[j] = +dots[j] + x; + dots[++j] = +dots[j] + y; + } + res.pop(); + res = res[concat](catmullRom2bezier(dots, crz)); + break; + case "M": + mx = +pa[1] + x; + my = +pa[2] + y; + default: + for (j = 1, jj = pa.length; j < jj; j++) { + r[j] = +pa[j] + ((j % 2) ? x : y); + } + } + } else if (pa[0] == "R") { + dots = [x, y][concat](pa.slice(1)); + res.pop(); + res = res[concat](catmullRom2bezier(dots, crz)); + r = ["R"][concat](pa.slice(-2)); + } else { + for (var k = 0, kk = pa.length; k < kk; k++) { + r[k] = pa[k]; + } + } + switch (r[0]) { + case "Z": + x = mx; + y = my; + break; + case "H": + x = r[1]; + break; + case "V": + y = r[1]; + break; + case "M": + mx = r[r.length - 2]; + my = r[r.length - 1]; + default: + x = r[r.length - 2]; + y = r[r.length - 1]; + } + } + res.toString = R._path2string; + return res; + }, null, pathClone), + l2c = function (x1, y1, x2, y2) { + return [x1, y1, x2, y2, x2, y2]; + }, + q2c = function (x1, y1, ax, ay, x2, y2) { + var _13 = 1 / 3, + _23 = 2 / 3; + return [ + _13 * x1 + _23 * ax, + _13 * y1 + _23 * ay, + _13 * x2 + _23 * ax, + _13 * y2 + _23 * ay, + x2, + y2 + ]; + }, + a2c = function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) { + // for more information of where this math came from visit: + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + var _120 = PI * 120 / 180, + rad = PI / 180 * (+angle || 0), + res = [], + xy, + rotate = cacher(function (x, y, rad) { + var X = x * math.cos(rad) - y * math.sin(rad), + Y = x * math.sin(rad) + y * math.cos(rad); + return {x: X, y: Y}; + }); + if (!recursive) { + xy = rotate(x1, y1, -rad); + x1 = xy.x; + y1 = xy.y; + xy = rotate(x2, y2, -rad); + x2 = xy.x; + y2 = xy.y; + var cos = math.cos(PI / 180 * angle), + sin = math.sin(PI / 180 * angle), + x = (x1 - x2) / 2, + y = (y1 - y2) / 2; + var h = (x * x) / (rx * rx) + (y * y) / (ry * ry); + if (h > 1) { + h = math.sqrt(h); + rx = h * rx; + ry = h * ry; + } + var rx2 = rx * rx, + ry2 = ry * ry, + k = (large_arc_flag == sweep_flag ? -1 : 1) * + math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))), + cx = k * rx * y / ry + (x1 + x2) / 2, + cy = k * -ry * x / rx + (y1 + y2) / 2, + f1 = math.asin(((y1 - cy) / ry).toFixed(9)), + f2 = math.asin(((y2 - cy) / ry).toFixed(9)); + + f1 = x1 < cx ? PI - f1 : f1; + f2 = x2 < cx ? PI - f2 : f2; + f1 < 0 && (f1 = PI * 2 + f1); + f2 < 0 && (f2 = PI * 2 + f2); + if (sweep_flag && f1 > f2) { + f1 = f1 - PI * 2; + } + if (!sweep_flag && f2 > f1) { + f2 = f2 - PI * 2; + } + } else { + f1 = recursive[0]; + f2 = recursive[1]; + cx = recursive[2]; + cy = recursive[3]; + } + var df = f2 - f1; + if (abs(df) > _120) { + var f2old = f2, + x2old = x2, + y2old = y2; + f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1); + x2 = cx + rx * math.cos(f2); + y2 = cy + ry * math.sin(f2); + res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]); + } + df = f2 - f1; + var c1 = math.cos(f1), + s1 = math.sin(f1), + c2 = math.cos(f2), + s2 = math.sin(f2), + t = math.tan(df / 4), + hx = 4 / 3 * rx * t, + hy = 4 / 3 * ry * t, + m1 = [x1, y1], + m2 = [x1 + hx * s1, y1 - hy * c1], + m3 = [x2 + hx * s2, y2 - hy * c2], + m4 = [x2, y2]; + m2[0] = 2 * m1[0] - m2[0]; + m2[1] = 2 * m1[1] - m2[1]; + if (recursive) { + return [m2, m3, m4][concat](res); + } else { + res = [m2, m3, m4][concat](res).join()[split](","); + var newres = []; + for (var i = 0, ii = res.length; i < ii; i++) { + newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x; + } + return newres; + } + }, + findDotAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { + var t1 = 1 - t; + return { + x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x, + y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y + }; + }, + curveDim = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { + var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x), + b = 2 * (c1x - p1x) - 2 * (c2x - c1x), + c = p1x - c1x, + t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a, + t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a, + y = [p1y, p2y], + x = [p1x, p2x], + dot; + abs(t1) > "1e12" && (t1 = .5); + abs(t2) > "1e12" && (t2 = .5); + if (t1 > 0 && t1 < 1) { + dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1); + x.push(dot.x); + y.push(dot.y); + } + if (t2 > 0 && t2 < 1) { + dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2); + x.push(dot.x); + y.push(dot.y); + } + a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y); + b = 2 * (c1y - p1y) - 2 * (c2y - c1y); + c = p1y - c1y; + t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a; + t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a; + abs(t1) > "1e12" && (t1 = .5); + abs(t2) > "1e12" && (t2 = .5); + if (t1 > 0 && t1 < 1) { + dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1); + x.push(dot.x); + y.push(dot.y); + } + if (t2 > 0 && t2 < 1) { + dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2); + x.push(dot.x); + y.push(dot.y); + } + return { + min: {x: mmin[apply](0, x), y: mmin[apply](0, y)}, + max: {x: mmax[apply](0, x), y: mmax[apply](0, y)} + }; + }), + path2curve = R._path2curve = cacher(function (path, path2) { + var p = pathToAbsolute(path), + p2 = path2 && pathToAbsolute(path2), + attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, + attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, + processPath = function (path, d) { + var nx, ny; + if (!path) { + return ["C", d.x, d.y, d.x, d.y, d.x, d.y]; + } + !(path[0] in {T:1, Q:1}) && (d.qx = d.qy = null); + switch (path[0]) { + case "M": + d.X = path[1]; + d.Y = path[2]; + break; + case "A": + path = ["C"][concat](a2c[apply](0, [d.x, d.y][concat](path.slice(1)))); + break; + case "S": + nx = d.x + (d.x - (d.bx || d.x)); + ny = d.y + (d.y - (d.by || d.y)); + path = ["C", nx, ny][concat](path.slice(1)); + break; + case "T": + d.qx = d.x + (d.x - (d.qx || d.x)); + d.qy = d.y + (d.y - (d.qy || d.y)); + path = ["C"][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2])); + break; + case "Q": + d.qx = path[1]; + d.qy = path[2]; + path = ["C"][concat](q2c(d.x, d.y, path[1], path[2], path[3], path[4])); + break; + case "L": + path = ["C"][concat](l2c(d.x, d.y, path[1], path[2])); + break; + case "H": + path = ["C"][concat](l2c(d.x, d.y, path[1], d.y)); + break; + case "V": + path = ["C"][concat](l2c(d.x, d.y, d.x, path[1])); + break; + case "Z": + path = ["C"][concat](l2c(d.x, d.y, d.X, d.Y)); + break; + } + return path; + }, + fixArc = function (pp, i) { + if (pp[i].length > 7) { + pp[i].shift(); + var pi = pp[i]; + while (pi.length) { + pp.splice(i++, 0, ["C"][concat](pi.splice(0, 6))); + } + pp.splice(i, 1); + ii = mmax(p.length, p2 && p2.length || 0); + } + }, + fixM = function (path1, path2, a1, a2, i) { + if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") { + path2.splice(i, 0, ["M", a2.x, a2.y]); + a1.bx = 0; + a1.by = 0; + a1.x = path1[i][1]; + a1.y = path1[i][2]; + ii = mmax(p.length, p2 && p2.length || 0); + } + }; + for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) { + p[i] = processPath(p[i], attrs); + fixArc(p, i); + p2 && (p2[i] = processPath(p2[i], attrs2)); + p2 && fixArc(p2, i); + fixM(p, p2, attrs, attrs2, i); + fixM(p2, p, attrs2, attrs, i); + var seg = p[i], + seg2 = p2 && p2[i], + seglen = seg.length, + seg2len = p2 && seg2.length; + attrs.x = seg[seglen - 2]; + attrs.y = seg[seglen - 1]; + attrs.bx = toFloat(seg[seglen - 4]) || attrs.x; + attrs.by = toFloat(seg[seglen - 3]) || attrs.y; + attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x); + attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y); + attrs2.x = p2 && seg2[seg2len - 2]; + attrs2.y = p2 && seg2[seg2len - 1]; + } + return p2 ? [p, p2] : p; + }, null, pathClone), + parseDots = R._parseDots = cacher(function (gradient) { + var dots = []; + for (var i = 0, ii = gradient.length; i < ii; i++) { + var dot = {}, + par = gradient[i].match(/^([^:]*):?([\d\.]*)/); + dot.color = R.getRGB(par[1]); + if (dot.color.error) { + return null; + } + dot.color = dot.color.hex; + par[2] && (dot.offset = par[2] + "%"); + dots.push(dot); + } + for (i = 1, ii = dots.length - 1; i < ii; i++) { + if (!dots[i].offset) { + var start = toFloat(dots[i - 1].offset || 0), + end = 0; + for (var j = i + 1; j < ii; j++) { + if (dots[j].offset) { + end = dots[j].offset; + break; + } + } + if (!end) { + end = 100; + j = ii; + } + end = toFloat(end); + var d = (end - start) / (j - i + 1); + for (; i < j; i++) { + start += d; + dots[i].offset = start + "%"; + } + } + } + return dots; + }), + tear = R._tear = function (el, paper) { + el == paper.top && (paper.top = el.prev); + el == paper.bottom && (paper.bottom = el.next); + el.next && (el.next.prev = el.prev); + el.prev && (el.prev.next = el.next); + }, + tofront = R._tofront = function (el, paper) { + if (paper.top === el) { + return; + } + tear(el, paper); + el.next = null; + el.prev = paper.top; + paper.top.next = el; + paper.top = el; + }, + toback = R._toback = function (el, paper) { + if (paper.bottom === el) { + return; + } + tear(el, paper); + el.next = paper.bottom; + el.prev = null; + paper.bottom.prev = el; + paper.bottom = el; + }, + insertafter = R._insertafter = function (el, el2, paper) { + tear(el, paper); + el2 == paper.top && (paper.top = el); + el2.next && (el2.next.prev = el); + el.next = el2.next; + el.prev = el2; + el2.next = el; + }, + insertbefore = R._insertbefore = function (el, el2, paper) { + tear(el, paper); + el2 == paper.bottom && (paper.bottom = el); + el2.prev && (el2.prev.next = el); + el.prev = el2.prev; + el2.prev = el; + el.next = el2; + }, + extractTransform = R._extractTransform = function (el, tstr) { + if (tstr == null) { + return el._.transform; + } + tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || E); + var tdata = R.parseTransformString(tstr), + deg = 0, + dx = 0, + dy = 0, + sx = 1, + sy = 1, + _ = el._, + m = new Matrix; + _.transform = tdata || []; + if (tdata) { + for (var i = 0, ii = tdata.length; i < ii; i++) { + var t = tdata[i], + tlen = t.length, + command = Str(t[0]).toLowerCase(), + absolute = t[0] != command, + inver = absolute ? m.invert() : 0, + x1, + y1, + x2, + y2, + bb; + if (command == "t" && tlen == 3) { + if (absolute) { + x1 = inver.x(0, 0); + y1 = inver.y(0, 0); + x2 = inver.x(t[1], t[2]); + y2 = inver.y(t[1], t[2]); + m.translate(x2 - x1, y2 - y1); + } else { + m.translate(t[1], t[2]); + } + } else if (command == "r") { + if (tlen == 2) { + bb = bb || el.getBBox(1); + m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2); + deg += t[1]; + } else if (tlen == 4) { + if (absolute) { + x2 = inver.x(t[2], t[3]); + y2 = inver.y(t[2], t[3]); + m.rotate(t[1], x2, y2); + } else { + m.rotate(t[1], t[2], t[3]); + } + deg += t[1]; + } + } else if (command == "s") { + if (tlen == 2 || tlen == 3) { + bb = bb || el.getBBox(1); + m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2); + sx *= t[1]; + sy *= t[tlen - 1]; + } else if (tlen == 5) { + if (absolute) { + x2 = inver.x(t[3], t[4]); + y2 = inver.y(t[3], t[4]); + m.scale(t[1], t[2], x2, y2); + } else { + m.scale(t[1], t[2], t[3], t[4]); + } + sx *= t[1]; + sy *= t[2]; + } + } else if (command == "m" && tlen == 7) { + m.add(t[1], t[2], t[3], t[4], t[5], t[6]); + } + _.dirtyT = 1; + el.matrix = m; + } + } + + el.matrix = m; + + _.sx = sx; + _.sy = sy; + _.deg = deg; + _.dx = dx = m.e; + _.dy = dy = m.f; + + if (sx == 1 && sy == 1 && !deg && _.bbox) { + _.bbox.x += +dx; + _.bbox.y += +dy; + } else { + _.dirtyT = 1; + } + }, + getEmpty = function (item) { + var l = item[0]; + switch (l.toLowerCase()) { + case "t": return [l, 0, 0]; + case "m": return [l, 1, 0, 0, 1, 0, 0]; + case "r": if (item.length == 4) { + return [l, 0, item[2], item[3]]; + } else { + return [l, 0]; + } + case "s": if (item.length == 5) { + return [l, 1, 1, item[3], item[4]]; + } else if (item.length == 3) { + return [l, 1, 1]; + } else { + return [l, 1]; + } + } + }, + equaliseTransform = R._equaliseTransform = function (t1, t2) { + t2 = Str(t2).replace(/\.{3}|\u2026/g, t1); + t1 = R.parseTransformString(t1) || []; + t2 = R.parseTransformString(t2) || []; + var maxlength = mmax(t1.length, t2.length), + from = [], + to = [], + i = 0, j, jj, + tt1, tt2; + for (; i < maxlength; i++) { + tt1 = t1[i] || getEmpty(t2[i]); + tt2 = t2[i] || getEmpty(tt1); + if ((tt1[0] != tt2[0]) || + (tt1[0].toLowerCase() == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) || + (tt1[0].toLowerCase() == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4])) + ) { + return; + } + from[i] = []; + to[i] = []; + for (j = 0, jj = mmax(tt1.length, tt2.length); j < jj; j++) { + j in tt1 && (from[i][j] = tt1[j]); + j in tt2 && (to[i][j] = tt2[j]); + } + } + return { + from: from, + to: to + }; + }; + R._getContainer = function (x, y, w, h) { + var container; + container = h == null && !R.is(x, "object") ? g.doc.getElementById(x) : x; + if (container == null) { + return; + } + if (container.tagName) { + if (y == null) { + return { + container: container, + width: container.style.pixelWidth || container.offsetWidth, + height: container.style.pixelHeight || container.offsetHeight + }; + } else { + return { + container: container, + width: y, + height: w + }; + } + } + return { + container: 1, + x: x, + y: y, + width: w, + height: h + }; + }; + + R.pathToRelative = pathToRelative; + R._engine = {}; + + R.path2curve = path2curve; + + R.matrix = function (a, b, c, d, e, f) { + return new Matrix(a, b, c, d, e, f); + }; + function Matrix(a, b, c, d, e, f) { + if (a != null) { + this.a = +a; + this.b = +b; + this.c = +c; + this.d = +d; + this.e = +e; + this.f = +f; + } else { + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.e = 0; + this.f = 0; + } + } + (function (matrixproto) { + + matrixproto.add = function (a, b, c, d, e, f) { + var out = [[], [], []], + m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]], + matrix = [[a, c, e], [b, d, f], [0, 0, 1]], + x, y, z, res; + + if (a && a instanceof Matrix) { + matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]]; + } + + for (x = 0; x < 3; x++) { + for (y = 0; y < 3; y++) { + res = 0; + for (z = 0; z < 3; z++) { + res += m[x][z] * matrix[z][y]; + } + out[x][y] = res; + } + } + this.a = out[0][0]; + this.b = out[1][0]; + this.c = out[0][1]; + this.d = out[1][1]; + this.e = out[0][2]; + this.f = out[1][2]; + }; + + matrixproto.invert = function () { + var me = this, + x = me.a * me.d - me.b * me.c; + return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x); + }; + + matrixproto.clone = function () { + return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f); + }; + + matrixproto.translate = function (x, y) { + this.add(1, 0, 0, 1, x, y); + }; + + matrixproto.scale = function (x, y, cx, cy) { + y == null && (y = x); + (cx || cy) && this.add(1, 0, 0, 1, cx, cy); + this.add(x, 0, 0, y, 0, 0); + (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy); + }; + + matrixproto.rotate = function (a, x, y) { + a = R.rad(a); + x = x || 0; + y = y || 0; + var cos = +math.cos(a).toFixed(9), + sin = +math.sin(a).toFixed(9); + this.add(cos, sin, -sin, cos, x, y); + this.add(1, 0, 0, 1, -x, -y); + }; + + matrixproto.x = function (x, y) { + return x * this.a + y * this.c + this.e; + }; + + matrixproto.y = function (x, y) { + return x * this.b + y * this.d + this.f; + }; + matrixproto.get = function (i) { + return +this[Str.fromCharCode(97 + i)].toFixed(4); + }; + matrixproto.toString = function () { + return R.svg ? + "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")" : + [this.get(0), this.get(2), this.get(1), this.get(3), 0, 0].join(); + }; + matrixproto.toFilter = function () { + return "progid:DXImageTransform.Microsoft.Matrix(M11=" + this.get(0) + + ", M12=" + this.get(2) + ", M21=" + this.get(1) + ", M22=" + this.get(3) + + ", Dx=" + this.get(4) + ", Dy=" + this.get(5) + ", sizingmethod='auto expand')"; + }; + matrixproto.offset = function () { + return [this.e.toFixed(4), this.f.toFixed(4)]; + }; + function norm(a) { + return a[0] * a[0] + a[1] * a[1]; + } + function normalize(a) { + var mag = math.sqrt(norm(a)); + a[0] && (a[0] /= mag); + a[1] && (a[1] /= mag); + } + + matrixproto.split = function () { + var out = {}; + // translation + out.dx = this.e; + out.dy = this.f; + + // scale and shear + var row = [[this.a, this.c], [this.b, this.d]]; + out.scalex = math.sqrt(norm(row[0])); + normalize(row[0]); + + out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1]; + row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear]; + + out.scaley = math.sqrt(norm(row[1])); + normalize(row[1]); + out.shear /= out.scaley; + + // rotation + var sin = -row[0][1], + cos = row[1][1]; + if (cos < 0) { + out.rotate = R.deg(math.acos(cos)); + if (sin < 0) { + out.rotate = 360 - out.rotate; + } + } else { + out.rotate = R.deg(math.asin(sin)); + } + + out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate); + out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate; + out.noRotation = !+out.shear.toFixed(9) && !out.rotate; + return out; + }; + + matrixproto.toTransformString = function (shorter) { + var s = shorter || this[split](); + if (s.isSimple) { + s.scalex = +s.scalex.toFixed(4); + s.scaley = +s.scaley.toFixed(4); + s.rotate = +s.rotate.toFixed(4); + return (s.dx || s.dy ? "t" + [s.dx, s.dy] : E) + + (s.scalex != 1 || s.scaley != 1 ? "s" + [s.scalex, s.scaley, 0, 0] : E) + + (s.rotate ? "r" + [s.rotate, 0, 0] : E); + } else { + return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)]; + } + }; + })(Matrix.prototype); + + // WebKit rendering bug workaround method + var version = navigator.userAgent.match(/Version\/(.*?)\s/) || navigator.userAgent.match(/Chrome\/(\d+)/); + if ((navigator.vendor == "Apple Computer, Inc.") && (version && version[1] < 4 || navigator.platform.slice(0, 2) == "iP") || + (navigator.vendor == "Google Inc." && version && version[1] < 8)) { + + paperproto.safari = function () { + var rect = this.rect(-99, -99, this.width + 99, this.height + 99).attr({stroke: "none"}); + setTimeout(function () {rect.remove();}); + }; + } else { + paperproto.safari = fun; + } + + var preventDefault = function () { + this.returnValue = false; + }, + preventTouch = function () { + return this.originalEvent.preventDefault(); + }, + stopPropagation = function () { + this.cancelBubble = true; + }, + stopTouch = function () { + return this.originalEvent.stopPropagation(); + }, + addEvent = (function () { + if (g.doc.addEventListener) { + return function (obj, type, fn, element) { + var realName = supportsTouch && touchMap[type] ? touchMap[type] : type, + f = function (e) { + var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, + scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft, + x = e.clientX + scrollX, + y = e.clientY + scrollY; + if (supportsTouch && touchMap[has](type)) { + for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) { + if (e.targetTouches[i].target == obj) { + var olde = e; + e = e.targetTouches[i]; + e.originalEvent = olde; + e.preventDefault = preventTouch; + e.stopPropagation = stopTouch; + break; + } + } + } + return fn.call(element, e, x, y); + }; + obj.addEventListener(realName, f, false); + return function () { + obj.removeEventListener(realName, f, false); + return true; + }; + }; + } else if (g.doc.attachEvent) { + return function (obj, type, fn, element) { + var f = function (e) { + e = e || g.win.event; + var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, + scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft, + x = e.clientX + scrollX, + y = e.clientY + scrollY; + e.preventDefault = e.preventDefault || preventDefault; + e.stopPropagation = e.stopPropagation || stopPropagation; + return fn.call(element, e, x, y); + }; + obj.attachEvent("on" + type, f); + var detacher = function () { + obj.detachEvent("on" + type, f); + return true; + }; + return detacher; + }; + } + })(), + drag = [], + dragMove = function (e) { + var x = e.clientX, + y = e.clientY, + scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, + scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft, + dragi, + j = drag.length; + while (j--) { + dragi = drag[j]; + if (supportsTouch) { + var i = e.touches.length, + touch; + while (i--) { + touch = e.touches[i]; + if (touch.identifier == dragi.el._drag.id) { + x = touch.clientX; + y = touch.clientY; + (e.originalEvent ? e.originalEvent : e).preventDefault(); + break; + } + } + } else { + e.preventDefault(); + } + var node = dragi.el.node, + o, + next = node.nextSibling, + parent = node.parentNode, + display = node.style.display; + g.win.opera && parent.removeChild(node); + node.style.display = "none"; + o = dragi.el.paper.getElementByPoint(x, y); + node.style.display = display; + g.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node)); + o && eve("drag.over." + dragi.el.id, dragi.el, o); + x += scrollX; + y += scrollY; + eve("drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e); + } + }, + dragUp = function (e) { + R.unmousemove(dragMove).unmouseup(dragUp); + var i = drag.length, + dragi; + while (i--) { + dragi = drag[i]; + dragi.el._drag = {}; + eve("drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e); + } + drag = []; + }, + + elproto = R.el = {}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + for (var i = events.length; i--;) { + (function (eventName) { + R[eventName] = elproto[eventName] = function (fn, scope) { + if (R.is(fn, "function")) { + this.events = this.events || []; + this.events.push({name: eventName, f: fn, unbind: addEvent(this.shape || this.node || g.doc, eventName, fn, scope || this)}); + } + return this; + }; + R["un" + eventName] = elproto["un" + eventName] = function (fn) { + var events = this.events || [], + l = events.length; + while (l--) if (events[l].name == eventName && events[l].f == fn) { + events[l].unbind(); + events.splice(l, 1); + !events.length && delete this.events; + return this; + } + return this; + }; + })(events[i]); + } + + + elproto.data = function (key, value) { + var data = eldata[this.id] = eldata[this.id] || {}; + if (arguments.length == 1) { + if (R.is(key, "object")) { + for (var i in key) if (key[has](i)) { + this.data(i, key[i]); + } + return this; + } + eve("data.get." + this.id, this, data[key], key); + return data[key]; + } + data[key] = value; + eve("data.set." + this.id, this, value, key); + return this; + }; + + elproto.removeData = function (key) { + if (key == null) { + eldata[this.id] = {}; + } else { + eldata[this.id] && delete eldata[this.id][key]; + } + return this; + }; + + elproto.hover = function (f_in, f_out, scope_in, scope_out) { + return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in); + }; + + elproto.unhover = function (f_in, f_out) { + return this.unmouseover(f_in).unmouseout(f_out); + }; + var draggable = []; + + elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) { + function start(e) { + (e.originalEvent || e).preventDefault(); + var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, + scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft; + this._drag.x = e.clientX + scrollX; + this._drag.y = e.clientY + scrollY; + this._drag.id = e.identifier; + !drag.length && R.mousemove(dragMove).mouseup(dragUp); + drag.push({el: this, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope}); + onstart && eve.on("drag.start." + this.id, onstart); + onmove && eve.on("drag.move." + this.id, onmove); + onend && eve.on("drag.end." + this.id, onend); + eve("drag.start." + this.id, start_scope || move_scope || this, e.clientX + scrollX, e.clientY + scrollY, e); + } + this._drag = {}; + draggable.push({el: this, start: start}); + this.mousedown(start); + return this; + }; + + elproto.onDragOver = function (f) { + f ? eve.on("drag.over." + this.id, f) : eve.unbind("drag.over." + this.id); + }; + + elproto.undrag = function () { + var i = draggable.length; + while (i--) if (draggable[i].el == this) { + this.unmousedown(draggable[i].start); + draggable.splice(i, 1); + eve.unbind("drag.*." + this.id); + } + !draggable.length && R.unmousemove(dragMove).unmouseup(dragUp); + }; + + paperproto.circle = function (x, y, r) { + var out = R._engine.circle(this, x || 0, y || 0, r || 0); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.rect = function (x, y, w, h, r) { + var out = R._engine.rect(this, x || 0, y || 0, w || 0, h || 0, r || 0); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.ellipse = function (x, y, rx, ry) { + var out = R._engine.ellipse(this, x || 0, y || 0, rx || 0, ry || 0); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.path = function (pathString) { + pathString && !R.is(pathString, string) && !R.is(pathString[0], array) && (pathString += E); + var out = R._engine.path(R.format[apply](R, arguments), this); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.image = function (src, x, y, w, h) { + var out = R._engine.image(this, src || "about:blank", x || 0, y || 0, w || 0, h || 0); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.text = function (x, y, text) { + var out = R._engine.text(this, x || 0, y || 0, Str(text)); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.set = function (itemsArray) { + !R.is(itemsArray, "array") && (itemsArray = Array.prototype.splice.call(arguments, 0, arguments.length)); + var out = new Set(itemsArray); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.setStart = function (set) { + this.__set__ = set || this.set(); + }; + + paperproto.setFinish = function (set) { + var out = this.__set__; + delete this.__set__; + return out; + }; + + paperproto.setSize = function (width, height) { + return R._engine.setSize.call(this, width, height); + }; + + paperproto.setViewBox = function (x, y, w, h, fit) { + return R._engine.setViewBox.call(this, x, y, w, h, fit); + }; + + + paperproto.top = paperproto.bottom = null; + + paperproto.raphael = R; + var getOffset = function (elem) { + var box = elem.getBoundingClientRect(), + doc = elem.ownerDocument, + body = doc.body, + docElem = doc.documentElement, + clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, + top = box.top + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop, + left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft; + return { + y: top, + x: left + }; + }; + + paperproto.getElementByPoint = function (x, y) { + var paper = this, + svg = paper.canvas, + target = g.doc.elementFromPoint(x, y); + if (g.win.opera && target.tagName == "svg") { + var so = getOffset(svg), + sr = svg.createSVGRect(); + sr.x = x - so.x; + sr.y = y - so.y; + sr.width = sr.height = 1; + var hits = svg.getIntersectionList(sr, null); + if (hits.length) { + target = hits[hits.length - 1]; + } + } + if (!target) { + return null; + } + while (target.parentNode && target != svg.parentNode && !target.raphael) { + target = target.parentNode; + } + target == paper.canvas.parentNode && (target = svg); + target = target && target.raphael ? paper.getById(target.raphaelid) : null; + return target; + }; + + paperproto.getById = function (id) { + var bot = this.bottom; + while (bot) { + if (bot.id == id) { + return bot; + } + bot = bot.next; + } + return null; + }; + + paperproto.forEach = function (callback, thisArg) { + var bot = this.bottom; + while (bot) { + if (callback.call(thisArg, bot) === false) { + return this; + } + bot = bot.next; + } + return this; + }; + function x_y() { + return this.x + S + this.y; + } + function x_y_w_h() { + return this.x + S + this.y + S + this.width + " \xd7 " + this.height; + } + + elproto.getBBox = function (isWithoutTransform) { + if (this.removed) { + return {}; + } + var _ = this._; + if (isWithoutTransform) { + if (_.dirty || !_.bboxwt) { + this.realPath = getPath[this.type](this); + _.bboxwt = pathDimensions(this.realPath); + _.bboxwt.toString = x_y_w_h; + _.dirty = 0; + } + return _.bboxwt; + } + if (_.dirty || _.dirtyT || !_.bbox) { + if (_.dirty || !this.realPath) { + _.bboxwt = 0; + this.realPath = getPath[this.type](this); + } + _.bbox = pathDimensions(mapPath(this.realPath, this.matrix)); + _.bbox.toString = x_y_w_h; + _.dirty = _.dirtyT = 0; + } + return _.bbox; + }; + + elproto.clone = function () { + if (this.removed) { + return null; + } + var out = this.paper[this.type]().attr(this.attr()); + this.__set__ && this.__set__.push(out); + return out; + }; + + elproto.glow = function (glow) { + if (this.type == "text") { + return null; + } + glow = glow || {}; + var s = { + width: (glow.width || 10) + (+this.attr("stroke-width") || 1), + fill: glow.fill || false, + opacity: glow.opacity || .5, + offsetx: glow.offsetx || 0, + offsety: glow.offsety || 0, + color: glow.color || "#000" + }, + c = s.width / 2, + r = this.paper, + out = r.set(), + path = this.realPath || getPath[this.type](this); + path = this.matrix ? mapPath(path, this.matrix) : path; + for (var i = 1; i < c + 1; i++) { + out.push(r.path(path).attr({ + stroke: s.color, + fill: s.fill ? s.color : "none", + "stroke-linejoin": "round", + "stroke-linecap": "round", + "stroke-width": +(s.width / c * i).toFixed(3), + opacity: +(s.opacity / c).toFixed(3) + })); + } + return out.insertBefore(this).translate(s.offsetx, s.offsety); + }; + var curveslengths = {}, + getPointAtSegmentLength = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) { + var len = 0, + precision = 100, + name = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y].join(), + cache = curveslengths[name], + old, dot; + !cache && (curveslengths[name] = cache = {data: []}); + cache.timer && clearTimeout(cache.timer); + cache.timer = setTimeout(function () {delete curveslengths[name];}, 2e3); + if (length != null && !cache.precision) { + var total = getPointAtSegmentLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y); + cache.precision = ~~total * 10; + cache.data = []; + } + precision = cache.precision || precision; + for (var i = 0; i < precision + 1; i++) { + if (cache.data[i * precision]) { + dot = cache.data[i * precision]; + } else { + dot = R.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, i / precision); + cache.data[i * precision] = dot; + } + i && (len += pow(pow(old.x - dot.x, 2) + pow(old.y - dot.y, 2), .5)); + if (length != null && len >= length) { + return dot; + } + old = dot; + } + if (length == null) { + return len; + } + }, + getLengthFactory = function (istotal, subpath) { + return function (path, length, onlystart) { + path = path2curve(path); + var x, y, p, l, sp = "", subpaths = {}, point, + len = 0; + for (var i = 0, ii = path.length; i < ii; i++) { + p = path[i]; + if (p[0] == "M") { + x = +p[1]; + y = +p[2]; + } else { + l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); + if (len + l > length) { + if (subpath && !subpaths.start) { + point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); + sp += ["C" + point.start.x, point.start.y, point.m.x, point.m.y, point.x, point.y]; + if (onlystart) {return sp;} + subpaths.start = sp; + sp = ["M" + point.x, point.y + "C" + point.n.x, point.n.y, point.end.x, point.end.y, p[5], p[6]].join(); + len += l; + x = +p[5]; + y = +p[6]; + continue; + } + if (!istotal && !subpath) { + point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); + return {x: point.x, y: point.y, alpha: point.alpha}; + } + } + len += l; + x = +p[5]; + y = +p[6]; + } + sp += p.shift() + p; + } + subpaths.end = sp; + point = istotal ? len : subpath ? subpaths : R.findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1); + point.alpha && (point = {x: point.x, y: point.y, alpha: point.alpha}); + return point; + }; + }; + var getTotalLength = getLengthFactory(1), + getPointAtLength = getLengthFactory(), + getSubpathsAtLength = getLengthFactory(0, 1); + + R.getTotalLength = getTotalLength; + + R.getPointAtLength = getPointAtLength; + + R.getSubpath = function (path, from, to) { + if (this.getTotalLength(path) - to < 1e-6) { + return getSubpathsAtLength(path, from).end; + } + var a = getSubpathsAtLength(path, to, 1); + return from ? getSubpathsAtLength(a, from).end : a; + }; + + elproto.getTotalLength = function () { + if (this.type != "path") {return;} + if (this.node.getTotalLength) { + return this.node.getTotalLength(); + } + return getTotalLength(this.attrs.path); + }; + + elproto.getPointAtLength = function (length) { + if (this.type != "path") {return;} + return getPointAtLength(this.attrs.path, length); + }; + + elproto.getSubpath = function (from, to) { + if (this.type != "path") {return;} + return R.getSubpath(this.attrs.path, from, to); + }; + + var ef = R.easing_formulas = { + linear: function (n) { + return n; + }, + "<": function (n) { + return pow(n, 1.7); + }, + ">": function (n) { + return pow(n, .48); + }, + "<>": function (n) { + var q = .48 - n / 1.04, + Q = math.sqrt(.1734 + q * q), + x = Q - q, + X = pow(abs(x), 1 / 3) * (x < 0 ? -1 : 1), + y = -Q - q, + Y = pow(abs(y), 1 / 3) * (y < 0 ? -1 : 1), + t = X + Y + .5; + return (1 - t) * 3 * t * t + t * t * t; + }, + backIn: function (n) { + var s = 1.70158; + return n * n * ((s + 1) * n - s); + }, + backOut: function (n) { + n = n - 1; + var s = 1.70158; + return n * n * ((s + 1) * n + s) + 1; + }, + elastic: function (n) { + if (n == !!n) { + return n; + } + return pow(2, -10 * n) * math.sin((n - .075) * (2 * PI) / .3) + 1; + }, + bounce: function (n) { + var s = 7.5625, + p = 2.75, + l; + if (n < (1 / p)) { + l = s * n * n; + } else { + if (n < (2 / p)) { + n -= (1.5 / p); + l = s * n * n + .75; + } else { + if (n < (2.5 / p)) { + n -= (2.25 / p); + l = s * n * n + .9375; + } else { + n -= (2.625 / p); + l = s * n * n + .984375; + } + } + } + return l; + } + }; + ef.easeIn = ef["ease-in"] = ef["<"]; + ef.easeOut = ef["ease-out"] = ef[">"]; + ef.easeInOut = ef["ease-in-out"] = ef["<>"]; + ef["back-in"] = ef.backIn; + ef["back-out"] = ef.backOut; + + var animationElements = [], + requestAnimFrame = window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function (callback) { + setTimeout(callback, 16); + }, + animation = function () { + var Now = +new Date, + l = 0; + for (; l < animationElements.length; l++) { + var e = animationElements[l]; + if (e.el.removed || e.paused) { + continue; + } + var time = Now - e.start, + ms = e.ms, + easing = e.easing, + from = e.from, + diff = e.diff, + to = e.to, + t = e.t, + that = e.el, + set = {}, + now, + init = {}, + key; + if (e.initstatus) { + time = (e.initstatus * e.anim.top - e.prev) / (e.percent - e.prev) * ms; + e.status = e.initstatus; + delete e.initstatus; + e.stop && animationElements.splice(l--, 1); + } else { + e.status = (e.prev + (e.percent - e.prev) * (time / ms)) / e.anim.top; + } + if (time < 0) { + continue; + } + if (time < ms) { + var pos = easing(time / ms); + for (var attr in from) if (from[has](attr)) { + switch (availableAnimAttrs[attr]) { + case nu: + now = +from[attr] + pos * ms * diff[attr]; + break; + case "colour": + now = "rgb(" + [ + upto255(round(from[attr].r + pos * ms * diff[attr].r)), + upto255(round(from[attr].g + pos * ms * diff[attr].g)), + upto255(round(from[attr].b + pos * ms * diff[attr].b)) + ].join(",") + ")"; + break; + case "path": + now = []; + for (var i = 0, ii = from[attr].length; i < ii; i++) { + now[i] = [from[attr][i][0]]; + for (var j = 1, jj = from[attr][i].length; j < jj; j++) { + now[i][j] = +from[attr][i][j] + pos * ms * diff[attr][i][j]; + } + now[i] = now[i].join(S); + } + now = now.join(S); + break; + case "transform": + if (diff[attr].real) { + now = []; + for (i = 0, ii = from[attr].length; i < ii; i++) { + now[i] = [from[attr][i][0]]; + for (j = 1, jj = from[attr][i].length; j < jj; j++) { + now[i][j] = from[attr][i][j] + pos * ms * diff[attr][i][j]; + } + } + } else { + var get = function (i) { + return +from[attr][i] + pos * ms * diff[attr][i]; + }; + // now = [["r", get(2), 0, 0], ["t", get(3), get(4)], ["s", get(0), get(1), 0, 0]]; + now = [["m", get(0), get(1), get(2), get(3), get(4), get(5)]]; + } + break; + case "csv": + if (attr == "clip-rect") { + now = []; + i = 4; + while (i--) { + now[i] = +from[attr][i] + pos * ms * diff[attr][i]; + } + } + break; + default: + var from2 = [][concat](from[attr]); + now = []; + i = that.paper.customAttributes[attr].length; + while (i--) { + now[i] = +from2[i] + pos * ms * diff[attr][i]; + } + break; + } + set[attr] = now; + } + that.attr(set); + (function (id, that, anim) { + setTimeout(function () { + eve("anim.frame." + id, that, anim); + }); + })(that.id, that, e.anim); + } else { + (function(f, el, a) { + setTimeout(function() { + eve("anim.frame." + el.id, el, a); + eve("anim.finish." + el.id, el, a); + R.is(f, "function") && f.call(el); + }); + })(e.callback, that, e.anim); + that.attr(to); + animationElements.splice(l--, 1); + if (e.repeat > 1 && !e.next) { + for (key in to) if (to[has](key)) { + init[key] = e.totalOrigin[key]; + } + e.el.attr(init); + runAnimation(e.anim, e.el, e.anim.percents[0], null, e.totalOrigin, e.repeat - 1); + } + if (e.next && !e.stop) { + runAnimation(e.anim, e.el, e.next, null, e.totalOrigin, e.repeat); + } + } + } + R.svg && that && that.paper && that.paper.safari(); + animationElements.length && requestAnimFrame(animation); + }, + upto255 = function (color) { + return color > 255 ? 255 : color < 0 ? 0 : color; + }; + + elproto.animateWith = function (el, anim, params, ms, easing, callback) { + var element = this; + if (element.removed) { + callback && callback.call(element); + return element; + } + var a = params instanceof Animation ? params : R.animation(params, ms, easing, callback), + x, y; + runAnimation(a, element, a.percents[0], null, element.attr()); + for (var i = 0, ii = animationElements.length; i < ii; i++) { + if (animationElements[i].anim == anim && animationElements[i].el == el) { + animationElements[ii - 1].start = animationElements[i].start; + break; + } + } + return element; + // + // + // var a = params ? R.animation(params, ms, easing, callback) : anim, + // status = element.status(anim); + // return this.animate(a).status(a, status * anim.ms / a.ms); + }; + function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration) { + var cx = 3 * p1x, + bx = 3 * (p2x - p1x) - cx, + ax = 1 - cx - bx, + cy = 3 * p1y, + by = 3 * (p2y - p1y) - cy, + ay = 1 - cy - by; + function sampleCurveX(t) { + return ((ax * t + bx) * t + cx) * t; + } + function solve(x, epsilon) { + var t = solveCurveX(x, epsilon); + return ((ay * t + by) * t + cy) * t; + } + function solveCurveX(x, epsilon) { + var t0, t1, t2, x2, d2, i; + for(t2 = x, i = 0; i < 8; i++) { + x2 = sampleCurveX(t2) - x; + if (abs(x2) < epsilon) { + return t2; + } + d2 = (3 * ax * t2 + 2 * bx) * t2 + cx; + if (abs(d2) < 1e-6) { + break; + } + t2 = t2 - x2 / d2; + } + t0 = 0; + t1 = 1; + t2 = x; + if (t2 < t0) { + return t0; + } + if (t2 > t1) { + return t1; + } + while (t0 < t1) { + x2 = sampleCurveX(t2); + if (abs(x2 - x) < epsilon) { + return t2; + } + if (x > x2) { + t0 = t2; + } else { + t1 = t2; + } + t2 = (t1 - t0) / 2 + t0; + } + return t2; + } + return solve(t, 1 / (200 * duration)); + } + elproto.onAnimation = function (f) { + f ? eve.on("anim.frame." + this.id, f) : eve.unbind("anim.frame." + this.id); + return this; + }; + function Animation(anim, ms) { + var percents = [], + newAnim = {}; + this.ms = ms; + this.times = 1; + if (anim) { + for (var attr in anim) if (anim[has](attr)) { + newAnim[toFloat(attr)] = anim[attr]; + percents.push(toFloat(attr)); + } + percents.sort(sortByNumber); + } + this.anim = newAnim; + this.top = percents[percents.length - 1]; + this.percents = percents; + } + + Animation.prototype.delay = function (delay) { + var a = new Animation(this.anim, this.ms); + a.times = this.times; + a.del = +delay || 0; + return a; + }; + + Animation.prototype.repeat = function (times) { + var a = new Animation(this.anim, this.ms); + a.del = this.del; + a.times = math.floor(mmax(times, 0)) || 1; + return a; + }; + function runAnimation(anim, element, percent, status, totalOrigin, times) { + percent = toFloat(percent); + var params, + isInAnim, + isInAnimSet, + percents = [], + next, + prev, + timestamp, + ms = anim.ms, + from = {}, + to = {}, + diff = {}; + if (status) { + for (i = 0, ii = animationElements.length; i < ii; i++) { + var e = animationElements[i]; + if (e.el.id == element.id && e.anim == anim) { + if (e.percent != percent) { + animationElements.splice(i, 1); + isInAnimSet = 1; + } else { + isInAnim = e; + } + element.attr(e.totalOrigin); + break; + } + } + } else { + status = +to; // NaN + } + for (var i = 0, ii = anim.percents.length; i < ii; i++) { + if (anim.percents[i] == percent || anim.percents[i] > status * anim.top) { + percent = anim.percents[i]; + prev = anim.percents[i - 1] || 0; + ms = ms / anim.top * (percent - prev); + next = anim.percents[i + 1]; + params = anim.anim[percent]; + break; + } else if (status) { + element.attr(anim.anim[anim.percents[i]]); + } + } + if (!params) { + return; + } + if (!isInAnim) { + for (var attr in params) if (params[has](attr)) { + if (availableAnimAttrs[has](attr) || element.paper.customAttributes[has](attr)) { + from[attr] = element.attr(attr); + (from[attr] == null) && (from[attr] = availableAttrs[attr]); + to[attr] = params[attr]; + switch (availableAnimAttrs[attr]) { + case nu: + diff[attr] = (to[attr] - from[attr]) / ms; + break; + case "colour": + from[attr] = R.getRGB(from[attr]); + var toColour = R.getRGB(to[attr]); + diff[attr] = { + r: (toColour.r - from[attr].r) / ms, + g: (toColour.g - from[attr].g) / ms, + b: (toColour.b - from[attr].b) / ms + }; + break; + case "path": + var pathes = path2curve(from[attr], to[attr]), + toPath = pathes[1]; + from[attr] = pathes[0]; + diff[attr] = []; + for (i = 0, ii = from[attr].length; i < ii; i++) { + diff[attr][i] = [0]; + for (var j = 1, jj = from[attr][i].length; j < jj; j++) { + diff[attr][i][j] = (toPath[i][j] - from[attr][i][j]) / ms; + } + } + break; + case "transform": + var _ = element._, + eq = equaliseTransform(_[attr], to[attr]); + if (eq) { + from[attr] = eq.from; + to[attr] = eq.to; + diff[attr] = []; + diff[attr].real = true; + for (i = 0, ii = from[attr].length; i < ii; i++) { + diff[attr][i] = [from[attr][i][0]]; + for (j = 1, jj = from[attr][i].length; j < jj; j++) { + diff[attr][i][j] = (to[attr][i][j] - from[attr][i][j]) / ms; + } + } + } else { + var m = (element.matrix || new Matrix), + to2 = { + _: {transform: _.transform}, + getBBox: function () { + return element.getBBox(1); + } + }; + from[attr] = [ + m.a, + m.b, + m.c, + m.d, + m.e, + m.f + ]; + extractTransform(to2, to[attr]); + to[attr] = to2._.transform; + diff[attr] = [ + (to2.matrix.a - m.a) / ms, + (to2.matrix.b - m.b) / ms, + (to2.matrix.c - m.c) / ms, + (to2.matrix.d - m.d) / ms, + (to2.matrix.e - m.e) / ms, + (to2.matrix.e - m.f) / ms + ]; + // from[attr] = [_.sx, _.sy, _.deg, _.dx, _.dy]; + // var to2 = {_:{}, getBBox: function () { return element.getBBox(); }}; + // extractTransform(to2, to[attr]); + // diff[attr] = [ + // (to2._.sx - _.sx) / ms, + // (to2._.sy - _.sy) / ms, + // (to2._.deg - _.deg) / ms, + // (to2._.dx - _.dx) / ms, + // (to2._.dy - _.dy) / ms + // ]; + } + break; + case "csv": + var values = Str(params[attr])[split](separator), + from2 = Str(from[attr])[split](separator); + if (attr == "clip-rect") { + from[attr] = from2; + diff[attr] = []; + i = from2.length; + while (i--) { + diff[attr][i] = (values[i] - from[attr][i]) / ms; + } + } + to[attr] = values; + break; + default: + values = [][concat](params[attr]); + from2 = [][concat](from[attr]); + diff[attr] = []; + i = element.paper.customAttributes[attr].length; + while (i--) { + diff[attr][i] = ((values[i] || 0) - (from2[i] || 0)) / ms; + } + break; + } + } + } + var easing = params.easing, + easyeasy = R.easing_formulas[easing]; + if (!easyeasy) { + easyeasy = Str(easing).match(bezierrg); + if (easyeasy && easyeasy.length == 5) { + var curve = easyeasy; + easyeasy = function (t) { + return CubicBezierAtTime(t, +curve[1], +curve[2], +curve[3], +curve[4], ms); + }; + } else { + easyeasy = pipe; + } + } + timestamp = params.start || anim.start || +new Date; + e = { + anim: anim, + percent: percent, + timestamp: timestamp, + start: timestamp + (anim.del || 0), + status: 0, + initstatus: status || 0, + stop: false, + ms: ms, + easing: easyeasy, + from: from, + diff: diff, + to: to, + el: element, + callback: params.callback, + prev: prev, + next: next, + repeat: times || anim.times, + origin: element.attr(), + totalOrigin: totalOrigin + }; + animationElements.push(e); + if (status && !isInAnim && !isInAnimSet) { + e.stop = true; + e.start = new Date - ms * status; + if (animationElements.length == 1) { + return animation(); + } + } + if (isInAnimSet) { + e.start = new Date - e.ms * status; + } + animationElements.length == 1 && requestAnimFrame(animation); + } else { + isInAnim.initstatus = status; + isInAnim.start = new Date - isInAnim.ms * status; + } + eve("anim.start." + element.id, element, anim); + } + + R.animation = function (params, ms, easing, callback) { + if (params instanceof Animation) { + return params; + } + if (R.is(easing, "function") || !easing) { + callback = callback || easing || null; + easing = null; + } + params = Object(params); + ms = +ms || 0; + var p = {}, + json, + attr; + for (attr in params) if (params[has](attr) && toFloat(attr) != attr && toFloat(attr) + "%" != attr) { + json = true; + p[attr] = params[attr]; + } + if (!json) { + return new Animation(params, ms); + } else { + easing && (p.easing = easing); + callback && (p.callback = callback); + return new Animation({100: p}, ms); + } + }; + + elproto.animate = function (params, ms, easing, callback) { + var element = this; + if (element.removed) { + callback && callback.call(element); + return element; + } + var anim = params instanceof Animation ? params : R.animation(params, ms, easing, callback); + runAnimation(anim, element, anim.percents[0], null, element.attr()); + return element; + }; + + elproto.setTime = function (anim, value) { + if (anim && value != null) { + this.status(anim, mmin(value, anim.ms) / anim.ms); + } + return this; + }; + + elproto.status = function (anim, value) { + var out = [], + i = 0, + len, + e; + if (value != null) { + runAnimation(anim, this, -1, mmin(value, 1)); + return this; + } else { + len = animationElements.length; + for (; i < len; i++) { + e = animationElements[i]; + if (e.el.id == this.id && (!anim || e.anim == anim)) { + if (anim) { + return e.status; + } + out.push({ + anim: e.anim, + status: e.status + }); + } + } + if (anim) { + return 0; + } + return out; + } + }; + + elproto.pause = function (anim) { + for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { + if (eve("anim.pause." + this.id, this, animationElements[i].anim) !== false) { + animationElements[i].paused = true; + } + } + return this; + }; + + elproto.resume = function (anim) { + for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { + var e = animationElements[i]; + if (eve("anim.resume." + this.id, this, e.anim) !== false) { + delete e.paused; + this.status(e.anim, e.status); + } + } + return this; + }; + + elproto.stop = function (anim) { + for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { + if (eve("anim.stop." + this.id, this, animationElements[i].anim) !== false) { + animationElements.splice(i--, 1); + } + } + return this; + }; + elproto.toString = function () { + return "Rapha\xebl\u2019s object"; + }; + + // Set + var Set = function (items) { + this.items = []; + this.length = 0; + this.type = "set"; + if (items) { + for (var i = 0, ii = items.length; i < ii; i++) { + if (items[i] && (items[i].constructor == elproto.constructor || items[i].constructor == Set)) { + this[this.items.length] = this.items[this.items.length] = items[i]; + this.length++; + } + } + } + }, + setproto = Set.prototype; + + setproto.push = function () { + var item, + len; + for (var i = 0, ii = arguments.length; i < ii; i++) { + item = arguments[i]; + if (item && (item.constructor == elproto.constructor || item.constructor == Set)) { + len = this.items.length; + this[len] = this.items[len] = item; + this.length++; + } + } + return this; + }; + + setproto.pop = function () { + this.length && delete this[this.length--]; + return this.items.pop(); + }; + + setproto.forEach = function (callback, thisArg) { + for (var i = 0, ii = this.items.length; i < ii; i++) { + if (callback.call(thisArg, this.items[i], i) === false) { + return this; + } + } + return this; + }; + for (var method in elproto) if (elproto[has](method)) { + setproto[method] = (function (methodname) { + return function () { + var arg = arguments; + return this.forEach(function (el) { + el[methodname][apply](el, arg); + }); + }; + })(method); + } + setproto.attr = function (name, value) { + if (name && R.is(name, array) && R.is(name[0], "object")) { + for (var j = 0, jj = name.length; j < jj; j++) { + this.items[j].attr(name[j]); + } + } else { + for (var i = 0, ii = this.items.length; i < ii; i++) { + this.items[i].attr(name, value); + } + } + return this; + }; + + setproto.clear = function () { + while (this.length) { + this.pop(); + } + }; + + setproto.splice = function (index, count, insertion) { + index = index < 0 ? mmax(this.length + index, 0) : index; + count = mmax(0, mmin(this.length - index, count)); + var tail = [], + todel = [], + args = [], + i; + for (i = 2; i < arguments.length; i++) { + args.push(arguments[i]); + } + for (i = 0; i < count; i++) { + todel.push(this[index + i]); + } + for (; i < this.length - index; i++) { + tail.push(this[index + i]); + } + var arglen = args.length; + for (i = 0; i < arglen + tail.length; i++) { + this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen]; + } + i = this.items.length = this.length -= count - arglen; + while (this[i]) { + delete this[i++]; + } + return new Set(todel); + }; + + setproto.exclude = function (el) { + for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) { + this.splice(i, 1); + return true; + } + }; + setproto.animate = function (params, ms, easing, callback) { + (R.is(easing, "function") || !easing) && (callback = easing || null); + var len = this.items.length, + i = len, + item, + set = this, + collector; + if (!len) { + return this; + } + callback && (collector = function () { + !--len && callback.call(set); + }); + easing = R.is(easing, string) ? easing : collector; + var anim = R.animation(params, ms, easing, collector); + item = this.items[--i].animate(anim); + while (i--) { + this.items[i] && !this.items[i].removed && this.items[i].animateWith(item, anim, anim); + } + return this; + }; + setproto.insertAfter = function (el) { + var i = this.items.length; + while (i--) { + this.items[i].insertAfter(el); + } + return this; + }; + setproto.getBBox = function () { + var x = [], + y = [], + w = [], + h = []; + for (var i = this.items.length; i--;) if (!this.items[i].removed) { + var box = this.items[i].getBBox(); + x.push(box.x); + y.push(box.y); + w.push(box.x + box.width); + h.push(box.y + box.height); + } + x = mmin[apply](0, x); + y = mmin[apply](0, y); + return { + x: x, + y: y, + width: mmax[apply](0, w) - x, + height: mmax[apply](0, h) - y + }; + }; + setproto.clone = function (s) { + s = new Set; + for (var i = 0, ii = this.items.length; i < ii; i++) { + s.push(this.items[i].clone()); + } + return s; + }; + setproto.toString = function () { + return "Rapha\xebl\u2018s set"; + }; + + + R.registerFont = function (font) { + if (!font.face) { + return font; + } + this.fonts = this.fonts || {}; + var fontcopy = { + w: font.w, + face: {}, + glyphs: {} + }, + family = font.face["font-family"]; + for (var prop in font.face) if (font.face[has](prop)) { + fontcopy.face[prop] = font.face[prop]; + } + if (this.fonts[family]) { + this.fonts[family].push(fontcopy); + } else { + this.fonts[family] = [fontcopy]; + } + if (!font.svg) { + fontcopy.face["units-per-em"] = toInt(font.face["units-per-em"], 10); + for (var glyph in font.glyphs) if (font.glyphs[has](glyph)) { + var path = font.glyphs[glyph]; + fontcopy.glyphs[glyph] = { + w: path.w, + k: {}, + d: path.d && "M" + path.d.replace(/[mlcxtrv]/g, function (command) { + return {l: "L", c: "C", x: "z", t: "m", r: "l", v: "c"}[command] || "M"; + }) + "z" + }; + if (path.k) { + for (var k in path.k) if (path[has](k)) { + fontcopy.glyphs[glyph].k[k] = path.k[k]; + } + } + } + } + return font; + }; + + paperproto.getFont = function (family, weight, style, stretch) { + stretch = stretch || "normal"; + style = style || "normal"; + weight = +weight || {normal: 400, bold: 700, lighter: 300, bolder: 800}[weight] || 400; + if (!R.fonts) { + return; + } + var font = R.fonts[family]; + if (!font) { + var name = new RegExp("(^|\\s)" + family.replace(/[^\w\d\s+!~.:_-]/g, E) + "(\\s|$)", "i"); + for (var fontName in R.fonts) if (R.fonts[has](fontName)) { + if (name.test(fontName)) { + font = R.fonts[fontName]; + break; + } + } + } + var thefont; + if (font) { + for (var i = 0, ii = font.length; i < ii; i++) { + thefont = font[i]; + if (thefont.face["font-weight"] == weight && (thefont.face["font-style"] == style || !thefont.face["font-style"]) && thefont.face["font-stretch"] == stretch) { + break; + } + } + } + return thefont; + }; + + paperproto.print = function (x, y, string, font, size, origin, letter_spacing) { + origin = origin || "middle"; // baseline|middle + letter_spacing = mmax(mmin(letter_spacing || 0, 1), -1); + var out = this.set(), + letters = Str(string)[split](E), + shift = 0, + path = E, + scale; + R.is(font, string) && (font = this.getFont(font)); + if (font) { + scale = (size || 16) / font.face["units-per-em"]; + var bb = font.face.bbox[split](separator), + top = +bb[0], + height = +bb[1] + (origin == "baseline" ? bb[3] - bb[1] + (+font.face.descent) : (bb[3] - bb[1]) / 2); + for (var i = 0, ii = letters.length; i < ii; i++) { + var prev = i && font.glyphs[letters[i - 1]] || {}, + curr = font.glyphs[letters[i]]; + shift += i ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) + (font.w * letter_spacing) : 0; + curr && curr.d && out.push(this.path(curr.d).attr({ + fill: "#000", + stroke: "none", + transform: [["t", shift * scale, 0]] + })); + } + out.transform(["...s", scale, scale, top, height, "t", (x - top) / scale, (y - height) / scale]); + } + return out; + }; + + + paperproto.add = function (json) { + if (R.is(json, "array")) { + var res = this.set(), + i = 0, + ii = json.length, + j; + for (; i < ii; i++) { + j = json[i] || {}; + elements[has](j.type) && res.push(this[j.type]().attr(j)); + } + } + return res; + }; + + + R.format = function (token, params) { + var args = R.is(params, array) ? [0][concat](params) : arguments; + token && R.is(token, string) && args.length - 1 && (token = token.replace(formatrg, function (str, i) { + return args[++i] == null ? E : args[i]; + })); + return token || E; + }; + + R.fullfill = (function () { + var tokenRegex = /\{([^\}]+)\}/g, + objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties + replacer = function (all, key, obj) { + var res = obj; + key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) { + name = name || quotedName; + if (res) { + if (name in res) { + res = res[name]; + } + typeof res == "function" && isFunc && (res = res()); + } + }); + res = (res == null || res == obj ? all : res) + ""; + return res; + }; + return function (str, obj) { + return String(str).replace(tokenRegex, function (all, key) { + return replacer(all, key, obj); + }); + }; + })(); + + R.ninja = function () { + oldRaphael.was ? (g.win.Raphael = oldRaphael.is) : delete Raphael; + return R; + }; + + R.st = setproto; + // Firefox <3.6 fix: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html + (function (doc, loaded, f) { + if (doc.readyState == null && doc.addEventListener){ + doc.addEventListener(loaded, f = function () { + doc.removeEventListener(loaded, f, false); + doc.readyState = "complete"; + }, false); + doc.readyState = "loading"; + } + function isLoaded() { + (/in/).test(doc.readyState) ? setTimeout(isLoaded, 9) : R.eve("DOMload"); + } + isLoaded(); + })(document, "DOMContentLoaded"); + + oldRaphael.was ? (g.win.Raphael = R) : (Raphael = R); + + eve.on("DOMload", function () { + loaded = true; + }); +})(); + + +// ┌─────────────────────────────────────────────────────────────────────┐ \\ +// │ Raphaël - JavaScript Vector Library │ \\ +// ├─────────────────────────────────────────────────────────────────────┤ \\ +// │ SVG Module │ \\ +// ├─────────────────────────────────────────────────────────────────────┤ \\ +// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ +// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ +// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ +// └─────────────────────────────────────────────────────────────────────┘ \\ +window.Raphael.svg && function (R) { + var has = "hasOwnProperty", + Str = String, + toFloat = parseFloat, + toInt = parseInt, + math = Math, + mmax = math.max, + abs = math.abs, + pow = math.pow, + separator = /[, ]+/, + eve = R.eve, + E = "", + S = " "; + var xlink = "http://www.w3.org/1999/xlink", + markers = { + block: "M5,0 0,2.5 5,5z", + classic: "M5,0 0,2.5 5,5 3.5,3 3.5,2z", + diamond: "M2.5,0 5,2.5 2.5,5 0,2.5z", + open: "M6,1 1,3.5 6,6", + oval: "M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z" + }, + markerCounter = {}; + R.toString = function () { + return "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version; + }; + var $ = function (el, attr) { + if (attr) { + if (typeof el == "string") { + el = $(el); + } + for (var key in attr) if (attr[has](key)) { + if (key.substring(0, 6) == "xlink:") { + el.setAttributeNS(xlink, key.substring(6), Str(attr[key])); + } else { + el.setAttribute(key, Str(attr[key])); + } + } + } else { + el = R._g.doc.createElementNS("http://www.w3.org/2000/svg", el); + el.style && (el.style.webkitTapHighlightColor = "rgba(0,0,0,0)"); + } + return el; + }, + addGradientFill = function (element, gradient) { + var type = "linear", + id = element.id + gradient, + fx = .5, fy = .5, + o = element.node, + SVG = element.paper, + s = o.style, + el = R._g.doc.getElementById(id); + if (!el) { + gradient = Str(gradient).replace(R._radial_gradient, function (all, _fx, _fy) { + type = "radial"; + if (_fx && _fy) { + fx = toFloat(_fx); + fy = toFloat(_fy); + var dir = ((fy > .5) * 2 - 1); + pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && + (fy = math.sqrt(.25 - pow(fx - .5, 2)) * dir + .5) && + fy != .5 && + (fy = fy.toFixed(5) - 1e-5 * dir); + } + return E; + }); + gradient = gradient.split(/\s*\-\s*/); + if (type == "linear") { + var angle = gradient.shift(); + angle = -toFloat(angle); + if (isNaN(angle)) { + return null; + } + var vector = [0, 0, math.cos(R.rad(angle)), math.sin(R.rad(angle))], + max = 1 / (mmax(abs(vector[2]), abs(vector[3])) || 1); + vector[2] *= max; + vector[3] *= max; + if (vector[2] < 0) { + vector[0] = -vector[2]; + vector[2] = 0; + } + if (vector[3] < 0) { + vector[1] = -vector[3]; + vector[3] = 0; + } + } + var dots = R._parseDots(gradient); + if (!dots) { + return null; + } + id = id.replace(/[\(\)\s,\xb0#]/g, "_"); + + if (element.gradient && id != element.gradient.id) { + SVG.defs.removeChild(element.gradient); + delete element.gradient; + } + + if (!element.gradient) { + el = $(type + "Gradient", {id: id}); + element.gradient = el; + $(el, type == "radial" ? { + fx: fx, + fy: fy + } : { + x1: vector[0], + y1: vector[1], + x2: vector[2], + y2: vector[3], + gradientTransform: element.matrix.invert() + }); + SVG.defs.appendChild(el); + for (var i = 0, ii = dots.length; i < ii; i++) { + el.appendChild($("stop", { + offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%", + "stop-color": dots[i].color || "#fff" + })); + } + } + } + $(o, { + fill: "url(#" + id + ")", + opacity: 1, + "fill-opacity": 1 + }); + s.fill = E; + s.opacity = 1; + s.fillOpacity = 1; + return 1; + }, + updatePosition = function (o) { + var bbox = o.getBBox(1); + $(o.pattern, {patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"}); + }, + addArrow = function (o, value, isEnd) { + if (o.type == "path") { + var values = Str(value).toLowerCase().split("-"), + p = o.paper, + se = isEnd ? "end" : "start", + node = o.node, + attrs = o.attrs, + stroke = attrs["stroke-width"], + i = values.length, + type = "classic", + from, + to, + dx, + refX, + attr, + w = 3, + h = 3, + t = 5; + while (i--) { + switch (values[i]) { + case "block": + case "classic": + case "oval": + case "diamond": + case "open": + case "none": + type = values[i]; + break; + case "wide": h = 5; break; + case "narrow": h = 2; break; + case "long": w = 5; break; + case "short": w = 2; break; + } + } + if (type == "open") { + w += 2; + h += 2; + t += 2; + dx = 1; + refX = isEnd ? 4 : 1; + attr = { + fill: "none", + stroke: attrs.stroke + }; + } else { + refX = dx = w / 2; + attr = { + fill: attrs.stroke, + stroke: "none" + }; + } + if (o._.arrows) { + if (isEnd) { + o._.arrows.endPath && markerCounter[o._.arrows.endPath]--; + o._.arrows.endMarker && markerCounter[o._.arrows.endMarker]--; + } else { + o._.arrows.startPath && markerCounter[o._.arrows.startPath]--; + o._.arrows.startMarker && markerCounter[o._.arrows.startMarker]--; + } + } else { + o._.arrows = {}; + } + if (type != "none") { + var pathId = "raphael-marker-" + type, + markerId = "raphael-marker-" + se + type + w + h + o.id; + if (!R._g.doc.getElementById(pathId)) { + p.defs.appendChild($($("path"), { + "stroke-linecap": "round", + d: markers[type], + id: pathId + })); + markerCounter[pathId] = 1; + } else { + markerCounter[pathId]++; + } + var marker = R._g.doc.getElementById(markerId), + use; + if (!marker) { + marker = $($("marker"), { + id: markerId, + markerHeight: h, + markerWidth: w, + orient: "auto", + refX: refX, + refY: h / 2 + }); + use = $($("use"), { + "xlink:href": "#" + pathId, + transform: (isEnd ? "rotate(180 " + w / 2 + " " + h / 2 + ") " : E) + "scale(" + w / t + "," + h / t + ")", + "stroke-width": (1 / ((w / t + h / t) / 2)).toFixed(4) + }); + marker.appendChild(use); + p.defs.appendChild(marker); + markerCounter[markerId] = 1; + } else { + markerCounter[markerId]++; + use = marker.getElementsByTagName("use")[0]; + } + $(use, attr); + var delta = dx * (type != "diamond" && type != "oval"); + if (isEnd) { + from = o._.arrows.startdx * stroke || 0; + to = R.getTotalLength(attrs.path) - delta * stroke; + } else { + from = delta * stroke; + to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0); + } + attr = {}; + attr["marker-" + se] = "url(#" + markerId + ")"; + if (to || from) { + attr.d = Raphael.getSubpath(attrs.path, from, to); + } + $(node, attr); + o._.arrows[se + "Path"] = pathId; + o._.arrows[se + "Marker"] = markerId; + o._.arrows[se + "dx"] = delta; + o._.arrows[se + "Type"] = type; + o._.arrows[se + "String"] = value; + } else { + if (isEnd) { + from = o._.arrows.startdx * stroke || 0; + to = R.getTotalLength(attrs.path) - from; + } else { + from = 0; + to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0); + } + o._.arrows[se + "Path"] && $(node, {d: Raphael.getSubpath(attrs.path, from, to)}); + delete o._.arrows[se + "Path"]; + delete o._.arrows[se + "Marker"]; + delete o._.arrows[se + "dx"]; + delete o._.arrows[se + "Type"]; + delete o._.arrows[se + "String"]; + } + for (attr in markerCounter) if (markerCounter[has](attr) && !markerCounter[attr]) { + var item = R._g.doc.getElementById(attr); + item && item.parentNode.removeChild(item); + } + } + }, + dasharray = { + "": [0], + "none": [0], + "-": [3, 1], + ".": [1, 1], + "-.": [3, 1, 1, 1], + "-..": [3, 1, 1, 1, 1, 1], + ". ": [1, 3], + "- ": [4, 3], + "--": [8, 3], + "- .": [4, 3, 1, 3], + "--.": [8, 3, 1, 3], + "--..": [8, 3, 1, 3, 1, 3] + }, + addDashes = function (o, value, params) { + value = dasharray[Str(value).toLowerCase()]; + if (value) { + var width = o.attrs["stroke-width"] || "1", + butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0, + dashes = [], + i = value.length; + while (i--) { + dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt; + } + $(o.node, {"stroke-dasharray": dashes.join(",")}); + } + }, + setFillAndStroke = function (o, params) { + var node = o.node, + attrs = o.attrs, + vis = node.style.visibility; + node.style.visibility = "hidden"; + for (var att in params) { + if (params[has](att)) { + if (!R._availableAttrs[has](att)) { + continue; + } + var value = params[att]; + attrs[att] = value; + switch (att) { + case "blur": + o.blur(value); + break; + case "href": + case "title": + case "target": + var pn = node.parentNode; + if (pn.tagName.toLowerCase() != "a") { + var hl = $("a"); + pn.insertBefore(hl, node); + hl.appendChild(node); + pn = hl; + } + if (att == "target") { + pn.setAttributeNS(xlink, "show", value == "blank" ? "new" : value); + } else { + pn.setAttributeNS(xlink, att, value); + } + break; + case "cursor": + node.style.cursor = value; + break; + case "transform": + o.transform(value); + break; + case "arrow-start": + addArrow(o, value); + break; + case "arrow-end": + addArrow(o, value, 1); + break; + case "clip-rect": + var rect = Str(value).split(separator); + if (rect.length == 4) { + o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode); + var el = $("clipPath"), + rc = $("rect"); + el.id = R.createUUID(); + $(rc, { + x: rect[0], + y: rect[1], + width: rect[2], + height: rect[3] + }); + el.appendChild(rc); + o.paper.defs.appendChild(el); + $(node, {"clip-path": "url(#" + el.id + ")"}); + o.clip = rc; + } + if (!value) { + var path = node.getAttribute("clip-path"); + if (path) { + var clip = R._g.doc.getElementById(path.replace(/(^url\(#|\)$)/g, E)); + clip && clip.parentNode.removeChild(clip); + $(node, {"clip-path": E}); + delete o.clip; + } + } + break; + case "path": + if (o.type == "path") { + $(node, {d: value ? attrs.path = R._pathToAbsolute(value) : "M0,0"}); + o._.dirty = 1; + if (o._.arrows) { + "startString" in o._.arrows && addArrow(o, o._.arrows.startString); + "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); + } + } + break; + case "width": + node.setAttribute(att, value); + o._.dirty = 1; + if (attrs.fx) { + att = "x"; + value = attrs.x; + } else { + break; + } + case "x": + if (attrs.fx) { + value = -attrs.x - (attrs.width || 0); + } + case "rx": + if (att == "rx" && o.type == "rect") { + break; + } + case "cx": + node.setAttribute(att, value); + o.pattern && updatePosition(o); + o._.dirty = 1; + break; + case "height": + node.setAttribute(att, value); + o._.dirty = 1; + if (attrs.fy) { + att = "y"; + value = attrs.y; + } else { + break; + } + case "y": + if (attrs.fy) { + value = -attrs.y - (attrs.height || 0); + } + case "ry": + if (att == "ry" && o.type == "rect") { + break; + } + case "cy": + node.setAttribute(att, value); + o.pattern && updatePosition(o); + o._.dirty = 1; + break; + case "r": + if (o.type == "rect") { + $(node, {rx: value, ry: value}); + } else { + node.setAttribute(att, value); + } + o._.dirty = 1; + break; + case "src": + if (o.type == "image") { + node.setAttributeNS(xlink, "href", value); + } + break; + case "stroke-width": + if (o._.sx != 1 || o._.sy != 1) { + value /= mmax(abs(o._.sx), abs(o._.sy)) || 1; + } + if (o.paper._vbSize) { + value *= o.paper._vbSize; + } + node.setAttribute(att, value); + if (attrs["stroke-dasharray"]) { + addDashes(o, attrs["stroke-dasharray"], params); + } + if (o._.arrows) { + "startString" in o._.arrows && addArrow(o, o._.arrows.startString); + "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); + } + break; + case "stroke-dasharray": + addDashes(o, value, params); + break; + case "fill": + var isURL = Str(value).match(R._ISURL); + if (isURL) { + el = $("pattern"); + var ig = $("image"); + el.id = R.createUUID(); + $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1}); + $(ig, {x: 0, y: 0, "xlink:href": isURL[1]}); + el.appendChild(ig); + + (function (el) { + R._preload(isURL[1], function () { + var w = this.offsetWidth, + h = this.offsetHeight; + $(el, {width: w, height: h}); + $(ig, {width: w, height: h}); + o.paper.safari(); + }); + })(el); + o.paper.defs.appendChild(el); + $(node, {fill: "url(#" + el.id + ")"}); + o.pattern = el; + o.pattern && updatePosition(o); + break; + } + var clr = R.getRGB(value); + if (!clr.error) { + delete params.gradient; + delete attrs.gradient; + !R.is(attrs.opacity, "undefined") && + R.is(params.opacity, "undefined") && + $(node, {opacity: attrs.opacity}); + !R.is(attrs["fill-opacity"], "undefined") && + R.is(params["fill-opacity"], "undefined") && + $(node, {"fill-opacity": attrs["fill-opacity"]}); + } else if ((o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value)) { + if ("opacity" in attrs || "fill-opacity" in attrs) { + var gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E)); + if (gradient) { + var stops = gradient.getElementsByTagName("stop"); + $(stops[stops.length - 1], {"stop-opacity": ("opacity" in attrs ? attrs.opacity : 1) * ("fill-opacity" in attrs ? attrs["fill-opacity"] : 1)}); + } + } + attrs.gradient = value; + attrs.fill = "none"; + break; + } + clr[has]("opacity") && $(node, {"fill-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity}); + case "stroke": + clr = R.getRGB(value); + node.setAttribute(att, clr.hex); + att == "stroke" && clr[has]("opacity") && $(node, {"stroke-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity}); + if (att == "stroke" && o._.arrows) { + "startString" in o._.arrows && addArrow(o, o._.arrows.startString); + "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); + } + break; + case "gradient": + (o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value); + break; + case "opacity": + if (attrs.gradient && !attrs[has]("stroke-opacity")) { + $(node, {"stroke-opacity": value > 1 ? value / 100 : value}); + } + // fall + case "fill-opacity": + if (attrs.gradient) { + gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E)); + if (gradient) { + stops = gradient.getElementsByTagName("stop"); + $(stops[stops.length - 1], {"stop-opacity": value}); + } + break; + } + default: + att == "font-size" && (value = toInt(value, 10) + "px"); + var cssrule = att.replace(/(\-.)/g, function (w) { + return w.substring(1).toUpperCase(); + }); + node.style[cssrule] = value; + o._.dirty = 1; + node.setAttribute(att, value); + break; + } + } + } + + tuneText(o, params); + node.style.visibility = vis; + }, + leading = 1.2, + tuneText = function (el, params) { + if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) { + return; + } + var a = el.attrs, + node = el.node, + fontSize = node.firstChild ? toInt(R._g.doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size"), 10) : 10; + + if (params[has]("text")) { + a.text = params.text; + while (node.firstChild) { + node.removeChild(node.firstChild); + } + var texts = Str(params.text).split("\n"), + tspans = [], + tspan; + for (var i = 0, ii = texts.length; i < ii; i++) { + tspan = $("tspan"); + i && $(tspan, {dy: fontSize * leading, x: a.x}); + tspan.appendChild(R._g.doc.createTextNode(texts[i])); + node.appendChild(tspan); + tspans[i] = tspan; + } + } else { + tspans = node.getElementsByTagName("tspan"); + for (i = 0, ii = tspans.length; i < ii; i++) if (i) { + $(tspans[i], {dy: fontSize * leading, x: a.x}); + } else { + $(tspans[0], {dy: 0}); + } + } + $(node, {x: a.x, y: a.y}); + el._.dirty = 1; + var bb = el._getBBox(), + dif = a.y - (bb.y + bb.height / 2); + dif && R.is(dif, "finite") && $(tspans[0], {dy: dif}); + }, + Element = function (node, svg) { + var X = 0, + Y = 0; + + this[0] = this.node = node; + + node.raphael = true; + + this.id = R._oid++; + node.raphaelid = this.id; + this.matrix = R.matrix(); + this.realPath = null; + + this.paper = svg; + this.attrs = this.attrs || {}; + this._ = { + transform: [], + sx: 1, + sy: 1, + deg: 0, + dx: 0, + dy: 0, + dirty: 1 + }; + !svg.bottom && (svg.bottom = this); + + this.prev = svg.top; + svg.top && (svg.top.next = this); + svg.top = this; + + this.next = null; + }, + elproto = R.el; + + Element.prototype = elproto; + elproto.constructor = Element; + + R._engine.path = function (pathString, SVG) { + var el = $("path"); + SVG.canvas && SVG.canvas.appendChild(el); + var p = new Element(el, SVG); + p.type = "path"; + setFillAndStroke(p, { + fill: "none", + stroke: "#000", + path: pathString + }); + return p; + }; + + elproto.rotate = function (deg, cx, cy) { + if (this.removed) { + return this; + } + deg = Str(deg).split(separator); + if (deg.length - 1) { + cx = toFloat(deg[1]); + cy = toFloat(deg[2]); + } + deg = toFloat(deg[0]); + (cy == null) && (cx = cy); + if (cx == null || cy == null) { + var bbox = this.getBBox(1); + cx = bbox.x + bbox.width / 2; + cy = bbox.y + bbox.height / 2; + } + this.transform(this._.transform.concat([["r", deg, cx, cy]])); + return this; + }; + + elproto.scale = function (sx, sy, cx, cy) { + if (this.removed) { + return this; + } + sx = Str(sx).split(separator); + if (sx.length - 1) { + sy = toFloat(sx[1]); + cx = toFloat(sx[2]); + cy = toFloat(sx[3]); + } + sx = toFloat(sx[0]); + (sy == null) && (sy = sx); + (cy == null) && (cx = cy); + if (cx == null || cy == null) { + var bbox = this.getBBox(1); + } + cx = cx == null ? bbox.x + bbox.width / 2 : cx; + cy = cy == null ? bbox.y + bbox.height / 2 : cy; + this.transform(this._.transform.concat([["s", sx, sy, cx, cy]])); + return this; + }; + + elproto.translate = function (dx, dy) { + if (this.removed) { + return this; + } + dx = Str(dx).split(separator); + if (dx.length - 1) { + dy = toFloat(dx[1]); + } + dx = toFloat(dx[0]) || 0; + dy = +dy || 0; + this.transform(this._.transform.concat([["t", dx, dy]])); + return this; + }; + + elproto.transform = function (tstr) { + var _ = this._; + if (tstr == null) { + return _.transform; + } + R._extractTransform(this, tstr); + + this.clip && $(this.clip, {transform: this.matrix.invert()}); + this.pattern && updatePosition(this); + this.node && $(this.node, {transform: this.matrix}); + + if (_.sx != 1 || _.sy != 1) { + var sw = this.attrs[has]("stroke-width") ? this.attrs["stroke-width"] : 1; + this.attr({"stroke-width": sw}); + } + + return this; + }; + + elproto.hide = function () { + !this.removed && this.paper.safari(this.node.style.display = "none"); + return this; + }; + + elproto.show = function () { + !this.removed && this.paper.safari(this.node.style.display = ""); + return this; + }; + + elproto.remove = function () { + if (this.removed) { + return; + } + var paper = this.paper; + paper.__set__ && paper.__set__.exclude(this); + eve.unbind("*.*." + this.id); + if (this.gradient) { + paper.defs.removeChild(this.gradient); + } + R._tear(this, paper); + if (this.node.parentNode.tagName.toLowerCase() == "a") { + this.node.parentNode.parentNode.removeChild(this.node.parentNode); + } else { + this.node.parentNode.removeChild(this.node); + } + for (var i in this) { + this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; + } + this.removed = true; + }; + elproto._getBBox = function () { + if (this.node.style.display == "none") { + this.show(); + var hide = true; + } + var bbox = {}; + try { + bbox = this.node.getBBox(); + } catch(e) { + // Firefox 3.0.x plays badly here + } finally { + bbox = bbox || {}; + } + hide && this.hide(); + return bbox; + }; + + elproto.attr = function (name, value) { + if (this.removed) { + return this; + } + if (name == null) { + var res = {}; + for (var a in this.attrs) if (this.attrs[has](a)) { + res[a] = this.attrs[a]; + } + res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient; + res.transform = this._.transform; + return res; + } + if (value == null && R.is(name, "string")) { + if (name == "fill" && this.attrs.fill == "none" && this.attrs.gradient) { + return this.attrs.gradient; + } + if (name == "transform") { + return this._.transform; + } + var names = name.split(separator), + out = {}; + for (var i = 0, ii = names.length; i < ii; i++) { + name = names[i]; + if (name in this.attrs) { + out[name] = this.attrs[name]; + } else if (R.is(this.paper.customAttributes[name], "function")) { + out[name] = this.paper.customAttributes[name].def; + } else { + out[name] = R._availableAttrs[name]; + } + } + return ii - 1 ? out : out[names[0]]; + } + if (value == null && R.is(name, "array")) { + out = {}; + for (i = 0, ii = name.length; i < ii; i++) { + out[name[i]] = this.attr(name[i]); + } + return out; + } + if (value != null) { + var params = {}; + params[name] = value; + } else if (name != null && R.is(name, "object")) { + params = name; + } + for (var key in params) { + eve("attr." + key + "." + this.id, this, params[key]); + } + for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) { + var par = this.paper.customAttributes[key].apply(this, [].concat(params[key])); + this.attrs[key] = params[key]; + for (var subkey in par) if (par[has](subkey)) { + params[subkey] = par[subkey]; + } + } + setFillAndStroke(this, params); + return this; + }; + + elproto.toFront = function () { + if (this.removed) { + return this; + } + if (this.node.parentNode.tagName.toLowerCase() == "a") { + this.node.parentNode.parentNode.appendChild(this.node.parentNode); + } else { + this.node.parentNode.appendChild(this.node); + } + var svg = this.paper; + svg.top != this && R._tofront(this, svg); + return this; + }; + + elproto.toBack = function () { + if (this.removed) { + return this; + } + var parent = this.node.parentNode; + if (parent.tagName.toLowerCase() == "a") { + parent.parentNode.insertBefore(this.node.parentNode, this.node.parentNode.parentNode.firstChild); + } else if (parent.firstChild != this.node) { + parent.insertBefore(this.node, this.node.parentNode.firstChild); + } + R._toback(this, this.paper); + var svg = this.paper; + return this; + }; + + elproto.insertAfter = function (element) { + if (this.removed) { + return this; + } + var node = element.node || element[element.length - 1].node; + if (node.nextSibling) { + node.parentNode.insertBefore(this.node, node.nextSibling); + } else { + node.parentNode.appendChild(this.node); + } + R._insertafter(this, element, this.paper); + return this; + }; + + elproto.insertBefore = function (element) { + if (this.removed) { + return this; + } + var node = element.node || element[0].node; + node.parentNode.insertBefore(this.node, node); + R._insertbefore(this, element, this.paper); + return this; + }; + elproto.blur = function (size) { + // Experimental. No Safari support. Use it on your own risk. + var t = this; + if (+size !== 0) { + var fltr = $("filter"), + blur = $("feGaussianBlur"); + t.attrs.blur = size; + fltr.id = R.createUUID(); + $(blur, {stdDeviation: +size || 1.5}); + fltr.appendChild(blur); + t.paper.defs.appendChild(fltr); + t._blur = fltr; + $(t.node, {filter: "url(#" + fltr.id + ")"}); + } else { + if (t._blur) { + t._blur.parentNode.removeChild(t._blur); + delete t._blur; + delete t.attrs.blur; + } + t.node.removeAttribute("filter"); + } + }; + R._engine.circle = function (svg, x, y, r) { + var el = $("circle"); + svg.canvas && svg.canvas.appendChild(el); + var res = new Element(el, svg); + res.attrs = {cx: x, cy: y, r: r, fill: "none", stroke: "#000"}; + res.type = "circle"; + $(el, res.attrs); + return res; + }; + R._engine.rect = function (svg, x, y, w, h, r) { + var el = $("rect"); + svg.canvas && svg.canvas.appendChild(el); + var res = new Element(el, svg); + res.attrs = {x: x, y: y, width: w, height: h, r: r || 0, rx: r || 0, ry: r || 0, fill: "none", stroke: "#000"}; + res.type = "rect"; + $(el, res.attrs); + return res; + }; + R._engine.ellipse = function (svg, x, y, rx, ry) { + var el = $("ellipse"); + svg.canvas && svg.canvas.appendChild(el); + var res = new Element(el, svg); + res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: "none", stroke: "#000"}; + res.type = "ellipse"; + $(el, res.attrs); + return res; + }; + R._engine.image = function (svg, src, x, y, w, h) { + var el = $("image"); + $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: "none"}); + el.setAttributeNS(xlink, "href", src); + svg.canvas && svg.canvas.appendChild(el); + var res = new Element(el, svg); + res.attrs = {x: x, y: y, width: w, height: h, src: src}; + res.type = "image"; + return res; + }; + R._engine.text = function (svg, x, y, text) { + var el = $("text"); + svg.canvas && svg.canvas.appendChild(el); + var res = new Element(el, svg); + res.attrs = { + x: x, + y: y, + "text-anchor": "middle", + text: text, + font: R._availableAttrs.font, + stroke: "none", + fill: "#000" + }; + res.type = "text"; + setFillAndStroke(res, res.attrs); + return res; + }; + R._engine.setSize = function (width, height) { + this.width = width || this.width; + this.height = height || this.height; + this.canvas.setAttribute("width", this.width); + this.canvas.setAttribute("height", this.height); + if (this._viewBox) { + this.setViewBox.apply(this, this._viewBox); + } + return this; + }; + R._engine.create = function () { + var con = R._getContainer.apply(0, arguments), + container = con && con.container, + x = con.x, + y = con.y, + width = con.width, + height = con.height; + if (!container) { + throw new Error("SVG container not found."); + } + var cnvs = $("svg"), + css = "overflow:hidden;", + isFloating; + x = x || 0; + y = y || 0; + width = width || 512; + height = height || 342; + $(cnvs, { + height: height, + version: 1.1, + width: width, + xmlns: "http://www.w3.org/2000/svg" + }); + if (container == 1) { + cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px"; + R._g.doc.body.appendChild(cnvs); + isFloating = 1; + } else { + cnvs.style.cssText = css + "position:relative"; + if (container.firstChild) { + container.insertBefore(cnvs, container.firstChild); + } else { + container.appendChild(cnvs); + } + } + container = new R._Paper; + container.width = width; + container.height = height; + container.canvas = cnvs; + container.clear(); + container._left = container._top = 0; + isFloating && (container.renderfix = function () {}); + container.renderfix(); + return container; + }; + R._engine.setViewBox = function (x, y, w, h, fit) { + eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]); + var size = mmax(w / this.width, h / this.height), + top = this.top, + aspectRatio = fit ? "meet" : "xMinYMin", + vb, + sw; + if (x == null) { + if (this._vbSize) { + size = 1; + } + delete this._vbSize; + vb = "0 0 " + this.width + S + this.height; + } else { + this._vbSize = size; + vb = x + S + y + S + w + S + h; + } + $(this.canvas, { + viewBox: vb, + preserveAspectRatio: aspectRatio + }); + while (size && top) { + sw = "stroke-width" in top.attrs ? top.attrs["stroke-width"] : 1; + top.attr({"stroke-width": sw}); + top._.dirty = 1; + top._.dirtyT = 1; + top = top.prev; + } + this._viewBox = [x, y, w, h, !!fit]; + return this; + }; + + R.prototype.renderfix = function () { + var cnvs = this.canvas, + s = cnvs.style, + pos; + try { + pos = cnvs.getScreenCTM() || cnvs.createSVGMatrix(); + } catch (e) { + pos = cnvs.createSVGMatrix(); + } + var left = -pos.e % 1, + top = -pos.f % 1; + if (left || top) { + if (left) { + this._left = (this._left + left) % 1; + s.left = this._left + "px"; + } + if (top) { + this._top = (this._top + top) % 1; + s.top = this._top + "px"; + } + } + }; + + R.prototype.clear = function () { + R.eve("clear", this); + var c = this.canvas; + while (c.firstChild) { + c.removeChild(c.firstChild); + } + this.bottom = this.top = null; + (this.desc = $("desc")).appendChild(R._g.doc.createTextNode("Created with Rapha\xebl " + R.version)); + c.appendChild(this.desc); + c.appendChild(this.defs = $("defs")); + }; + + R.prototype.remove = function () { + eve("remove", this); + this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas); + for (var i in this) { + this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; + } + }; + var setproto = R.st; + for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) { + setproto[method] = (function (methodname) { + return function () { + var arg = arguments; + return this.forEach(function (el) { + el[methodname].apply(el, arg); + }); + }; + })(method); + } +}(window.Raphael); + +// ┌─────────────────────────────────────────────────────────────────────┐ \\ +// │ Raphaël - JavaScript Vector Library │ \\ +// ├─────────────────────────────────────────────────────────────────────┤ \\ +// │ VML Module │ \\ +// ├─────────────────────────────────────────────────────────────────────┤ \\ +// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ +// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ +// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ +// └─────────────────────────────────────────────────────────────────────┘ \\ +window.Raphael.vml && function (R) { + var has = "hasOwnProperty", + Str = String, + toFloat = parseFloat, + math = Math, + round = math.round, + mmax = math.max, + mmin = math.min, + abs = math.abs, + fillString = "fill", + separator = /[, ]+/, + eve = R.eve, + ms = " progid:DXImageTransform.Microsoft", + S = " ", + E = "", + map = {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"}, + bites = /([clmz]),?([^clmz]*)/gi, + blurregexp = / progid:\S+Blur\([^\)]+\)/g, + val = /-?[^,\s-]+/g, + cssDot = "position:absolute;left:0;top:0;width:1px;height:1px", + zoom = 21600, + pathTypes = {path: 1, rect: 1, image: 1}, + ovalTypes = {circle: 1, ellipse: 1}, + path2vml = function (path) { + var total = /[ahqstv]/ig, + command = R._pathToAbsolute; + Str(path).match(total) && (command = R._path2curve); + total = /[clmz]/g; + if (command == R._pathToAbsolute && !Str(path).match(total)) { + var res = Str(path).replace(bites, function (all, command, args) { + var vals = [], + isMove = command.toLowerCase() == "m", + res = map[command]; + args.replace(val, function (value) { + if (isMove && vals.length == 2) { + res += vals + map[command == "m" ? "l" : "L"]; + vals = []; + } + vals.push(round(value * zoom)); + }); + return res + vals; + }); + return res; + } + var pa = command(path), p, r; + res = []; + for (var i = 0, ii = pa.length; i < ii; i++) { + p = pa[i]; + r = pa[i][0].toLowerCase(); + r == "z" && (r = "x"); + for (var j = 1, jj = p.length; j < jj; j++) { + r += round(p[j] * zoom) + (j != jj - 1 ? "," : E); + } + res.push(r); + } + return res.join(S); + }, + compensation = function (deg, dx, dy) { + var m = R.matrix(); + m.rotate(-deg, .5, .5); + return { + dx: m.x(dx, dy), + dy: m.y(dx, dy) + }; + }, + setCoords = function (p, sx, sy, dx, dy, deg) { + var _ = p._, + m = p.matrix, + fillpos = _.fillpos, + o = p.node, + s = o.style, + y = 1, + flip = "", + dxdy, + kx = zoom / sx, + ky = zoom / sy; + s.visibility = "hidden"; + if (!sx || !sy) { + return; + } + o.coordsize = abs(kx) + S + abs(ky); + s.rotation = deg * (sx * sy < 0 ? -1 : 1); + if (deg) { + var c = compensation(deg, dx, dy); + dx = c.dx; + dy = c.dy; + } + sx < 0 && (flip += "x"); + sy < 0 && (flip += " y") && (y = -1); + s.flip = flip; + o.coordorigin = (dx * -kx) + S + (dy * -ky); + if (fillpos || _.fillsize) { + var fill = o.getElementsByTagName(fillString); + fill = fill && fill[0]; + o.removeChild(fill); + if (fillpos) { + c = compensation(deg, m.x(fillpos[0], fillpos[1]), m.y(fillpos[0], fillpos[1])); + fill.position = c.dx * y + S + c.dy * y; + } + if (_.fillsize) { + fill.size = _.fillsize[0] * abs(sx) + S + _.fillsize[1] * abs(sy); + } + o.appendChild(fill); + } + s.visibility = "visible"; + }; + R.toString = function () { + return "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version; + }; + var addArrow = function (o, value, isEnd) { + var values = Str(value).toLowerCase().split("-"), + se = isEnd ? "end" : "start", + i = values.length, + type = "classic", + w = "medium", + h = "medium"; + while (i--) { + switch (values[i]) { + case "block": + case "classic": + case "oval": + case "diamond": + case "open": + case "none": + type = values[i]; + break; + case "wide": + case "narrow": h = values[i]; break; + case "long": + case "short": w = values[i]; break; + } + } + var stroke = o.node.getElementsByTagName("stroke")[0]; + stroke[se + "arrow"] = type; + stroke[se + "arrowlength"] = w; + stroke[se + "arrowwidth"] = h; + }, + setFillAndStroke = function (o, params) { + // o.paper.canvas.style.display = "none"; + o.attrs = o.attrs || {}; + var node = o.node, + a = o.attrs, + s = node.style, + xy, + newpath = pathTypes[o.type] && (params.x != a.x || params.y != a.y || params.width != a.width || params.height != a.height || params.cx != a.cx || params.cy != a.cy || params.rx != a.rx || params.ry != a.ry || params.r != a.r), + isOval = ovalTypes[o.type] && (a.cx != params.cx || a.cy != params.cy || a.r != params.r || a.rx != params.rx || a.ry != params.ry), + res = o; + + + for (var par in params) if (params[has](par)) { + a[par] = params[par]; + } + if (newpath) { + a.path = R._getPath[o.type](o); + o._.dirty = 1; + } + params.href && (node.href = params.href); + params.title && (node.title = params.title); + params.target && (node.target = params.target); + params.cursor && (s.cursor = params.cursor); + "blur" in params && o.blur(params.blur); + if (params.path && o.type == "path" || newpath) { + node.path = path2vml(~Str(a.path).toLowerCase().indexOf("r") ? R._pathToAbsolute(a.path) : a.path); + if (o.type == "image") { + o._.fillpos = [a.x, a.y]; + o._.fillsize = [a.width, a.height]; + setCoords(o, 1, 1, 0, 0, 0); + } + } + "transform" in params && o.transform(params.transform); + if (isOval) { + var cx = +a.cx, + cy = +a.cy, + rx = +a.rx || +a.r || 0, + ry = +a.ry || +a.r || 0; + node.path = R.format("ar{0},{1},{2},{3},{4},{1},{4},{1}x", round((cx - rx) * zoom), round((cy - ry) * zoom), round((cx + rx) * zoom), round((cy + ry) * zoom), round(cx * zoom)); + } + if ("clip-rect" in params) { + var rect = Str(params["clip-rect"]).split(separator); + if (rect.length == 4) { + rect[2] = +rect[2] + (+rect[0]); + rect[3] = +rect[3] + (+rect[1]); + var div = node.clipRect || R._g.doc.createElement("div"), + dstyle = div.style; + dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect); + if (!node.clipRect) { + dstyle.position = "absolute"; + dstyle.top = 0; + dstyle.left = 0; + dstyle.width = o.paper.width + "px"; + dstyle.height = o.paper.height + "px"; + node.parentNode.insertBefore(div, node); + div.appendChild(node); + node.clipRect = div; + } + } + if (!params["clip-rect"]) { + node.clipRect && (node.clipRect.style.clip = "auto"); + } + } + if (o.textpath) { + var textpathStyle = o.textpath.style; + params.font && (textpathStyle.font = params.font); + params["font-family"] && (textpathStyle.fontFamily = '"' + params["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g, E) + '"'); + params["font-size"] && (textpathStyle.fontSize = params["font-size"]); + params["font-weight"] && (textpathStyle.fontWeight = params["font-weight"]); + params["font-style"] && (textpathStyle.fontStyle = params["font-style"]); + } + if ("arrow-start" in params) { + addArrow(res, params["arrow-start"]); + } + if ("arrow-end" in params) { + addArrow(res, params["arrow-end"], 1); + } + if (params.opacity != null || + params["stroke-width"] != null || + params.fill != null || + params.src != null || + params.stroke != null || + params["stroke-width"] != null || + params["stroke-opacity"] != null || + params["fill-opacity"] != null || + params["stroke-dasharray"] != null || + params["stroke-miterlimit"] != null || + params["stroke-linejoin"] != null || + params["stroke-linecap"] != null) { + var fill = node.getElementsByTagName(fillString), + newfill = false; + fill = fill && fill[0]; + !fill && (newfill = fill = createNode(fillString)); + if (o.type == "image" && params.src) { + fill.src = params.src; + } + params.fill && (fill.on = true); + if (fill.on == null || params.fill == "none" || params.fill === null) { + fill.on = false; + } + if (fill.on && params.fill) { + var isURL = Str(params.fill).match(R._ISURL); + if (isURL) { + fill.parentNode == node && node.removeChild(fill); + fill.rotate = true; + fill.src = isURL[1]; + fill.type = "tile"; + var bbox = o.getBBox(1); + fill.position = bbox.x + S + bbox.y; + o._.fillpos = [bbox.x, bbox.y]; + + R._preload(isURL[1], function () { + o._.fillsize = [this.offsetWidth, this.offsetHeight]; + }); + } else { + fill.color = R.getRGB(params.fill).hex; + fill.src = E; + fill.type = "solid"; + if (R.getRGB(params.fill).error && (res.type in {circle: 1, ellipse: 1} || Str(params.fill).charAt() != "r") && addGradientFill(res, params.fill, fill)) { + a.fill = "none"; + a.gradient = params.fill; + fill.rotate = false; + } + } + } + if ("fill-opacity" in params || "opacity" in params) { + var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+R.getRGB(params.fill).o + 1 || 2) - 1); + opacity = mmin(mmax(opacity, 0), 1); + fill.opacity = opacity; + if (fill.src) { + fill.color = "none"; + } + } + node.appendChild(fill); + var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]), + newstroke = false; + !stroke && (newstroke = stroke = createNode("stroke")); + if ((params.stroke && params.stroke != "none") || + params["stroke-width"] || + params["stroke-opacity"] != null || + params["stroke-dasharray"] || + params["stroke-miterlimit"] || + params["stroke-linejoin"] || + params["stroke-linecap"]) { + stroke.on = true; + } + (params.stroke == "none" || params.stroke === null || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false); + var strokeColor = R.getRGB(params.stroke); + stroke.on && params.stroke && (stroke.color = strokeColor.hex); + opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+strokeColor.o + 1 || 2) - 1); + var width = (toFloat(params["stroke-width"]) || 1) * .75; + opacity = mmin(mmax(opacity, 0), 1); + params["stroke-width"] == null && (width = a["stroke-width"]); + params["stroke-width"] && (stroke.weight = width); + width && width < 1 && (opacity *= width) && (stroke.weight = 1); + stroke.opacity = opacity; + + params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"] || "miter"); + stroke.miterlimit = params["stroke-miterlimit"] || 8; + params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round"); + if (params["stroke-dasharray"]) { + var dasharray = { + "-": "shortdash", + ".": "shortdot", + "-.": "shortdashdot", + "-..": "shortdashdotdot", + ". ": "dot", + "- ": "dash", + "--": "longdash", + "- .": "dashdot", + "--.": "longdashdot", + "--..": "longdashdotdot" + }; + stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] : E; + } + newstroke && node.appendChild(stroke); + } + if (res.type == "text") { + res.paper.canvas.style.display = E; + var span = res.paper.span, + m = 100, + fontSize = a.font && a.font.match(/\d+(?:\.\d*)?(?=px)/); + s = span.style; + a.font && (s.font = a.font); + a["font-family"] && (s.fontFamily = a["font-family"]); + a["font-weight"] && (s.fontWeight = a["font-weight"]); + a["font-style"] && (s.fontStyle = a["font-style"]); + fontSize = toFloat(a["font-size"] || fontSize && fontSize[0]) || 10; + s.fontSize = fontSize * m + "px"; + res.textpath.string && (span.innerHTML = Str(res.textpath.string).replace(/")); + var brect = span.getBoundingClientRect(); + res.W = a.w = (brect.right - brect.left) / m; + res.H = a.h = (brect.bottom - brect.top) / m; + // res.paper.canvas.style.display = "none"; + res.X = a.x; + res.Y = a.y + res.H / 2; + + ("x" in params || "y" in params) && (res.path.v = R.format("m{0},{1}l{2},{1}", round(a.x * zoom), round(a.y * zoom), round(a.x * zoom) + 1)); + var dirtyattrs = ["x", "y", "text", "font", "font-family", "font-weight", "font-style", "font-size"]; + for (var d = 0, dd = dirtyattrs.length; d < dd; d++) if (dirtyattrs[d] in params) { + res._.dirty = 1; + break; + } + + // text-anchor emulation + switch (a["text-anchor"]) { + case "start": + res.textpath.style["v-text-align"] = "left"; + res.bbx = res.W / 2; + break; + case "end": + res.textpath.style["v-text-align"] = "right"; + res.bbx = -res.W / 2; + break; + default: + res.textpath.style["v-text-align"] = "center"; + res.bbx = 0; + break; + } + res.textpath.style["v-text-kern"] = true; + } + // res.paper.canvas.style.display = E; + }, + addGradientFill = function (o, gradient, fill) { + o.attrs = o.attrs || {}; + var attrs = o.attrs, + pow = Math.pow, + opacity, + oindex, + type = "linear", + fxfy = ".5 .5"; + o.attrs.gradient = gradient; + gradient = Str(gradient).replace(R._radial_gradient, function (all, fx, fy) { + type = "radial"; + if (fx && fy) { + fx = toFloat(fx); + fy = toFloat(fy); + pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = math.sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5); + fxfy = fx + S + fy; + } + return E; + }); + gradient = gradient.split(/\s*\-\s*/); + if (type == "linear") { + var angle = gradient.shift(); + angle = -toFloat(angle); + if (isNaN(angle)) { + return null; + } + } + var dots = R._parseDots(gradient); + if (!dots) { + return null; + } + o = o.shape || o.node; + if (dots.length) { + o.removeChild(fill); + fill.on = true; + fill.method = "none"; + fill.color = dots[0].color; + fill.color2 = dots[dots.length - 1].color; + var clrs = []; + for (var i = 0, ii = dots.length; i < ii; i++) { + dots[i].offset && clrs.push(dots[i].offset + S + dots[i].color); + } + fill.colors = clrs.length ? clrs.join() : "0% " + fill.color; + if (type == "radial") { + fill.type = "gradientTitle"; + fill.focus = "100%"; + fill.focussize = "0 0"; + fill.focusposition = fxfy; + fill.angle = 0; + } else { + // fill.rotate= true; + fill.type = "gradient"; + fill.angle = (270 - angle) % 360; + } + o.appendChild(fill); + } + return 1; + }, + Element = function (node, vml) { + this[0] = this.node = node; + node.raphael = true; + this.id = R._oid++; + node.raphaelid = this.id; + this.X = 0; + this.Y = 0; + this.attrs = {}; + this.paper = vml; + this.matrix = R.matrix(); + this._ = { + transform: [], + sx: 1, + sy: 1, + dx: 0, + dy: 0, + deg: 0, + dirty: 1, + dirtyT: 1 + }; + !vml.bottom && (vml.bottom = this); + this.prev = vml.top; + vml.top && (vml.top.next = this); + vml.top = this; + this.next = null; + }; + var elproto = R.el; + + Element.prototype = elproto; + elproto.constructor = Element; + elproto.transform = function (tstr) { + if (tstr == null) { + return this._.transform; + } + var vbs = this.paper._viewBoxShift, + vbt = vbs ? "s" + [vbs.scale, vbs.scale] + "-1-1t" + [vbs.dx, vbs.dy] : E, + oldt; + if (vbs) { + oldt = tstr = Str(tstr).replace(/\.{3}|\u2026/g, this._.transform || E); + } + R._extractTransform(this, vbt + tstr); + var matrix = this.matrix.clone(), + skew = this.skew, + o = this.node, + split, + isGrad = ~Str(this.attrs.fill).indexOf("-"), + isPatt = !Str(this.attrs.fill).indexOf("url("); + matrix.translate(-.5, -.5); + if (isPatt || isGrad || this.type == "image") { + skew.matrix = "1 0 0 1"; + skew.offset = "0 0"; + split = matrix.split(); + if ((isGrad && split.noRotation) || !split.isSimple) { + o.style.filter = matrix.toFilter(); + var bb = this.getBBox(), + bbt = this.getBBox(1), + dx = bb.x - bbt.x, + dy = bb.y - bbt.y; + o.coordorigin = (dx * -zoom) + S + (dy * -zoom); + setCoords(this, 1, 1, dx, dy, 0); + } else { + o.style.filter = E; + setCoords(this, split.scalex, split.scaley, split.dx, split.dy, split.rotate); + } + } else { + o.style.filter = E; + skew.matrix = Str(matrix); + skew.offset = matrix.offset(); + } + oldt && (this._.transform = oldt); + return this; + }; + elproto.rotate = function (deg, cx, cy) { + if (this.removed) { + return this; + } + if (deg == null) { + return; + } + deg = Str(deg).split(separator); + if (deg.length - 1) { + cx = toFloat(deg[1]); + cy = toFloat(deg[2]); + } + deg = toFloat(deg[0]); + (cy == null) && (cx = cy); + if (cx == null || cy == null) { + var bbox = this.getBBox(1); + cx = bbox.x + bbox.width / 2; + cy = bbox.y + bbox.height / 2; + } + this._.dirtyT = 1; + this.transform(this._.transform.concat([["r", deg, cx, cy]])); + return this; + }; + elproto.translate = function (dx, dy) { + if (this.removed) { + return this; + } + dx = Str(dx).split(separator); + if (dx.length - 1) { + dy = toFloat(dx[1]); + } + dx = toFloat(dx[0]) || 0; + dy = +dy || 0; + if (this._.bbox) { + this._.bbox.x += dx; + this._.bbox.y += dy; + } + this.transform(this._.transform.concat([["t", dx, dy]])); + return this; + }; + elproto.scale = function (sx, sy, cx, cy) { + if (this.removed) { + return this; + } + sx = Str(sx).split(separator); + if (sx.length - 1) { + sy = toFloat(sx[1]); + cx = toFloat(sx[2]); + cy = toFloat(sx[3]); + isNaN(cx) && (cx = null); + isNaN(cy) && (cy = null); + } + sx = toFloat(sx[0]); + (sy == null) && (sy = sx); + (cy == null) && (cx = cy); + if (cx == null || cy == null) { + var bbox = this.getBBox(1); + } + cx = cx == null ? bbox.x + bbox.width / 2 : cx; + cy = cy == null ? bbox.y + bbox.height / 2 : cy; + + this.transform(this._.transform.concat([["s", sx, sy, cx, cy]])); + this._.dirtyT = 1; + return this; + }; + elproto.hide = function () { + !this.removed && (this.node.style.display = "none"); + return this; + }; + elproto.show = function () { + !this.removed && (this.node.style.display = E); + return this; + }; + elproto._getBBox = function () { + if (this.removed) { + return {}; + } + return { + x: this.X + (this.bbx || 0) - this.W / 2, + y: this.Y - this.H, + width: this.W, + height: this.H + }; + }; + elproto.remove = function () { + if (this.removed) { + return; + } + this.paper.__set__ && this.paper.__set__.exclude(this); + R.eve.unbind("*.*." + this.id); + R._tear(this, this.paper); + this.node.parentNode.removeChild(this.node); + this.shape && this.shape.parentNode.removeChild(this.shape); + for (var i in this) { + this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; + } + this.removed = true; + }; + elproto.attr = function (name, value) { + if (this.removed) { + return this; + } + if (name == null) { + var res = {}; + for (var a in this.attrs) if (this.attrs[has](a)) { + res[a] = this.attrs[a]; + } + res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient; + res.transform = this._.transform; + return res; + } + if (value == null && R.is(name, "string")) { + if (name == fillString && this.attrs.fill == "none" && this.attrs.gradient) { + return this.attrs.gradient; + } + var names = name.split(separator), + out = {}; + for (var i = 0, ii = names.length; i < ii; i++) { + name = names[i]; + if (name in this.attrs) { + out[name] = this.attrs[name]; + } else if (R.is(this.paper.customAttributes[name], "function")) { + out[name] = this.paper.customAttributes[name].def; + } else { + out[name] = R._availableAttrs[name]; + } + } + return ii - 1 ? out : out[names[0]]; + } + if (this.attrs && value == null && R.is(name, "array")) { + out = {}; + for (i = 0, ii = name.length; i < ii; i++) { + out[name[i]] = this.attr(name[i]); + } + return out; + } + var params; + if (value != null) { + params = {}; + params[name] = value; + } + value == null && R.is(name, "object") && (params = name); + for (var key in params) { + eve("attr." + key + "." + this.id, this, params[key]); + } + if (params) { + for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) { + var par = this.paper.customAttributes[key].apply(this, [].concat(params[key])); + this.attrs[key] = params[key]; + for (var subkey in par) if (par[has](subkey)) { + params[subkey] = par[subkey]; + } + } + // this.paper.canvas.style.display = "none"; + if (params.text && this.type == "text") { + this.textpath.string = params.text; + } + setFillAndStroke(this, params); + // this.paper.canvas.style.display = E; + } + return this; + }; + elproto.toFront = function () { + !this.removed && this.node.parentNode.appendChild(this.node); + this.paper && this.paper.top != this && R._tofront(this, this.paper); + return this; + }; + elproto.toBack = function () { + if (this.removed) { + return this; + } + if (this.node.parentNode.firstChild != this.node) { + this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild); + R._toback(this, this.paper); + } + return this; + }; + elproto.insertAfter = function (element) { + if (this.removed) { + return this; + } + if (element.constructor == R.st.constructor) { + element = element[element.length - 1]; + } + if (element.node.nextSibling) { + element.node.parentNode.insertBefore(this.node, element.node.nextSibling); + } else { + element.node.parentNode.appendChild(this.node); + } + R._insertafter(this, element, this.paper); + return this; + }; + elproto.insertBefore = function (element) { + if (this.removed) { + return this; + } + if (element.constructor == R.st.constructor) { + element = element[0]; + } + element.node.parentNode.insertBefore(this.node, element.node); + R._insertbefore(this, element, this.paper); + return this; + }; + elproto.blur = function (size) { + var s = this.node.runtimeStyle, + f = s.filter; + f = f.replace(blurregexp, E); + if (+size !== 0) { + this.attrs.blur = size; + s.filter = f + S + ms + ".Blur(pixelradius=" + (+size || 1.5) + ")"; + s.margin = R.format("-{0}px 0 0 -{0}px", round(+size || 1.5)); + } else { + s.filter = f; + s.margin = 0; + delete this.attrs.blur; + } + }; + + R._engine.path = function (pathString, vml) { + var el = createNode("shape"); + el.style.cssText = cssDot; + el.coordsize = zoom + S + zoom; + el.coordorigin = vml.coordorigin; + var p = new Element(el, vml), + attr = {fill: "none", stroke: "#000"}; + pathString && (attr.path = pathString); + p.type = "path"; + p.path = []; + p.Path = E; + setFillAndStroke(p, attr); + vml.canvas.appendChild(el); + var skew = createNode("skew"); + skew.on = true; + el.appendChild(skew); + p.skew = skew; + p.transform(E); + return p; + }; + R._engine.rect = function (vml, x, y, w, h, r) { + var path = R._rectPath(x, y, w, h, r), + res = vml.path(path), + a = res.attrs; + res.X = a.x = x; + res.Y = a.y = y; + res.W = a.width = w; + res.H = a.height = h; + a.r = r; + a.path = path; + res.type = "rect"; + return res; + }; + R._engine.ellipse = function (vml, x, y, rx, ry) { + var res = vml.path(), + a = res.attrs; + res.X = x - rx; + res.Y = y - ry; + res.W = rx * 2; + res.H = ry * 2; + res.type = "ellipse"; + setFillAndStroke(res, { + cx: x, + cy: y, + rx: rx, + ry: ry + }); + return res; + }; + R._engine.circle = function (vml, x, y, r) { + var res = vml.path(), + a = res.attrs; + res.X = x - r; + res.Y = y - r; + res.W = res.H = r * 2; + res.type = "circle"; + setFillAndStroke(res, { + cx: x, + cy: y, + r: r + }); + return res; + }; + R._engine.image = function (vml, src, x, y, w, h) { + var path = R._rectPath(x, y, w, h), + res = vml.path(path).attr({stroke: "none"}), + a = res.attrs, + node = res.node, + fill = node.getElementsByTagName(fillString)[0]; + a.src = src; + res.X = a.x = x; + res.Y = a.y = y; + res.W = a.width = w; + res.H = a.height = h; + a.path = path; + res.type = "image"; + fill.parentNode == node && node.removeChild(fill); + fill.rotate = true; + fill.src = src; + fill.type = "tile"; + res._.fillpos = [x, y]; + res._.fillsize = [w, h]; + node.appendChild(fill); + setCoords(res, 1, 1, 0, 0, 0); + return res; + }; + R._engine.text = function (vml, x, y, text) { + var el = createNode("shape"), + path = createNode("path"), + o = createNode("textpath"); + x = x || 0; + y = y || 0; + text = text || ""; + path.v = R.format("m{0},{1}l{2},{1}", round(x * zoom), round(y * zoom), round(x * zoom) + 1); + path.textpathok = true; + o.string = Str(text); + o.on = true; + el.style.cssText = cssDot; + el.coordsize = zoom + S + zoom; + el.coordorigin = "0 0"; + var p = new Element(el, vml), + attr = { + fill: "#000", + stroke: "none", + font: R._availableAttrs.font, + text: text + }; + p.shape = el; + p.path = path; + p.textpath = o; + p.type = "text"; + p.attrs.text = Str(text); + p.attrs.x = x; + p.attrs.y = y; + p.attrs.w = 1; + p.attrs.h = 1; + setFillAndStroke(p, attr); + el.appendChild(o); + el.appendChild(path); + vml.canvas.appendChild(el); + var skew = createNode("skew"); + skew.on = true; + el.appendChild(skew); + p.skew = skew; + p.transform(E); + return p; + }; + R._engine.setSize = function (width, height) { + var cs = this.canvas.style; + this.width = width; + this.height = height; + width == +width && (width += "px"); + height == +height && (height += "px"); + cs.width = width; + cs.height = height; + cs.clip = "rect(0 " + width + " " + height + " 0)"; + if (this._viewBox) { + R._engine.setViewBox.apply(this, this._viewBox); + } + return this; + }; + R._engine.setViewBox = function (x, y, w, h, fit) { + R.eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]); + var width = this.width, + height = this.height, + size = 1 / mmax(w / width, h / height), + H, W; + if (fit) { + H = height / h; + W = width / w; + if (w * H < width) { + x -= (width - w * H) / 2 / H; + } + if (h * W < height) { + y -= (height - h * W) / 2 / W; + } + } + this._viewBox = [x, y, w, h, !!fit]; + this._viewBoxShift = { + dx: -x, + dy: -y, + scale: size + }; + this.forEach(function (el) { + el.transform("..."); + }); + return this; + }; + var createNode; + R._engine.initWin = function (win) { + var doc = win.document; + doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)"); + try { + !doc.namespaces.rvml && doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml"); + createNode = function (tagName) { + return doc.createElement(''); + }; + } catch (e) { + createNode = function (tagName) { + return doc.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">'); + }; + } + }; + R._engine.initWin(R._g.win); + R._engine.create = function () { + var con = R._getContainer.apply(0, arguments), + container = con.container, + height = con.height, + s, + width = con.width, + x = con.x, + y = con.y; + if (!container) { + throw new Error("VML container not found."); + } + var res = new R._Paper, + c = res.canvas = R._g.doc.createElement("div"), + cs = c.style; + x = x || 0; + y = y || 0; + width = width || 512; + height = height || 342; + res.width = width; + res.height = height; + width == +width && (width += "px"); + height == +height && (height += "px"); + res.coordsize = zoom * 1e3 + S + zoom * 1e3; + res.coordorigin = "0 0"; + res.span = R._g.doc.createElement("span"); + res.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;"; + c.appendChild(res.span); + cs.cssText = R.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden", width, height); + if (container == 1) { + R._g.doc.body.appendChild(c); + cs.left = x + "px"; + cs.top = y + "px"; + cs.position = "absolute"; + } else { + if (container.firstChild) { + container.insertBefore(c, container.firstChild); + } else { + container.appendChild(c); + } + } + // plugins.call(res, res, R.fn); + res.renderfix = function () {}; + return res; + }; + R.prototype.clear = function () { + R.eve("clear", this); + this.canvas.innerHTML = E; + this.span = R._g.doc.createElement("span"); + this.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;"; + this.canvas.appendChild(this.span); + this.bottom = this.top = null; + }; + R.prototype.remove = function () { + R.eve("remove", this); + this.canvas.parentNode.removeChild(this.canvas); + for (var i in this) { + this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; + } + return true; + }; + + var setproto = R.st; + for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) { + setproto[method] = (function (methodname) { + return function () { + var arg = arguments; + return this.forEach(function (el) { + el[methodname].apply(el, arg); + }); + }; + })(method); + } +}(window.Raphael); diff --git a/addons/web_diagram/static/src/css/base_diagram.css b/addons/web_diagram/static/src/css/base_diagram.css index 6be8d4873d2..8d0a418f52e 100644 --- a/addons/web_diagram/static/src/css/base_diagram.css +++ b/addons/web_diagram/static/src/css/base_diagram.css @@ -1,35 +1,53 @@ +.openerp .oe_diagram_header h3.oe_diagram_title { + font-weight: normal; + color: #252424; + margin: 0 0 0 2px; +} + .openerp .oe_diagram_pager { - text-align: right; + float:right; + /*text-align: right;*/ white-space: nowrap; } .openerp .oe_diagram_buttons { float: left; } - -/*.openerp .dhx_canvas_text { - padding:30px 0 0 10px; - -webkit-transform: rotate(60deg); - -moz-transform: rotate(60deg); - -o-transform: rotate(60deg); - -ms-transform: rotate(60deg); - transform: rotate(60deg); +.openerp .clear{ + clear:both; +} +/* We use a resizable diagram-container. The problem with a + * resizable diagram is that the diagram catches the mouse events + * and the diagram is then impossible to resize. That's why the + * diagram has a height of 98.5%, so that the bottom part of the + * diagram can be used for resize + */ +.openerp .diagram-container{ + margin:0; + padding:0; + width:100%; + height:500px; + resize:vertical; + background-color:#FFF; + border:1px solid #DCDCDC; + overflow:hidden; +} +.openerp .oe_diagram_diagram{ + margin:0; + padding:0; + background-color:#FFF; + width:100%; + height:98.5%; } -.openerp .dhx_canvas_text.dhx_axis_item_y, .openerp .dhx_canvas_text.dhx_axis_title_x { - padding: 0px; - -webkit-transform: rotate(0deg); - -moz-transform: rotate(0deg); - -o-transform: rotate(0deg); - -ms-transform: rotate(0deg); - transform: rotate(0deg); -} +/* prevent accidental selection of the text in the svg nodes */ +.openerp .oe_diagram_diagram *{ + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; +}; -.openerp .dhx_canvas_text.dhx_axis_title_y { - padding: 0; - -webkit-transform: rotate(270deg); - -moz-transform: rotate(270deg); - -o-transform: rotate(270deg); - -ms-transform: rotate(270deg); - transform: rotate(270deg); -} */ diff --git a/addons/web_diagram/static/src/img/grid.jpg b/addons/web_diagram/static/src/img/grid.jpg deleted file mode 100644 index 5254207b964..00000000000 Binary files a/addons/web_diagram/static/src/img/grid.jpg and /dev/null differ diff --git a/addons/web_diagram/static/src/js/diagram.js b/addons/web_diagram/static/src/js/diagram.js index 90f8000bc0f..41b3c4844db 100644 --- a/addons/web_diagram/static/src/js/diagram.js +++ b/addons/web_diagram/static/src/js/diagram.js @@ -55,7 +55,7 @@ openerp.web.DiagramView = openerp.web.View.extend({ this.do_update_pager(); // New Node,Edge - this.$element.find('#new_node.oe_diagram_button_new').click(function(){self.add_edit_node(null, self.node);}); + this.$element.find('#new_node.oe_diagram_button_new').click(function(){self.add_node();}); if(this.id) { self.get_diagram_info(); @@ -111,175 +111,233 @@ openerp.web.DiagramView = openerp.web.View.extend({ this.get_diagram_info(); } }, - select_node: function (node, element) { - if (!this.selected_node) { - this.selected_node = node; - element.attr('stroke', 'red'); - return; - } - // Re-click selected node, deselect it - if (node.id === this.selected_node.id) { - this.selected_node = null; - element.attr('stroke', 'black'); - return; - } - this.add_edit_node(null, this.connector, { - act_from: this.selected_node.id, - act_to: node.id - }); - }, + + // Set-up the drawing elements of the diagram draw_diagram: function(result) { - this.selected_node = null; - var diagram = new Graph(); - - this.active_model = result['id_model']; - - var res_nodes = result['nodes']; - var res_connectors = result['conn']; - this.parent_field = result.parent_field; - - //Custom logic var self = this; - var renderer = function(r, n) { - var shape = (n.node.shape === 'rectangle') ? 'rect' : 'ellipse'; + var res_nodes = result['nodes']; + var res_edges = result['conn']; + this.parent_field = result.parent_field; + this.$element.find('h3.oe_diagram_title').text(result.name); - var node = r[shape](n.node.x, n.node.y).attr({ - "fill": n.node.color - }); + var id_to_node = {}; - var nodes = r.set(node, r.text(n.node.x, n.node.y, (n.label || n.id))) - .attr("cursor", "pointer") - .dblclick(function() { - self.add_edit_node(n.node.id, self.node); - }) - .mousedown(function () { node.moved = false; }) - .mousemove(function () { node.moved = true; }) - .click(function () { - // Ignore click from move event - if (node.moved) { return; } - self.select_node(n.node, node); - }); - if (shape === 'rect') { - node.attr({width: "60", height: "44"}); - node.next.attr({"text-anchor": "middle", x: n.node.x + 20, y: n.node.y + 20}); - } else { - node.attr({rx: "40", ry: "20"}); - } + var style = { + edge_color: "#A0A0A0", + edge_label_color: "#555", + edge_label_font_size: 10, + edge_width: 2, + edge_spacing: 100, + edge_loop_radius: 100, - return nodes; + node_label_color: "#333", + node_label_font_size: 12, + node_outline_color: "#333", + node_outline_width: 1, + node_selected_color: "#0097BE", + node_selected_width: 2, + node_size_x: 110, + node_size_y: 80, + connector_active_color: "#FFF", + connector_radius: 4, + + close_button_radius: 8, + close_button_color: "#333", + close_button_x_color: "#FFF", + + gray: "#DCDCDC", + white: "#FFF", + + viewport_margin: 50 }; - _.each(res_nodes, function(res_node) { - diagram.addNode(res_node['name'],{node: res_node,render: renderer}); + // remove previous diagram + var canvas = self.$element.find('div.oe_diagram_diagram') + .empty().get(0); + + var r = new Raphael(canvas, '100%','100%'); + + var graph = new CuteGraph(r,style,canvas.parentNode); + + var confirm_dialog = $('#dialog').dialog({ + autoOpen: false, + title: _t("Are you sure?") }); + + + _.each(res_nodes, function(node) { + var n = new CuteNode( + graph, + node.x + 50, //FIXME the +50 should be in the layout algorithm + node.y + 50, + CuteGraph.wordwrap(node.name, 14), + node.shape === 'rectangle' ? 'rect' : 'circle', + node.color === 'white' ? style.white : style.gray); + + n.id = node.id; + id_to_node[node.id] = n; }); - // Id for Path(Edges) - var edge_ids = []; - - _.each(res_connectors, function(connector, index) { - edge_ids.push(index); - diagram.addEdge(connector['source'], connector['destination'], {directed : true, label: connector['signal']}); + _.each(res_edges, function(edge) { + var e = new CuteEdge( + graph, + CuteGraph.wordwrap(edge.signal, 32), + id_to_node[edge.s_id], + id_to_node[edge.d_id] || id_to_node[edge.s_id] ); //WORKAROUND + e.id = edge.id; }); - self.$element.find('.diagram').empty(); - - var layouter = new Graph.Layout.Ordered(diagram); - var render_diagram = new Graph.Renderer.Raphael('dia-canvas', diagram, $('div#dia-canvas').width(), $('div#dia-canvas').height()); - - _.each(diagram.edges, function(edge, index) { - if(edge.connection) { - edge.connection.fg.attr({cursor: "pointer"}).dblclick(function() { - self.add_edit_node(edge_ids[index], self.connector); - }); + CuteNode.double_click_callback = function(cutenode){ + self.edit_node(cutenode.id); + }; + var i = 0; + CuteNode.destruction_callback = function(cutenode){ + if(!confirm(_t("Deleting this node cannot be undone.\nIt will also delete all connected transitions.\n\nAre you sure ?"))){ + return $.Deferred().reject().promise(); } - }); + return new openerp.web.DataSet(self,self.node).unlink([cutenode.id]); + }; + CuteEdge.double_click_callback = function(cuteedge){ + self.edit_connector(cuteedge.id); + }; + + CuteEdge.creation_callback = function(node_start, node_end){ + return {label:_t("")}; + }; + CuteEdge.new_edge_callback = function(cuteedge){ + self.add_connector(cuteedge.get_start().id, + cuteedge.get_end().id, + cuteedge); + }; + CuteEdge.destruction_callback = function(cuteedge){ + if(!confirm(_t("Deleting this transition cannot be undone.\n\nAre you sure ?"))){ + return $.Deferred().reject().promise(); + } + return new openerp.web.DataSet(self,self.connector).unlink([cuteedge.id]); + }; + }, - add_edit_node: function(id, model, defaults) { - defaults = defaults || {}; + // Creates a popup to edit the content of the node with id node_id + edit_node: function(node_id){ var self = this; + var title = _t('Activity'); + var pop = new openerp.web.form.FormOpenPopup(self); - if(!model) - model = self.node; - if(id) - id = parseInt(id, 10); - - var pop, - title = model == self.node ? _t('Activity') : _t('Transition'); - if(!id) { - pop = new openerp.web.form.SelectCreatePopup(this); - pop.select_element( - model, - { - title: _t("Create:") + title, - initial_view: 'form', - disable_multiple_selection: true - }, - this.dataset.domain, - this.context || this.dataset.context - ); - pop.on_select_elements.add_last(function(element_ids) { - self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_diagram_loaded); - }); - } else { - pop = new openerp.web.form.FormOpenPopup(this); - pop.show_element( - model, - id, - this.context || this.dataset.context, + pop.show_element( + self.node, + node_id, + self.context || self.dataset.context, { title: _t("Open: ") + title } ); - pop.on_write.add(function() { - self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_diagram_loaded); + + pop.on_write.add(function() { + self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_diagram_loaded); }); - } + + var form_fields = [self.parent_field]; + var form_controller = pop.view_form; + + form_controller.on_record_loaded.add_first(function() { + _.each(form_fields, function(fld) { + if (!(fld in form_controller.fields)) { return; } + var field = form_controller.fields[fld]; + field.$input.prop('disabled', true); + field.$drop_down.unbind(); + field.$menu_btn.unbind(); + }); + }); + }, + + // Creates a popup to add a node to the diagram + add_node: function(){ + var self = this; + var title = _t('Activity'); + var pop = new openerp.web.form.SelectCreatePopup(self); + pop.select_element( + self.node, + { + title: _t("Create:") + title, + initial_view: 'form', + disable_multiple_selection: true + }, + self.dataset.domain, + self.context || self.dataset.context + ); + pop.on_select_elements.add_last(function(element_ids) { + self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_diagram_loaded); + }); + + var form_controller = pop.view_form; + var form_fields = [this.parent_field]; + + form_controller.on_record_loaded.add_last(function() { + _.each(form_fields, function(fld) { + if (!(fld in form_controller.fields)) { return; } + var field = form_controller.fields[fld]; + field.set_value(self.id); + field.dirty = true; + }); + }); + }, + + // Creates a popup to edit the connector of id connector_id + edit_connector: function(connector_id){ + var self = this; + var title = _t('Transition'); + var pop = new openerp.web.form.FormOpenPopup(self); + pop.show_element( + self.connector, + parseInt(connector_id,10), //FIXME Isn't connector_id supposed to be an int ? + self.context || self.dataset.context, + { + title: _t("Open: ") + title + } + ); + pop.on_write.add(function() { + self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_diagram_loaded); + }); + }, + + // Creates a popup to add a connector from node_source_id to node_dest_id. + // dummy_cuteedge if not null, will be removed form the graph after the popup is closed. + add_connector: function(node_source_id, node_dest_id, dummy_cuteedge){ + var self = this; + var title = _t('Transition'); + var pop = new openerp.web.form.SelectCreatePopup(self); + + pop.select_element( + self.connector, + { + title: _t("Create:") + title, + initial_view: 'form', + disable_multiple_selection: true + }, + this.dataset.domain, + this.context || this.dataset.context + ); + + pop.on_select_elements.add_last(function(element_ids) { + self.dataset.read_index(_.keys(self.fields_view.fields)).pipe(self.on_diagram_loaded); + }); + // We want to destroy the dummy edge after a creation cancel. This destroys it even if we save the changes. + // This is not a problem since the diagram is completely redrawn on saved changes. + pop.$element.bind("dialogbeforeclose",function(){ + if(dummy_cuteedge){ + dummy_cuteedge.remove(); + } + }); var form_controller = pop.view_form; - var form_fields; - - if (model === self.node) { - form_fields = [this.parent_field]; - if (!id) { - form_controller.on_record_loaded.add_last(function() { - _.each(form_fields, function(fld) { - if (!(fld in form_controller.fields)) { return; } - var field = form_controller.fields[fld]; - field.set_value([self.id,self.active_model]); - field.dirty = true; - }); - }); - } else { - form_controller.on_record_loaded.add_first(function() { - _.each(form_fields, function(fld) { - if (!(fld in form_controller.fields)) { return; } - var field = form_controller.fields[fld]; - field.$input.prop('disabled', true); - field.$drop_down.unbind(); - field.$menu_btn.unbind(); - }); - }); - } - } else { - form_fields = [ - this.connectors.attrs.source, - this.connectors.attrs.destination]; - } - - if (!_.isEmpty(defaults)) { - form_controller.on_record_loaded.add_last(function () { - _(form_fields).each(function (field) { - if (!defaults[field]) { return; } - form_controller.fields[field].set_value(defaults[field]); - form_controller.fields[field].dirty = true; - }); - }); - } - - + form_controller.on_record_loaded.add_last(function () { + form_controller.fields[self.connectors.attrs.source].set_value(node_source_id); + form_controller.fields[self.connectors.attrs.source].dirty = true; + form_controller.fields[self.connectors.attrs.destination].set_value(node_dest_id); + form_controller.fields[self.connectors.attrs.destination].dirty = true; + }); }, on_pager_action: function(action) { @@ -297,8 +355,10 @@ openerp.web.DiagramView = openerp.web.View.extend({ this.dataset.index = this.dataset.ids.length - 1; break; } - this.dataset.read_index(_.keys(this.fields_view.fields)).pipe(this.on_diagram_loaded); + var loaded = this.dataset.read_index(_.keys(this.fields_view.fields)) + .pipe(this.on_diagram_loaded); this.do_update_pager(); + return loaded; }, do_update_pager: function(hide_index) { @@ -313,7 +373,7 @@ openerp.web.DiagramView = openerp.web.View.extend({ do_show: function() { this.do_push_state({}); - return this._super(); + return $.when(this._super(), this.on_pager_action('reload')); } }); }; diff --git a/addons/web_diagram/static/src/js/graph.js b/addons/web_diagram/static/src/js/graph.js new file mode 100644 index 00000000000..b61b2bf7a6b --- /dev/null +++ b/addons/web_diagram/static/src/js/graph.js @@ -0,0 +1,996 @@ + +(function(window){ + + // this serves as the end of an edge when creating a link + function EdgeEnd(pos_x,pos_y){ + this.x = pos_x; + this.y = pos_y; + + this.get_pos = function(){ + return new Vec2(this.x,this.y); + } + } + + // A close button, + // if entity_type == "node": + // GraphNode.destruction_callback(entity) is called where entity is a node. + // If it returns true the node and all connected edges are destroyed. + // if entity_type == "edge": + // GraphEdge.destruction_callback(entity) is called where entity is an edge + // If it returns true the edge is destroyed + // pos_x,pos_y is the relative position of the close button to the entity position (entity.get_pos()) + + function CloseButton(graph, entity, entity_type, pos_x,pos_y){ + var self = this; + var visible = false; + var close_button_radius = graph.style.close_button_radius || 8; + var close_circle = graph.r.circle( entity.get_pos().x + pos_x, + entity.get_pos().y + pos_y, + close_button_radius ); + //the outer gray circle + close_circle.attr({ 'opacity': 0, + 'fill': graph.style.close_button_color || "black", + 'cursor': 'pointer', + 'stroke': 'none' }); + close_circle.transform(graph.get_transform()); + graph.set_scrolling(close_circle); + + //the 'x' inside the circle + var close_label = graph.r.text( entity.get_pos().x + pos_x, entity.get_pos().y + pos_y,"x"); + close_label.attr({ 'fill': graph.style.close_button_x_color || "white", + 'font-size': close_button_radius, + 'cursor': 'pointer' }); + + close_label.transform(graph.get_transform()); + graph.set_scrolling(close_label); + + // the dummy_circle is used to catch events, and avoid hover in/out madness + // between the 'x' and the button + var dummy_circle = graph.r.circle( entity.get_pos().x + pos_x, + entity.get_pos().y + pos_y, + close_button_radius ); + dummy_circle.attr({'opacity':1, 'fill': 'transparent', 'stroke':'none', 'cursor':'pointer'}); + dummy_circle.transform(graph.get_transform()); + graph.set_scrolling(dummy_circle); + + this.get_pos = function(){ + return entity.get_pos().add_xy(pos_x,pos_y); + }; + + this.update_pos = function(){ + var pos = self.get_pos(); + close_circle.attr({'cx':pos.x, 'cy':pos.y}); + dummy_circle.attr({'cx':pos.x, 'cy':pos.y}); + close_label.attr({'x':pos.x, 'y':pos.y}); + }; + + function hover_in(){ + if(!visible){ return; } + close_circle.animate({'r': close_button_radius * 1.5}, 300, 'elastic'); + dummy_circle.animate({'r': close_button_radius * 1.5}, 300, 'elastic'); + } + function hover_out(){ + if(!visible){ return; } + close_circle.animate({'r': close_button_radius},400,'linear'); + dummy_circle.animate({'r': close_button_radius},400,'linear'); + } + dummy_circle.hover(hover_in,hover_out); + + function click_action(){ + if(!visible){ return; } + + close_circle.attr({'r': close_button_radius * 2 }); + dummy_circle.attr({'r': close_button_radius * 2 }); + close_circle.animate({'r': close_button_radius }, 400, 'linear'); + dummy_circle.animate({'r': close_button_radius }, 400, 'linear'); + + if(entity_type == "node"){ + $.when(GraphNode.destruction_callback(entity)).then(function () { + //console.log("remove node",entity); + entity.remove(); + }); + }else if(entity_type == "edge"){ + $.when(GraphEdge.destruction_callback(entity)).then(function () { + //console.log("remove edge",entity); + entity.remove(); + }); + } + } + dummy_circle.click(click_action); + + this.show = function(){ + if(!visible){ + close_circle.animate({'opacity':1}, 100, 'linear'); + close_label.animate({'opacity':1}, 100, 'linear'); + visible = true; + } + } + this.hide = function(){ + if(visible){ + close_circle.animate({'opacity':0}, 100, 'linear'); + close_label.animate({'opacity':0}, 100, 'linear'); + visible = false; + } + } + //destroy this object and remove it from the graph + this.remove = function(){ + if(visible){ + visible = false; + close_circle.animate({'opacity':0}, 100, 'linear'); + close_label.animate({'opacity':0}, 100, 'linear',self.remove); + }else{ + close_circle.remove(); + close_label.remove(); + dummy_circle.remove(); + } + } + } + + // connectors are start and end point of edge creation drags. + function Connector(graph,node,pos_x,pos_y){ + var visible = false; + var conn_circle = graph.r.circle(node.get_pos().x + pos_x, node.get_pos().y + pos_y,4); + conn_circle.attr({ 'opacity': 0, + 'fill': graph.style.node_outline_color, + 'stroke': 'none' }); + conn_circle.transform(graph.get_transform()); + graph.set_scrolling(conn_circle); + + var self = this; + + this.update_pos = function(){ + conn_circle.attr({'cx':node.get_pos().x + pos_x, 'cy':node.get_pos().y + pos_y}); + }; + this.get_pos = function(){ + return new node.get_pos().add_xy(pos_x,pos_y); + }; + this.remove = function(){ + conn_circle.remove(); + } + function hover_in(){ + if(!visible){ return;} + conn_circle.animate({'r':8},300,'elastic'); + if(graph.creating_edge){ + graph.target_node = node; + conn_circle.animate({ 'fill': graph.style.connector_active_color, + 'stroke': graph.style.node_outline_color, + 'stroke-width': graph.style.node_selected_width, + },100,'linear'); + } + } + function hover_out(){ + if(!visible){ return;} + conn_circle.animate({ 'r':graph.style.connector_radius, + 'fill':graph.style.node_outline_color, + 'stroke':'none'},400,'linear'); + graph.target_node = null; + } + conn_circle.hover(hover_in,hover_out); + + + var drag_down = function(){ + if(!visible){ return; } + self.ox = conn_circle.attr("cx"); + self.oy = conn_circle.attr("cy"); + self.edge_start = new EdgeEnd(self.ox,self.oy); + self.edge_end = new EdgeEnd(self.ox, self.oy); + self.edge_tmp = new GraphEdge(graph,'',self.edge_start,self.edge_end,true); + graph.creating_edge = true; + }; + var drag_move = function(dx,dy){ + if(!visible){ return; } + self.edge_end.x = self.ox + dx; + self.edge_end.y = self.oy + dy; + self.edge_tmp.update(); + }; + var drag_up = function(){ + if(!visible){ return; } + graph.creating_edge = false; + self.edge_tmp.remove(); + if(graph.target_node){ + var edge_prop = GraphEdge.creation_callback(node,graph.target_node); + if(edge_prop){ + var new_edge = new GraphEdge(graph,edge_prop.label, node,graph.target_node); + GraphEdge.new_edge_callback(new_edge); + } + } + }; + conn_circle.drag(drag_move,drag_down,drag_up); + + function show(){ + if(!visible){ + conn_circle.animate({'opacity':1}, 100, 'linear'); + visible = true; + } + } + function hide(){ + if(visible){ + conn_circle.animate({'opacity':0}, 100, 'linear'); + visible = false; + } + } + this.show = show; + this.hide = hide; + } + + //Creates a new graph on raphael document r. + //style is a dictionary containing the style definitions + //viewport (optional) is the dom element representing the viewport of the graph. It is used + //to prevent scrolling to scroll the graph outside the viewport. + + function Graph(r,style,viewport){ + var self = this; + var nodes = []; // list of all nodes in the graph + var edges = []; // list of all edges in the graph + var graph = {}; // graph[n1.uid][n2.uid] -> list of all edges from n1 to n2 + var links = {}; // links[n.uid] -> list of all edges from or to n + var uid = 1; // all nodes and edges have an uid used to order their display when they are curved + var selected_entity = null; //the selected entity (node or edge) + + self.creating_edge = false; // true if we are dragging a new edge onto a node + self.target_node = null; // this holds the target node when creating an edge and hovering a connector + self.r = r; // the raphael instance + self.style = style; // definition of the colors, spacing, fonts, ... used by the elements + var tr_x = 0, tr_y = 0; // global translation coordinate + + var background = r.rect(0,0,'100%','100%').attr({'fill':'white', 'stroke':'none', 'opacity':0, 'cursor':'move'}); + + // return the global transform of the scene + this.get_transform = function(){ + return "T"+tr_x+","+tr_y + }; + + + // translate every element of the graph except the background. + // elements inserted in the graph after a translate_all() must manually apply transformation + // via get_transform() + var translate_all = function(dx,dy){ + tr_x += dx; + tr_y += dy; + var tstr = self.get_transform(); + + r.forEach(function(el){ + if(el != background){ + el.transform(tstr); + } + }); + }; + //returns {minx, miny, maxx, maxy}, the translated bounds containing all nodes + var get_bounds = function(){ + var minx = Number.MAX_VALUE; + var miny = Number.MAX_VALUE; + var maxx = Number.MIN_VALUE; + var maxy = Number.MIN_VALUE; + + for(var i = 0; i < nodes.length; i++){ + var pos = nodes[i].get_pos(); + minx = Math.min(minx,pos.x); + miny = Math.min(miny,pos.y); + maxx = Math.max(maxx,pos.x); + maxy = Math.max(maxy,pos.y); + } + + minx = minx - style.node_size_x / 2 + tr_x; + miny = miny - style.node_size_y / 2 + tr_y; + maxx = maxx + style.node_size_x / 2 + tr_x; + maxy = maxy + style.node_size_y / 2 + tr_y; + + return { minx:minx, miny:miny, maxx:maxx, maxy:maxy }; + + }; + // returns false if the translation dx,dy of the viewport + // hides the graph (with optional margin) + var translation_respects_viewport = function(dx,dy,margin){ + if(!viewport){ + return true; + } + margin = margin || 0; + var b = get_bounds(); + var width = viewport.offsetWidth; + var height = viewport.offsetHeight; + + if( ( dy < 0 && b.maxy + dy < margin ) || + ( dy > 0 && b.miny + dy > height - margin ) || + ( dx < 0 && b.maxx + dx < margin ) || + ( dx > 0 && b.minx + dx > width - margin ) ){ + return false; + } + + return true; + } + //Adds a mousewheel event callback to raph_element that scrolls the viewport + this.set_scrolling = function(raph_element){ + $(raph_element.node).bind('mousewheel',function(event,delta){ + var dy = delta * 20; + if( translation_respects_viewport(0,dy, style.viewport_margin) ){ + translate_all(0,dy); + } + }); + }; + + var px, py; + // Graph translation when background is dragged + var bg_drag_down = function(){ + px = py = 0; + }; + var bg_drag_move = function(x,y){ + var dx = x - px; + var dy = y - py; + px = x; + py = y; + if( translation_respects_viewport(dx,dy, style.viewport_margin) ){ + translate_all(dx,dy); + } + }; + var bg_drag_up = function(){}; + background.drag( bg_drag_move, bg_drag_down, bg_drag_up); + + this.set_scrolling(background); + + //adds a node to the graph and sets its uid. + this.add_node = function (n){ + nodes.push(n); + n.uid = uid++; + }; + + //return the list of all nodes in the graph + this.get_node_list = function(){ + return nodes; + }; + + //adds an edge to the graph and sets its uid + this.add_edge = function (n1,n2,e){ + edges.push(e); + e.uid = uid++; + if(!graph[n1.uid]) graph[n1.uid] = {}; + if(!graph[n1.uid][n2.uid]) graph[n1.uid][n2.uid] = []; + if(!links[n1.uid]) links[n1.uid] = []; + if(!links[n2.uid]) links[n2.uid] = []; + + graph[n1.uid][n2.uid].push(e); + links[n1.uid].push(e); + if(n1 != n2){ + links[n2.uid].push(e); + } + }; + + //removes an edge from the graph + this.remove_edge = function(edge){ + edges = _.without(edges,edge); + var n1 = edge.get_start(); + var n2 = edge.get_end(); + links[n1.uid] = _.without(links[n1.uid],edge); + links[n2.uid] = _.without(links[n2.uid],edge); + graph[n1.uid][n2.uid] = _.without(graph[n1.uid][n2.uid],edge); + if ( selected_entity == edge ){ + selected_entity = null; + } + }; + //removes a node and all connected edges from the graph + this.remove_node = function(node){ + var linked_edges = self.get_linked_edge_list(node); + for(var i = 0; i < linked_edges.length; i++){ + linked_edges[i].remove(); + } + nodes = _.without(nodes,node); + + if ( selected_entity == node ){ + selected_entity = null; + } + } + + + //return the list of edges from n1 to n2 + this.get_edge_list = function(n1,n2){ + var list = []; + if(!graph[n1.uid]) return list; + if(!graph[n1.uid][n2.uid]) return list; + return graph[n1.uid][n2.uid]; + }; + //returns the list of all edge connected to n + this.get_linked_edge_list = function(n){ + if(!links[n.uid]) return []; + return links[n.uid]; + }; + //return a curvature index so that all edges connecting n1,n2 have different curvatures + this.get_edge_curvature = function(n1,n2,e){ + var el_12 = this.get_edge_list(n1,n2); + var c12 = el_12.length; + var el_21 = this.get_edge_list(n2,n1); + var c21 = el_21.length; + if(c12 + c21 == 1){ // only one edge + return 0; + }else{ + var index = 0; + for(var i = 0; i < c12; i++){ + if (el_12[i].uid < e.uid){ + index++; + } + } + if(c21 == 0){ // all edges in the same direction + return index - (c12-1)/2.0; + }else{ + return index + 0.5; + } + } + }; + + + // Returns the angle in degrees of the edge loop. We do not support more than 8 loops on one node + this.get_loop_angle = function(n,e){ + var loop_list = this.get_edge_list(n,n); + + var slots = []; // the 8 angles where we can put the loops + for(var angle = 0; angle < 360; angle += 45){ + slots.push(Vec2.new_polar_deg(1,angle)); + } + + //we assign to each slot a score. The higher the score, the closer it is to other edges. + var links = this.get_linked_edge_list(n); + for(var i = 0; i < links.length; i++){ + var edge = links[i]; + if(!edge.is_loop || edge.is_loop()){ + continue; + } + var end = edge.get_end(); + if (end == n){ + end = edge.get_start(); + } + var dir = end.get_pos().sub(n.get_pos()).normalize(); + for(var s = 0; s < slots.length; s++){ + var score = slots[s].dot(dir); + if(score < 0){ + score = -0.2*Math.pow(score,2); + }else{ + score = Math.pow(score,2); + } + if(!slots[s].score){ + slots[s].score = score; + }else{ + slots[s].score += score; + } + } + } + //we want the loops with lower uid to get the slots with the lower score + slots.sort(function(a,b){ return a.score < b.score ? -1: 1; }); + + var index = 0; + for(var i = 0; i < links.length; i++){ + var edge = links[i]; + if(!edge.is_loop || !edge.is_loop()){ + continue; + } + if(edge.uid < e.uid){ + index++; + } + } + index %= slots.length; + + return slots[index].angle_deg(); + } + + //selects a node or an edge and deselects everything else + this.select = function(entity){ + if(selected_entity){ + if(selected_entity == entity){ + return; + }else{ + if(selected_entity.set_not_selected){ + selected_entity.set_not_selected(); + } + selected_entity = null; + } + } + selected_entity = entity; + if(entity && entity.set_selected){ + entity.set_selected(); + } + }; + } + + // creates a new Graph Node on Raphael document r, centered on [pos_x,pos_y], with label 'label', + // and of type 'circle' or 'rect', and of color 'color' + function GraphNode(graph,pos_x, pos_y,label,type,color){ + var self = this; + var r = graph.r; + var sy = graph.style.node_size_y; + var sx = graph.style.node_size_x; + var node_fig = null; + var selected = false; + this.connectors = []; + this.close_button = null; + this.uid = 0; + + graph.add_node(this); + + if(type == 'circle'){ + node_fig = r.ellipse(pos_x,pos_y,sx/2,sy/2); + }else{ + node_fig = r.rect(pos_x-sx/2,pos_y-sy/2,sx,sy); + } + node_fig.attr({ 'fill': color, + 'stroke': graph.style.node_outline_color, + 'stroke-width': graph.style.node_outline_width, + 'cursor':'pointer' }); + node_fig.transform(graph.get_transform()); + graph.set_scrolling(node_fig); + + var node_label = r.text(pos_x,pos_y,label); + node_label.attr({ 'fill': graph.style.node_label_color, + 'font-size': graph.style.node_label_font_size, + 'cursor': 'pointer' }); + node_label.transform(graph.get_transform()); + graph.set_scrolling(node_label); + + // redraws all edges linked to this node + var update_linked_edges = function(){ + var edges = graph.get_linked_edge_list(self); + for(var i = 0; i < edges.length; i++){ + edges[i].update(); + } + }; + + // sets the center position of the node + var set_pos = function(pos){ + if(type == 'circle'){ + node_fig.attr({'cx':pos.x,'cy':pos.y}); + }else{ + node_fig.attr({'x':pos.x-sx/2,'y':pos.y-sy/2}); + } + node_label.attr({'x':pos.x,'y':pos.y}); + for(var i = 0; i < self.connectors.length; i++){ + self.connectors[i].update_pos(); + } + if(self.close_button){ + self.close_button.update_pos(); + } + update_linked_edges(); + }; + // returns the figure used to draw the node + var get_fig = function(){ + return node_fig; + }; + // returns the center coordinates + var get_pos = function(){ + if(type == 'circle'){ + return new Vec2(node_fig.attr('cx'), node_fig.attr('cy')); + }else{ + return new Vec2(node_fig.attr('x') + sx/2, node_fig.attr('y') + sy/2); + } + }; + // return the label string + var get_label = function(){ + return node_label.attr("text"); + }; + // sets the label string + var set_label = function(text){ + node_label.attr({'text':text}); + }; + var get_bound = function(){ + if(type == 'circle'){ + return new BEllipse(get_pos().x,get_pos().y,sx/2,sy/2); + }else{ + return BRect.new_centered(get_pos().x,get_pos().y,sx,sy); + } + }; + // selects this node and deselects all other nodes + var set_selected = function(){ + if(!selected){ + selected = true; + node_fig.attr({ 'stroke': graph.style.node_selected_color, + 'stroke-width': graph.style.node_selected_width }); + if(!self.close_button){ + self.close_button = new CloseButton(graph,self, "node" ,sx/2 , - sy/2); + self.close_button.show(); + } + for(var i = 0; i < self.connectors.length; i++){ + self.connectors[i].show(); + } + } + }; + // deselect this node + var set_not_selected = function(){ + if(selected){ + node_fig.animate({ 'stroke': graph.style.node_outline_color, + 'stroke-width': graph.style.node_outline_width }, + 100,'linear'); + if(self.close_button){ + self.close_button.remove(); + self.close_button = null; + } + selected = false; + } + for(var i = 0; i < self.connectors.length; i++){ + self.connectors[i].hide(); + } + }; + var remove = function(){ + if(self.close_button){ + self.close_button.remove(); + } + for(var i = 0; i < self.connectors.length; i++){ + self.connectors[i].remove(); + } + graph.remove_node(self); + node_fig.remove(); + node_label.remove(); + } + + + this.set_pos = set_pos; + this.get_pos = get_pos; + this.set_label = set_label; + this.get_label = get_label; + this.get_bound = get_bound; + this.get_fig = get_fig; + this.set_selected = set_selected; + this.set_not_selected = set_not_selected; + this.update_linked_edges = update_linked_edges; + this.remove = remove; + + + //select the node and play an animation when clicked + var click_action = function(){ + if(type == 'circle'){ + node_fig.attr({'rx':sx/2 + 3, 'ry':sy/2+ 3}); + node_fig.animate({'rx':sx/2, 'ry':sy/2},500,'elastic'); + }else{ + var cx = get_pos().x; + var cy = get_pos().y; + node_fig.attr({'x':cx - (sx/2) - 3, 'y':cy - (sy/2) - 3, 'ẃidth':sx+6, 'height':sy+6}); + node_fig.animate({'x':cx - sx/2, 'y':cy - sy/2, 'ẃidth':sx, 'height':sy},500,'elastic'); + } + graph.select(self); + }; + node_fig.click(click_action); + node_label.click(click_action); + + //move the node when dragged + var drag_down = function(){ + this.opos = get_pos(); + }; + var drag_move = function(dx,dy){ + // we disable labels when moving for performance reasons, + // updating the label position is quite expensive + // we put this here because drag_down is also called on simple clicks ... and this causes unwanted flicker + var edges = graph.get_linked_edge_list(self); + for(var i = 0; i < edges.length; i++){ + edges[i].label_disable(); + } + if(self.close_button){ + self.close_button.hide(); + } + set_pos(this.opos.add_xy(dx,dy)); + }; + var drag_up = function(){ + //we re-enable the + var edges = graph.get_linked_edge_list(self); + for(var i = 0; i < edges.length; i++){ + edges[i].label_enable(); + } + if(self.close_button){ + self.close_button.show(); + } + }; + node_fig.drag(drag_move,drag_down,drag_up); + node_label.drag(drag_move,drag_down,drag_up); + + //allow the user to create edges by dragging onto the node + function hover_in(){ + if(graph.creating_edge){ + graph.target_node = self; + } + } + function hover_out(){ + graph.target_node = null; + } + node_fig.hover(hover_in,hover_out); + node_label.hover(hover_in,hover_out); + + function double_click(){ + GraphNode.double_click_callback(self); + } + node_fig.dblclick(double_click); + node_label.dblclick(double_click); + + this.connectors.push(new Connector(graph,this,-sx/2,0)); + this.connectors.push(new Connector(graph,this,sx/2,0)); + this.connectors.push(new Connector(graph,this,0,-sy/2)); + this.connectors.push(new Connector(graph,this,0,sy/2)); + + this.close_button = new CloseButton(graph,this,"node",sx/2 , - sy/2 ); + } + + GraphNode.double_click_callback = function(node){ + console.log("double click from node:",node); + }; + + // this is the default node destruction callback. It is called before the node is removed from the graph + // and before the connected edges are destroyed + GraphNode.destruction_callback = function(node){ return true; }; + + // creates a new edge with label 'label' from start to end. start and end must implement get_pos_*, + // if tmp is true, the edge is not added to the graph, used for drag edges. + // replace tmp == false by graph == null + function GraphEdge(graph,label,start,end,tmp){ + var self = this; + var r = graph.r; + var curvature = 0; // 0 = straight, != 0 curved + var s,e; // positions of the start and end point of the line between start and end + var mc; // position of the middle of the curve (bezier control point) + var mc1,mc2; // control points of the cubic bezier for the loop edges + var elfs = graph.style.edge_label_font_size || 10 ; + var label_enabled = true; + this.uid = 0; // unique id used to order the curved edges + var edge_path = ""; // svg definition of the edge vector path + var selected = false; + + if(!tmp){ + graph.add_edge(start,end,this); + } + + //Return the position of the label + function get_label_pos(path){ + var cpos = path.getTotalLength() * 0.5; + var cindex = Math.abs(Math.floor(curvature)); + var mod = ((cindex % 3)) * (elfs * 3.1) - (elfs * 0.5); + var verticality = Math.abs(end.get_pos().sub(start.get_pos()).normalize().dot_xy(0,1)); + verticality = Math.max(verticality-0.5,0)*2; + + var lpos = path.getPointAtLength(cpos + mod * verticality); + return new Vec2(lpos.x,lpos.y - elfs *(1-verticality)); + } + + //used by close_button + this.get_pos = function(){ + if(!edge){ + return start.get_pos().lerp(end.get_pos(),0.5); + } + return get_label_pos(edge); + /* + var bbox = edge_label.getBBox(); Does not work... :( + return new Vec2(bbox.x + bbox.width, bbox.y);*/ + } + + //Straight line from s to e + function make_line(){ + return "M" + s.x + "," + s.y + "L" + e.x + "," + e.y ; + } + //Curved line from s to e by mc + function make_curve(){ + return "M" + s.x + "," + s.y + "Q" + mc.x + "," + mc.y + " " + e.x + "," + e.y; + } + //Curved line from s to e by mc1 mc2 + function make_loop(){ + return "M" + s.x + " " + s.y + + "C" + mc1.x + " " + mc1.y + " " + mc2.x + " " + mc2.y + " " + e.x + " " + e.y; + } + + //computes new start and end line coordinates + function update_curve(){ + if(start != end){ + if(!tmp){ + curvature = graph.get_edge_curvature(start,end,self); + }else{ + curvature = 0; + } + s = start.get_pos(); + e = end.get_pos(); + + mc = s.lerp(e,0.5); //middle of the line s->e + var se = e.sub(s); + se = se.normalize(); + se = se.rotate_deg(-90); + se = se.scale(curvature * graph.style.edge_spacing); + mc = mc.add(se); + + if(start.get_bound){ + var col = start.get_bound().collide_segment(s,mc); + if(col.length > 0){ + s = col[0]; + } + } + if(end.get_bound){ + var col = end.get_bound().collide_segment(mc,e); + if(col.length > 0){ + e = col[0]; + } + } + + if(curvature != 0){ + edge_path = make_curve(); + }else{ + edge_path = make_line(); + } + }else{ // start == end + var rad = graph.style.edge_loop_radius || 100; + s = start.get_pos(); + e = end.get_pos(); + + var r = Vec2.new_polar_deg(rad,graph.get_loop_angle(start,self)); + mc = s.add(r); + var p = r.rotate_deg(90); + mc1 = mc.add(p.set_len(rad*0.5)); + mc2 = mc.add(p.set_len(-rad*0.5)); + + if(start.get_bound){ + var col = start.get_bound().collide_segment(s,mc1); + if(col.length > 0){ + s = col[0]; + } + var col = start.get_bound().collide_segment(e,mc2); + if(col.length > 0){ + e = col[0]; + } + } + edge_path = make_loop(); + } + } + + update_curve(); + var edge = r.path(edge_path).attr({ 'stroke': graph.style.edge_color, + 'stroke-width': graph.style.edge_width, + 'arrow-end': 'block-wide-long', + 'cursor':'pointer' }).insertBefore(graph.get_node_list()[0].get_fig()); + var labelpos = get_label_pos(edge); + var edge_label = r.text(labelpos.x, labelpos.y - elfs, label).attr({ + 'fill': graph.style.edge_label_color, + 'cursor': 'pointer', + 'font-size': elfs }); + + edge.transform(graph.get_transform()); + graph.set_scrolling(edge); + + edge_label.transform(graph.get_transform()); + graph.set_scrolling(edge_label); + + + //since we create an edge we need to recompute the edges that have the same start and end positions as this one + if(!tmp){ + var edges_start = graph.get_linked_edge_list(start); + var edges_end = graph.get_linked_edge_list(end); + var edges = edges_start.length < edges_end.length ? edges_start : edges_end; + for(var i = 0; i < edges.length; i ++){ + if(edges[i] != self){ + edges[i].update(); + } + } + } + function label_enable(){ + if(!label_enabled){ + label_enabled = true; + edge_label.animate({'opacity':1},100,'linear'); + if(self.close_button){ + self.close_button.show(); + } + self.update(); + } + } + function label_disable(){ + if(label_enabled){ + label_enabled = false; + edge_label.animate({'opacity':0},100,'linear'); + if(self.close_button){ + self.close_button.hide(); + } + } + } + //update the positions + function update(){ + update_curve(); + edge.attr({'path':edge_path}); + if(label_enabled){ + var labelpos = get_label_pos(edge); + edge_label.attr({'x':labelpos.x, 'y':labelpos.y - 14}); + } + } + // removes the edge from the scene, disconnects it from linked + // nodes, destroy its drawable elements. + function remove(){ + edge.remove(); + edge_label.remove(); + if(!tmp){ + graph.remove_edge(self); + } + if(start.update_linked_edges){ + start.update_linked_edges(); + } + if(start != end && end.update_linked_edges){ + end.update_linked_edges(); + } + if(self.close_button){ + self.close_button.remove(); + } + } + + this.set_selected = function(){ + if(!selected){ + selected = true; + edge.attr({ 'stroke': graph.style.node_selected_color, + 'stroke-width': graph.style.node_selected_width }); + edge_label.attr({ 'fill': graph.style.node_selected_color }); + if(!self.close_button){ + self.close_button = new CloseButton(graph,self,"edge",0,30); + self.close_button.show(); + } + } + }; + + this.set_not_selected = function(){ + if(selected){ + selected = false; + edge.animate({ 'stroke': graph.style.edge_color, + 'stroke-width': graph.style.edge_width }, 100,'linear'); + edge_label.animate({ 'fill': graph.style.edge_label_color}, 100, 'linear'); + if(self.close_button){ + self.close_button.remove(); + self.close_button = null; + } + } + }; + function click_action(){ + graph.select(self); + } + edge.click(click_action); + edge_label.click(click_action); + + function double_click_action(){ + GraphEdge.double_click_callback(self); + } + + edge.dblclick(double_click_action); + edge_label.dblclick(double_click_action); + + + this.label_enable = label_enable; + this.label_disable = label_disable; + this.update = update; + this.remove = remove; + this.is_loop = function(){ return start == end; }; + this.get_start = function(){ return start; }; + this.get_end = function(){ return end; }; + } + + GraphEdge.double_click_callback = function(edge){ + console.log("double click from edge:",edge); + }; + + // this is the default edge creation callback. It is called before an edge is created + // It returns an object containing the properties of the edge. + // If it returns null, the edge is not created. + GraphEdge.creation_callback = function(start,end){ + var edge_prop = {}; + edge_prop.label = 'new edge!'; + return edge_prop; + }; + // This is is called after a new edge is created, with the new edge + // as parameter + GraphEdge.new_edge_callback = function(new_edge){}; + + // this is the default edge destruction callback. It is called before + // an edge is removed from the graph. + GraphEdge.destruction_callback = function(edge){ return true; }; + + + + // returns a new string with the same content as str, but with lines of maximum 'width' characters. + // lines are broken on words, or into words if a word is longer than 'width' + function wordwrap( str, width) { + // http://james.padolsey.com/javascript/wordwrap-for-javascript/ + width = width || 32; + var cut = true; + var brk = '\n'; + if (!str) { return str; } + var regex = '.{1,' +width+ '}(\\s|$)' + (cut ? '|.{' +width+ '}|.+$' : '|\\S+?(\\s|$)'); + return str.match(new RegExp(regex, 'g') ).join( brk ); + } + + window.CuteGraph = Graph; + window.CuteNode = GraphNode; + window.CuteEdge = GraphEdge; + + window.CuteGraph.wordwrap = wordwrap; + + +})(window); + diff --git a/addons/web_diagram/static/src/js/vec2.js b/addons/web_diagram/static/src/js/vec2.js new file mode 100644 index 00000000000..28790008be3 --- /dev/null +++ b/addons/web_diagram/static/src/js/vec2.js @@ -0,0 +1,358 @@ + +(function(window){ + + // A Javascript 2D vector library + // conventions : + // method that returns a float value do not modify the vector + // method that implement operators return a new vector with the modifications without + // modifying the calling vector or the parameters. + // + // v3 = v1.add(v2); // v3 is set to v1 + v2, v1, v2 are not modified + // + // methods that take a single vector as a parameter are usually also available with + // q '_xy' suffix. Those method takes two floats representing the x,y coordinates of + // the vector parameter and allow you to avoid to needlessly create a vector object : + // + // v2 = v1.add(new Vec2(3,4)); + // v2 = v1.add_xy(3,4); //equivalent to previous line + // + // angles are in radians by default but method that takes angle as parameters + // or return angle values usually have a variant with a '_deg' suffix that works in degrees + // + + // The 2D vector object + function Vec2(x,y){ + this.x = x; + this.y = y; + } + + window.Vec2 = Vec2; + + // Multiply a number expressed in radiant by rad2deg to convert it in degrees + var rad2deg = 57.29577951308232; + // Multiply a number expressed in degrees by deg2rad to convert it to radiant + var deg2rad = 0.017453292519943295; + // The numerical precision used to compare vector equality + var epsilon = 0.0000001; + + // This static method creates a new vector from polar coordinates with the angle expressed + // in degrees + Vec2.new_polar_deg = function(len,angle){ + var v = new Vec2(len,0); + return v.rotate_deg(angle); + }; + // This static method creates a new vector from polar coordinates with the angle expressed in + // radians + Vec2.new_polar = function(len,angle){ + var v = new Vec2(len,0); + v.rotate(angle); + return v; + }; + // returns the length or modulus or magnitude of the vector + Vec2.prototype.len = function(){ + return Math.sqrt(this.x*this.x + this.y*this.y); + }; + // returns the squared length of the vector, this method is much faster than len() + Vec2.prototype.len_sq = function(){ + return this.x*this.x + this.y*this.y; + }; + // return the distance between this vector and the vector v + Vec2.prototype.dist = function(v){ + var dx = this.x - v.x; + var dy = this.y - v.y; + return Math.sqrt(dx*dx + dy*dy); + }; + // return the distance between this vector and the vector of coordinates (x,y) + Vec2.prototype.dist_xy = function(x,y){ + var dx = this.x - x; + var dy = this.y - y; + return Math.sqrt(dx*dx + dy*dy); + }; + // return the squared distance between this vector and the vector and the vector v + Vec2.prototype.dist_sq = function(v){ + var dx = this.x - v.x; + var dy = this.y - v.y; + return dx*dx + dy*dy; + }; + // return the squared distance between this vector and the vector of coordinates (x,y) + Vec2.prototype.dist_sq_xy = function(x,y){ + var dx = this.x - x; + var dy = this.y - y; + return dx*dx + dy*dy; + }; + // return the dot product between this vector and the vector v + Vec2.prototype.dot = function(v){ + return this.x*v.x + this.y*v.y; + }; + // return the dot product between this vector and the vector of coordinate (x,y) + Vec2.prototype.dot_xy = function(x,y){ + return this.x*x + this.y*y; + }; + // return a new vector with the same coordinates as this + Vec2.prototype.clone = function(){ + return new Vec2(this.x,this.y); + }; + // return the sum of this and vector v as a new vector + Vec2.prototype.add = function(v){ + return new Vec2(this.x+v.x,this.y+v.y); + }; + // return the sum of this and vector (x,y) as a new vector + Vec2.prototype.add_xy = function(x,y){ + return new Vec2(this.x+x,this.y+y); + }; + // returns (this - v) as a new vector where v is a vector and - is the vector subtraction + Vec2.prototype.sub = function(v){ + return new Vec2(this.x-v.x,this.y-v.y); + }; + // returns (this - (x,y)) as a new vector where - is vector subtraction + Vec2.prototype.sub_xy = function(x,y){ + return new Vec2(this.x-x,this.y-y); + }; + // return (this * v) as a new vector where v is a vector and * is the by component product + Vec2.prototype.mult = function(v){ + return new Vec2(this.x*v.x,this.y*v.y); + }; + // return (this * (x,y)) as a new vector where * is the by component product + Vec2.prototype.mult_xy = function(x,y){ + return new Vec2(this.x*x,this.y*y); + }; + // return this scaled by float f as a new fector + Vec2.prototype.scale = function(f){ + return new Vec2(this.x*f, this.y*f); + }; + // return the negation of this vector + Vec2.prototype.neg = function(f){ + return new Vec2(-this.x,-this.y); + }; + // return this vector normalized as a new vector + Vec2.prototype.normalize = function(){ + var len = this.len(); + if(len == 0){ + return new Vec2(0,1); + }else if(len != 1){ + return this.scale(1.0/len); + } + return new Vec2(this.x,this.y); + }; + // return a new vector with the same direction as this vector of length float l. (negative values of l will invert direction) + Vec2.prototype.set_len = function(l){ + return this.normalize().scale(l); + }; + // return the projection of this onto the vector v as a new vector + Vec2.prototype.project = function(v){ + return v.set_len(this.dot(v)); + }; + // return a string representation of this vector + Vec2.prototype.toString = function(){ + var str = ""; + str += "["; + str += this.x; + str += ","; + str += this.y; + str += "]"; + return str; + }; + //return this vector counterclockwise rotated by rad radians as a new vector + Vec2.prototype.rotate = function(rad){ + var c = Math.cos(rad); + var s = Math.sin(rad); + var px = this.x * c - this.y *s; + var py = this.x * s + this.y *c; + return new Vec2(px,py); + }; + //return this vector counterclockwise rotated by deg degrees as a new vector + Vec2.prototype.rotate_deg = function(deg){ + return this.rotate(deg * deg2rad); + }; + //linearly interpolate this vector towards the vector v by float factor alpha. + // alpha == 0 : does nothing + // alpha == 1 : sets this to v + Vec2.prototype.lerp = function(v,alpha){ + var inv_alpha = 1 - alpha; + return new Vec2( this.x * inv_alpha + v.x * alpha, + this.y * inv_alpha + v.y * alpha ); + }; + // returns the angle between this vector and the vector (1,0) in radians + Vec2.prototype.angle = function(){ + return Math.atan2(this.y,this.x); + }; + // returns the angle between this vector and the vector (1,0) in degrees + Vec2.prototype.angle_deg = function(){ + return Math.atan2(this.y,this.x) * rad2deg; + }; + // returns true if this vector is equal to the vector v, with a tolerance defined by the epsilon module constant + Vec2.prototype.equals = function(v){ + if(Math.abs(this.x-v.x) > epsilon){ + return false; + }else if(Math.abs(this.y-v.y) > epsilon){ + return false; + } + return true; + }; + // returns true if this vector is equal to the vector (x,y) with a tolerance defined by the epsilon module constant + Vec2.prototype.equals_xy = function(x,y){ + if(Math.abs(this.x-x) > epsilon){ + return false; + }else if(Math.abs(this.y-y) > epsilon){ + return false; + } + return true; + }; +})(window); + +(function(window){ + // A Bounding Shapes Library + + + // A Bounding Ellipse + // cx,cy : center of the ellipse + // rx,ry : radius of the ellipse + function BEllipse(cx,cy,rx,ry){ + this.type = 'ellipse'; + this.x = cx-rx; // minimum x coordinate contained in the ellipse + this.y = cy-ry; // minimum y coordinate contained in the ellipse + this.sx = 2*rx; // width of the ellipse on the x axis + this.sy = 2*ry; // width of the ellipse on the y axis + this.hx = rx; // half of the ellipse width on the x axis + this.hy = ry; // half of the ellipse width on the y axis + this.cx = cx; // x coordinate of the ellipse center + this.cy = cy; // y coordinate of the ellipse center + this.mx = cx + rx; // maximum x coordinate contained in the ellipse + this.my = cy + ry; // maximum x coordinate contained in the ellipse + } + window.BEllipse = BEllipse; + + // returns an unordered list of vector defining the positions of the intersections between the ellipse's + // boundary and a line segment defined by the start and end vectors a,b + BEllipse.prototype.collide_segment = function(a,b){ + // http://paulbourke.net/geometry/sphereline/ + var collisions = []; + + if(a.equals(b)){ //we do not compute the intersection in this case. TODO ? + return collisions; + } + + // make all computations in a space where the ellipse is a circle + // centered on zero + var c = new Vec2(this.cx,this.cy); + a = a.sub(c).mult_xy(1/this.hx,1/this.hy); + b = b.sub(c).mult_xy(1/this.hx,1/this.hy); + + + if(a.len_sq() < 1 && b.len_sq() < 1){ //both points inside the ellipse + return collisions; + } + + // compute the roots of the intersection + var ab = b.sub(a); + var A = (ab.x*ab.x + ab.y*ab.y); + var B = 2*( ab.x*a.x + ab.y*a.y); + var C = a.x*a.x + a.y*a.y - 1; + var u = B * B - 4*A*C; + + if(u < 0){ + return collisions; + } + + u = Math.sqrt(u); + var u1 = (-B + u) / (2*A); + var u2 = (-B - u) / (2*A); + + if(u1 >= 0 && u1 <= 1){ + var pos = a.add(ab.scale(u1)); + collisions.push(pos); + } + if(u1 != u2 && u2 >= 0 && u2 <= 1){ + var pos = a.add(ab.scale(u2)); + collisions.push(pos); + } + for(var i = 0; i < collisions.length; i++){ + collisions[i] = collisions[i].mult_xy(this.hx,this.hy); + collisions[i] = collisions[i].add_xy(this.cx,this.cy); + } + return collisions; + }; + + // A bounding rectangle + // x,y the minimum coordinate contained in the rectangle + // sx,sy the size of the rectangle along the x,y axis + function BRect(x,y,sx,sy){ + this.type = 'rect'; + this.x = x; // minimum x coordinate contained in the rectangle + this.y = y; // minimum y coordinate contained in the rectangle + this.sx = sx; // width of the rectangle on the x axis + this.sy = sy; // width of the rectangle on the y axis + this.hx = sx/2; // half of the rectangle width on the x axis + this.hy = sy/2; // half of the rectangle width on the y axis + this.cx = x + this.hx; // x coordinate of the rectangle center + this.cy = y + this.hy; // y coordinate of the rectangle center + this.mx = x + sx; // maximum x coordinate contained in the rectangle + this.my = y + sy; // maximum x coordinate contained in the rectangle + } + + window.BRect = BRect; + // Static method creating a new bounding rectangle of size (sx,sy) centered on (cx,cy) + BRect.new_centered = function(cx,cy,sx,sy){ + return new BRect(cx-sx/2,cy-sy/2,sx,sy); + }; + //intersect line a,b with line c,d, returns null if no intersection + function line_intersect(a,b,c,d){ + // http://paulbourke.net/geometry/lineline2d/ + var f = ((d.y - c.y)*(b.x - a.x) - (d.x - c.x)*(b.y - a.y)); + if(f == 0){ + return null; + } + f = 1 / f; + var fab = ((d.x - c.x)*(a.y - c.y) - (d.y - c.y)*(a.x - c.x)) * f ; + if(fab < 0 || fab > 1){ + return null; + } + var fcd = ((b.x - a.x)*(a.y - c.y) - (b.y - a.y)*(a.x - c.x)) * f ; + if(fcd < 0 || fcd > 1){ + return null; + } + return new Vec2(a.x + fab * (b.x-a.x), a.y + fab * (b.y - a.y) ); + } + + // returns an unordered list of vector defining the positions of the intersections between the ellipse's + // boundary and a line segment defined by the start and end vectors a,b + + BRect.prototype.collide_segment = function(a,b){ + var collisions = []; + var corners = [ new Vec2(this.x,this.y), new Vec2(this.x,this.my), + new Vec2(this.mx,this.my), new Vec2(this.mx,this.y) ]; + var pos = line_intersect(a,b,corners[0],corners[1]); + if(pos) collisions.push(pos); + pos = line_intersect(a,b,corners[1],corners[2]); + if(pos) collisions.push(pos); + pos = line_intersect(a,b,corners[2],corners[3]); + if(pos) collisions.push(pos); + pos = line_intersect(a,b,corners[3],corners[0]); + if(pos) collisions.push(pos); + return collisions; + }; + + // returns true if the rectangle contains the position defined by the vector 'vec' + BRect.prototype.contains_vec = function(vec){ + return ( vec.x >= this.x && vec.x <= this.mx && + vec.y >= this.y && vec.y <= this.my ); + }; + // returns true if the rectangle contains the position (x,y) + BRect.prototype.contains_xy = function(x,y){ + return ( x >= this.x && x <= this.mx && + y >= this.y && y <= this.my ); + }; + // returns true if the ellipse contains the position defined by the vector 'vec' + BEllipse.prototype.contains_vec = function(v){ + v = v.mult_xy(this.hx,this.hy); + return v.len_sq() <= 1; + }; + // returns true if the ellipse contains the position (x,y) + BEllipse.prototype.contains_xy = function(x,y){ + return this.contains(new Vec2(x,y)); + }; + + +})(window); + + diff --git a/addons/web_diagram/static/src/xml/base_diagram.xml b/addons/web_diagram/static/src/xml/base_diagram.xml index 6d0e36e2f17..96e32f59648 100644 --- a/addons/web_diagram/static/src/xml/base_diagram.xml +++ b/addons/web_diagram/static/src/xml/base_diagram.xml @@ -1,6 +1,7 @@ diff --git a/addons/web_gantt/__openerp__.py b/addons/web_gantt/__openerp__.py index 44ddf66b791..ee6b2d71d18 100644 --- a/addons/web_gantt/__openerp__.py +++ b/addons/web_gantt/__openerp__.py @@ -16,5 +16,5 @@ 'qweb' : [ "static/src/xml/*.xml", ], - 'active': True + 'auto_install': True } diff --git a/addons/web_gantt/i18n/es_CR.po b/addons/web_gantt/i18n/es_CR.po index 3db7c89a234..bad743364ea 100644 --- a/addons/web_gantt/i18n/es_CR.po +++ b/addons/web_gantt/i18n/es_CR.po @@ -1,21 +1,21 @@ -# Translations template for PROJECT. -# Copyright (C) 2012 ORGANIZATION -# This file is distributed under the same license as the PROJECT project. +# Spanish (Costa Rica) translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. # FIRST AUTHOR , 2012. # msgid "" msgstr "" -"Project-Id-Version: PROJECT VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-06 17:33+0100\n" -"PO-Revision-Date: 2012-02-08 02:26-0600\n" -"Last-Translator: Carlos Vásquez - CLEARCORP \n" -"Language-Team: LANGUAGE \n" -"Language: \n" +"PO-Revision-Date: 2012-02-17 14:18+0000\n" +"Last-Translator: Freddy Gonzalez \n" +"Language-Team: Spanish (Costa Rica) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 0.9.6\n" +"X-Launchpad-Export-Date: 2012-02-18 05:18+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 @@ -26,4 +26,3 @@ msgstr "Gantt" #: addons/web_gantt/static/src/xml/web_gantt.xml:10 msgid "Create" msgstr "Crear" - diff --git a/addons/web_gantt/i18n/fi.po b/addons/web_gantt/i18n/fi.po new file mode 100644 index 00000000000..3df7d9539c4 --- /dev/null +++ b/addons/web_gantt/i18n/fi.po @@ -0,0 +1,28 @@ +# Finnish translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-03-19 11:57+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Finnish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-20 05:13+0000\n" +"X-Generator: Launchpad (build 14969)\n" + +#. openerp-web +#: addons/web_gantt/static/src/js/gantt.js:11 +msgid "Gantt" +msgstr "Gantt-kaavio" + +#. openerp-web +#: addons/web_gantt/static/src/xml/web_gantt.xml:10 +msgid "Create" +msgstr "Luo" diff --git a/addons/web_gantt/i18n/it.po b/addons/web_gantt/i18n/it.po new file mode 100644 index 00000000000..f855549b150 --- /dev/null +++ b/addons/web_gantt/i18n/it.po @@ -0,0 +1,28 @@ +# Italian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-02-16 21:56+0000\n" +"Last-Translator: Davide Corio - agilebg.com \n" +"Language-Team: Italian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" + +#. openerp-web +#: addons/web_gantt/static/src/js/gantt.js:11 +msgid "Gantt" +msgstr "Gantt" + +#. openerp-web +#: addons/web_gantt/static/src/xml/web_gantt.xml:10 +msgid "Create" +msgstr "Crea" diff --git a/addons/web_gantt/i18n/ka.po b/addons/web_gantt/i18n/ka.po new file mode 100644 index 00000000000..d406a2eb937 --- /dev/null +++ b/addons/web_gantt/i18n/ka.po @@ -0,0 +1,28 @@ +# Georgian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-03-15 19:00+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Georgian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-16 05:14+0000\n" +"X-Generator: Launchpad (build 14951)\n" + +#. openerp-web +#: addons/web_gantt/static/src/js/gantt.js:11 +msgid "Gantt" +msgstr "განტი" + +#. openerp-web +#: addons/web_gantt/static/src/xml/web_gantt.xml:10 +msgid "Create" +msgstr "შექმნა" diff --git a/addons/web_gantt/i18n/pl.po b/addons/web_gantt/i18n/pl.po new file mode 100644 index 00000000000..1d2da1bb3f4 --- /dev/null +++ b/addons/web_gantt/i18n/pl.po @@ -0,0 +1,28 @@ +# Polish translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-02-28 11:09+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Polish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-02-29 04:54+0000\n" +"X-Generator: Launchpad (build 14874)\n" + +#. openerp-web +#: addons/web_gantt/static/src/js/gantt.js:11 +msgid "Gantt" +msgstr "" + +#. openerp-web +#: addons/web_gantt/static/src/xml/web_gantt.xml:10 +msgid "Create" +msgstr "Utwórz" diff --git a/addons/web_gantt/i18n/pt.po b/addons/web_gantt/i18n/pt.po index a6113f74f5a..2da9efca5d6 100644 --- a/addons/web_gantt/i18n/pt.po +++ b/addons/web_gantt/i18n/pt.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-16 05:21+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web_gantt/static/src/js/gantt.js:11 diff --git a/addons/web_gantt/i18n/ro.po b/addons/web_gantt/i18n/ro.po new file mode 100644 index 00000000000..704fad3aa45 --- /dev/null +++ b/addons/web_gantt/i18n/ro.po @@ -0,0 +1,28 @@ +# Romanian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-03-19 23:43+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Romanian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-21 05:21+0000\n" +"X-Generator: Launchpad (build 14981)\n" + +#. openerp-web +#: addons/web_gantt/static/src/js/gantt.js:11 +msgid "Gantt" +msgstr "Gantt" + +#. openerp-web +#: addons/web_gantt/static/src/xml/web_gantt.xml:10 +msgid "Create" +msgstr "Crează" diff --git a/addons/web_graph/__openerp__.py b/addons/web_graph/__openerp__.py index 5a42ea381fe..6c62ffe4ede 100644 --- a/addons/web_graph/__openerp__.py +++ b/addons/web_graph/__openerp__.py @@ -12,5 +12,5 @@ 'qweb' : [ "static/src/xml/*.xml", ], - "active": True + "auto_install": True } diff --git a/addons/web_graph/i18n/cs.po b/addons/web_graph/i18n/cs.po new file mode 100644 index 00000000000..e3123d27c3c --- /dev/null +++ b/addons/web_graph/i18n/cs.po @@ -0,0 +1,23 @@ +# Czech translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-03-04 11:19+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Czech \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-05 04:53+0000\n" +"X-Generator: Launchpad (build 14900)\n" + +#. openerp-web +#: addons/web_graph/static/src/js/graph.js:19 +msgid "Graph" +msgstr "" diff --git a/addons/web_graph/i18n/es_CR.po b/addons/web_graph/i18n/es_CR.po index 00b23e0d232..9a2af51e9b1 100644 --- a/addons/web_graph/i18n/es_CR.po +++ b/addons/web_graph/i18n/es_CR.po @@ -1,24 +1,23 @@ -# Translations template for PROJECT. -# Copyright (C) 2012 ORGANIZATION -# This file is distributed under the same license as the PROJECT project. +# Spanish (Costa Rica) translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. # FIRST AUTHOR , 2012. # msgid "" msgstr "" -"Project-Id-Version: PROJECT VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-06 17:33+0100\n" -"PO-Revision-Date: 2012-02-08 02:27-0600\n" -"Last-Translator: Carlos Vásquez - CLEARCORP \n" -"Language-Team: LANGUAGE \n" -"Language: \n" +"PO-Revision-Date: 2012-02-17 14:21+0000\n" +"Last-Translator: Freddy Gonzalez \n" +"Language-Team: Spanish (Costa Rica) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 0.9.6\n" +"X-Launchpad-Export-Date: 2012-02-18 05:18+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web_graph/static/src/js/graph.js:19 msgid "Graph" msgstr "Gráfico" - diff --git a/addons/web_graph/i18n/fi.po b/addons/web_graph/i18n/fi.po new file mode 100644 index 00000000000..098a9e011cb --- /dev/null +++ b/addons/web_graph/i18n/fi.po @@ -0,0 +1,23 @@ +# Finnish translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-03-19 11:57+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Finnish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-20 05:13+0000\n" +"X-Generator: Launchpad (build 14969)\n" + +#. openerp-web +#: addons/web_graph/static/src/js/graph.js:19 +msgid "Graph" +msgstr "Kuvaaja" diff --git a/addons/web_graph/i18n/it.po b/addons/web_graph/i18n/it.po new file mode 100644 index 00000000000..a92a1cdc651 --- /dev/null +++ b/addons/web_graph/i18n/it.po @@ -0,0 +1,23 @@ +# Italian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-02-16 21:56+0000\n" +"Last-Translator: Davide Corio - agilebg.com \n" +"Language-Team: Italian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" + +#. openerp-web +#: addons/web_graph/static/src/js/graph.js:19 +msgid "Graph" +msgstr "Grafico" diff --git a/addons/web_graph/i18n/ja.po b/addons/web_graph/i18n/ja.po new file mode 100644 index 00000000000..ba87993d1f1 --- /dev/null +++ b/addons/web_graph/i18n/ja.po @@ -0,0 +1,23 @@ +# Japanese translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-02-22 02:21+0000\n" +"Last-Translator: Masaki Yamaya \n" +"Language-Team: Japanese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-02-23 04:56+0000\n" +"X-Generator: Launchpad (build 14855)\n" + +#. openerp-web +#: addons/web_graph/static/src/js/graph.js:19 +msgid "Graph" +msgstr "グラフ" diff --git a/addons/web_graph/i18n/ka.po b/addons/web_graph/i18n/ka.po new file mode 100644 index 00000000000..fbe3bf3f757 --- /dev/null +++ b/addons/web_graph/i18n/ka.po @@ -0,0 +1,23 @@ +# Georgian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-03-15 19:01+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Georgian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-16 05:14+0000\n" +"X-Generator: Launchpad (build 14951)\n" + +#. openerp-web +#: addons/web_graph/static/src/js/graph.js:19 +msgid "Graph" +msgstr "გრაფიკი" diff --git a/addons/web_graph/i18n/pl.po b/addons/web_graph/i18n/pl.po new file mode 100644 index 00000000000..f641d25a628 --- /dev/null +++ b/addons/web_graph/i18n/pl.po @@ -0,0 +1,23 @@ +# Polish translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-02-28 11:09+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Polish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-02-29 04:54+0000\n" +"X-Generator: Launchpad (build 14874)\n" + +#. openerp-web +#: addons/web_graph/static/src/js/graph.js:19 +msgid "Graph" +msgstr "Wykres" diff --git a/addons/web_graph/static/src/js/graph.js b/addons/web_graph/static/src/js/graph.js index b7b6063189f..d962c7d6752 100644 --- a/addons/web_graph/static/src/js/graph.js +++ b/addons/web_graph/static/src/js/graph.js @@ -33,7 +33,7 @@ openerp.web_graph.GraphView = openerp.web.View.extend({ this.renderer = null; }, - stop: function () { + destroy: function () { if (this.renderer) { clearTimeout(this.renderer); } @@ -97,7 +97,7 @@ openerp.web_graph.GraphView = openerp.web.View.extend({ this.$element.html(QWeb.render("GraphView", { "fields_view": this.fields_view, "chart": this.chart, - 'element_id': this.widget_parent.element_id + 'element_id': this.getParent().element_id })); var fields = _(this.columns).pluck('name').concat([this.abscissa]); @@ -272,7 +272,7 @@ openerp.web_graph.GraphView = openerp.web.View.extend({ self.renderer = null; var charts = new dhtmlXChart({ view: view_chart, - container: self.widget_parent.element_id+"-"+self.chart+"chart", + container: self.getParent().element_id+"-"+self.chart+"chart", value:"#"+group_list[0].group+"#", gradient: (self.chart == "bar") ? "3d" : "light", alpha: (self.chart == "area") ? 0.6 : 1, @@ -309,8 +309,8 @@ openerp.web_graph.GraphView = openerp.web.View.extend({ } } }); - self.$element.find("#"+self.widget_parent.element_id+"-"+self.chart+"chart").width( - self.$element.find("#"+self.widget_parent.element_id+"-"+self.chart+"chart").width()+120); + self.$element.find("#"+self.getParent().element_id+"-"+self.chart+"chart").width( + self.$element.find("#"+self.getParent().element_id+"-"+self.chart+"chart").width()+120); for (var m = 1; m, 2012. # msgid "" msgstr "" -"Project-Id-Version: PROJECT VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-06 17:33+0100\n" -"PO-Revision-Date: 2012-02-08 02:27-0600\n" -"Last-Translator: Carlos Vásquez - CLEARCORP \n" -"Language-Team: LANGUAGE \n" +"PO-Revision-Date: 2012-02-16 19:16+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Spanish (Costa Rica) \n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" +"Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 0.9.6\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" + diff --git a/addons/web_hello/i18n/pt_BR.po b/addons/web_hello/i18n/pt_BR.po new file mode 100644 index 00000000000..e762be9835d --- /dev/null +++ b/addons/web_hello/i18n/pt_BR.po @@ -0,0 +1,20 @@ +# Brazilian Portuguese translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-06 17:33+0100\n" +"PO-Revision-Date: 2012-03-09 20:43+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Brazilian Portuguese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-10 05:00+0000\n" +"X-Generator: Launchpad (build 14914)\n" + + diff --git a/addons/web_kanban/__openerp__.py b/addons/web_kanban/__openerp__.py index 73e42a25e96..8a769342461 100644 --- a/addons/web_kanban/__openerp__.py +++ b/addons/web_kanban/__openerp__.py @@ -16,5 +16,5 @@ 'qweb' : [ "static/src/xml/*.xml", ], - 'active': True + 'auto_install': True } diff --git a/addons/web_kanban/i18n/es_CR.po b/addons/web_kanban/i18n/es_CR.po index 616f6b5a477..c371f3e48ca 100644 --- a/addons/web_kanban/i18n/es_CR.po +++ b/addons/web_kanban/i18n/es_CR.po @@ -1,21 +1,21 @@ -# Translations template for PROJECT. -# Copyright (C) 2012 ORGANIZATION -# This file is distributed under the same license as the PROJECT project. +# Spanish (Costa Rica) translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. # FIRST AUTHOR , 2012. # msgid "" msgstr "" -"Project-Id-Version: PROJECT VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2012-02-06 17:33+0100\n" -"PO-Revision-Date: 2012-02-08 02:28-0600\n" -"Last-Translator: Carlos Vásquez - CLEARCORP \n" -"Language-Team: LANGUAGE \n" -"Language: \n" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-02-17 14:21+0000\n" +"Last-Translator: Freddy Gonzalez \n" +"Language-Team: Spanish (Costa Rica) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 0.9.6\n" +"X-Launchpad-Export-Date: 2012-02-18 05:18+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 @@ -23,22 +23,31 @@ msgid "Kanban" msgstr "Kanban" #. openerp-web -#: addons/web_kanban/static/src/js/kanban.js:291 +#: addons/web_kanban/static/src/js/kanban.js:294 msgid "Undefined" msgstr "Indefinido" #. openerp-web -#: addons/web_kanban/static/src/js/kanban.js:450 +#: addons/web_kanban/static/src/js/kanban.js:469 msgid "Are you sure you want to delete this record ?" msgstr "¿Está seguro/a que desea eliminar este registro?" #. openerp-web #: addons/web_kanban/static/src/xml/web_kanban.xml:5 -msgid "New" -msgstr "Nuevo" +msgid "Create" +msgstr "Crear" #. openerp-web -#: addons/web_kanban/static/src/xml/web_kanban.xml:55 +#: addons/web_kanban/static/src/xml/web_kanban.xml:41 +msgid "Show more... (" +msgstr "Mostrar más... (" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:41 +msgid "remaining)" +msgstr "restante)" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:59 msgid "
    " msgstr "" - diff --git a/addons/web_kanban/i18n/fi.po b/addons/web_kanban/i18n/fi.po new file mode 100644 index 00000000000..09527ffeae4 --- /dev/null +++ b/addons/web_kanban/i18n/fi.po @@ -0,0 +1,55 @@ +# Finnish translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-03-19 11:56+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Finnish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-20 05:13+0000\n" +"X-Generator: Launchpad (build 14969)\n" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:10 +msgid "Kanban" +msgstr "Kanban" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:294 +#: addons/web_kanban/static/src/js/kanban.js:295 +msgid "Undefined" +msgstr "Määrittämätön" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:469 +#: addons/web_kanban/static/src/js/kanban.js:470 +msgid "Are you sure you want to delete this record ?" +msgstr "Oletko varma että haluat poistaa tämän tietueen ?" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:5 +msgid "Create" +msgstr "Luo" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:41 +msgid "Show more... (" +msgstr "Näytä lisää... (" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:41 +msgid "remaining)" +msgstr "jäljellä)" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:59 +msgid "" +msgstr "" diff --git a/addons/web_kanban/i18n/it.po b/addons/web_kanban/i18n/it.po new file mode 100644 index 00000000000..a60e238f39f --- /dev/null +++ b/addons/web_kanban/i18n/it.po @@ -0,0 +1,53 @@ +# Italian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-02-16 21:57+0000\n" +"Last-Translator: Davide Corio - agilebg.com \n" +"Language-Team: Italian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:10 +msgid "Kanban" +msgstr "Kanban" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:294 +msgid "Undefined" +msgstr "Non definito" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:469 +msgid "Are you sure you want to delete this record ?" +msgstr "Sicuro di voler eliminare questo record?" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:5 +msgid "Create" +msgstr "Crea" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:41 +msgid "Show more... (" +msgstr "Mostra altro... (" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:41 +msgid "remaining)" +msgstr "rimanenti)" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:59 +msgid "" +msgstr "" diff --git a/addons/web_kanban/i18n/ja.po b/addons/web_kanban/i18n/ja.po new file mode 100644 index 00000000000..e5c5afdf5ac --- /dev/null +++ b/addons/web_kanban/i18n/ja.po @@ -0,0 +1,55 @@ +# Japanese translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-03-06 06:35+0000\n" +"Last-Translator: Masaki Yamaya \n" +"Language-Team: Japanese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-07 05:38+0000\n" +"X-Generator: Launchpad (build 14907)\n" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:10 +msgid "Kanban" +msgstr "看板" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:294 +#: addons/web_kanban/static/src/js/kanban.js:295 +msgid "Undefined" +msgstr "未定義" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:469 +#: addons/web_kanban/static/src/js/kanban.js:470 +msgid "Are you sure you want to delete this record ?" +msgstr "このレコードを削除しますか?" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:5 +msgid "Create" +msgstr "作成" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:41 +msgid "Show more... (" +msgstr "もっと表示する…(" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:41 +msgid "remaining)" +msgstr "残り)" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:59 +msgid "" +msgstr "" diff --git a/addons/web_kanban/i18n/ka.po b/addons/web_kanban/i18n/ka.po new file mode 100644 index 00000000000..ae539dda360 --- /dev/null +++ b/addons/web_kanban/i18n/ka.po @@ -0,0 +1,55 @@ +# Georgian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-03-15 19:02+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Georgian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-16 05:14+0000\n" +"X-Generator: Launchpad (build 14951)\n" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:10 +msgid "Kanban" +msgstr "კანბანი" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:294 +#: addons/web_kanban/static/src/js/kanban.js:295 +msgid "Undefined" +msgstr "განუსაზღვრელი" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:469 +#: addons/web_kanban/static/src/js/kanban.js:470 +msgid "Are you sure you want to delete this record ?" +msgstr "ნამდვილად გსურთ აღნიშნული ჩანაწერის წაშლა?" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:5 +msgid "Create" +msgstr "შექმნა" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:41 +msgid "Show more... (" +msgstr "გამოაჩინე მეტი... (" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:41 +msgid "remaining)" +msgstr "დარჩენილი)" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:59 +msgid "" +msgstr "" diff --git a/addons/web_kanban/i18n/pl.po b/addons/web_kanban/i18n/pl.po new file mode 100644 index 00000000000..b9db4ba185d --- /dev/null +++ b/addons/web_kanban/i18n/pl.po @@ -0,0 +1,53 @@ +# Polish translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-02-28 11:13+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Polish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-02-29 04:54+0000\n" +"X-Generator: Launchpad (build 14874)\n" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:10 +msgid "Kanban" +msgstr "" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:294 +msgid "Undefined" +msgstr "Niezdefiniowane" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:469 +msgid "Are you sure you want to delete this record ?" +msgstr "Jesteś pewien, że chcesz usunąć ten rekord?" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:5 +msgid "Create" +msgstr "Utwórz" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:41 +msgid "Show more... (" +msgstr "Pokaż więcej...(" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:41 +msgid "remaining)" +msgstr "pozostało)" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:59 +msgid "" +msgstr "" diff --git a/addons/web_kanban/i18n/pt.po b/addons/web_kanban/i18n/pt.po index caae21d78e7..1edd74960d1 100644 --- a/addons/web_kanban/i18n/pt.po +++ b/addons/web_kanban/i18n/pt.po @@ -14,8 +14,8 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-16 05:21+0000\n" -"X-Generator: Launchpad (build 14781)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web_kanban/static/src/js/kanban.js:10 diff --git a/addons/web_kanban/i18n/ro.po b/addons/web_kanban/i18n/ro.po new file mode 100644 index 00000000000..c07b5c7f6d0 --- /dev/null +++ b/addons/web_kanban/i18n/ro.po @@ -0,0 +1,55 @@ +# Romanian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-03-10 13:21+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Romanian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-11 04:56+0000\n" +"X-Generator: Launchpad (build 14914)\n" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:10 +msgid "Kanban" +msgstr "" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:294 +#: addons/web_kanban/static/src/js/kanban.js:295 +msgid "Undefined" +msgstr "Nedefinit" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:469 +#: addons/web_kanban/static/src/js/kanban.js:470 +msgid "Are you sure you want to delete this record ?" +msgstr "" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:5 +msgid "Create" +msgstr "Crează" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:41 +msgid "Show more... (" +msgstr "" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:41 +msgid "remaining)" +msgstr "" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:59 +msgid "" +msgstr "" diff --git a/addons/web_kanban/i18n/ru.po b/addons/web_kanban/i18n/ru.po new file mode 100644 index 00000000000..5b8781d5bc2 --- /dev/null +++ b/addons/web_kanban/i18n/ru.po @@ -0,0 +1,53 @@ +# Russian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-14 15:27+0100\n" +"PO-Revision-Date: 2012-02-17 07:42+0000\n" +"Last-Translator: Aleksei Motsik \n" +"Language-Team: Russian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-02-18 05:18+0000\n" +"X-Generator: Launchpad (build 14814)\n" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:10 +msgid "Kanban" +msgstr "Kanban" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:294 +msgid "Undefined" +msgstr "Не определено" + +#. openerp-web +#: addons/web_kanban/static/src/js/kanban.js:469 +msgid "Are you sure you want to delete this record ?" +msgstr "Вы действительно хотите удалить эту запись?" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:5 +msgid "Create" +msgstr "Создать" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:41 +msgid "Show more... (" +msgstr "Показать больше... (" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:41 +msgid "remaining)" +msgstr "осталось)" + +#. openerp-web +#: addons/web_kanban/static/src/xml/web_kanban.xml:59 +msgid "" +msgstr "" diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index 49964ed611a..2993954e3aa 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -176,7 +176,7 @@ openerp.web_kanban.KanbanView = openerp.web.View.extend({ }, do_clear_groups: function() { _.each(this.groups, function(group) { - group.stop(); + group.destroy(); }); this.groups = []; this.$element.find('.oe_kanban_groups_headers, .oe_kanban_groups_records').empty(); @@ -276,14 +276,15 @@ openerp.web_kanban.KanbanGroup = openerp.web.OldWidget.extend({ if (this.group) { this.value = group.value; this.title = group.value; + if (this.value instanceof Array) { + this.title = this.value[1]; + this.value = this.value[0]; + } var field = this.view.fields_view.fields[this.view.group_by]; if (field) { try { - this.title = openerp.web.format_value(this.value, field, false); + this.title = openerp.web.format_value(group.value, field, false); } catch(e) {} - } else if (this.value instanceof Array) { - this.title = this.value[1]; - this.value = this.value[0]; } _.each(this.view.aggregates, function(value, key) { self.aggregates[value] = group.aggregates[key]; @@ -327,7 +328,7 @@ openerp.web_kanban.KanbanGroup = openerp.web.OldWidget.extend({ this.$has_been_started.resolve(); return def; }, - stop: function() { + destroy: function() { this._super(); if (this.$records) { this.$records.remove(); @@ -469,7 +470,7 @@ openerp.web_kanban.KanbanRecord = openerp.web.OldWidget.extend({ if (confirm(_t("Are you sure you want to delete this record ?"))) { return $.when(this.view.dataset.unlink([this.id])).then(function() { self.group.remove_record(self.id); - self.stop(); + self.destroy(); }); } }, @@ -520,7 +521,7 @@ openerp.web_kanban.KanbanRecord = openerp.web.OldWidget.extend({ self.set_record(records[0]); self.do_render(); } else { - self.stop(); + self.destroy(); } }); }, diff --git a/addons/web_mobile/__openerp__.py b/addons/web_mobile/__openerp__.py index 03526288cf6..ce76361f619 100644 --- a/addons/web_mobile/__openerp__.py +++ b/addons/web_mobile/__openerp__.py @@ -7,5 +7,5 @@ """, "version" : "2.0", "depends" : [], - 'active': True, + 'auto_install': True, } diff --git a/addons/web_mobile/i18n/es_CR.po b/addons/web_mobile/i18n/es_CR.po index e7197b088e7..9677bdff8cb 100644 --- a/addons/web_mobile/i18n/es_CR.po +++ b/addons/web_mobile/i18n/es_CR.po @@ -8,15 +8,16 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2012-02-07 10:13+0100\n" -"PO-Revision-Date: 2012-02-08 02:31-0600\n" -"Last-Translator: Carlos Vásquez - CLEARCORP \n" +"PO-Revision-Date: 2012-02-16 21:38+0000\n" +"Last-Translator: Carlos Vásquez (CLEARCORP) " +"\n" "Language-Team: Spanish \n" -"Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-08 06:39+0000\n" -"X-Generator: Launchpad (build 14747)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" +"Language: es\n" #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:17 @@ -87,7 +88,8 @@ msgstr "Abrir este recurso" #: addons/web_mobile/static/src/xml/web_mobile.xml:223 #: addons/web_mobile/static/src/xml/web_mobile.xml:226 msgid "Percent of tasks closed according to total of tasks to do..." -msgstr "Porcentaje de tareas cerradas respecto al total de tareas por hacer..." +msgstr "" +"Porcentaje de tareas cerradas respecto al total de tareas por hacer..." #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:264 @@ -105,4 +107,3 @@ msgstr "Apagar" #: addons/web_mobile/static/src/xml/web_mobile.xml:294 msgid "Form View" msgstr "Vista Formulario" - diff --git a/addons/web_mobile/i18n/fi.po b/addons/web_mobile/i18n/fi.po new file mode 100644 index 00000000000..a9eec29a572 --- /dev/null +++ b/addons/web_mobile/i18n/fi.po @@ -0,0 +1,106 @@ +# Finnish translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-07 10:13+0100\n" +"PO-Revision-Date: 2012-03-19 11:54+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Finnish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-20 05:13+0000\n" +"X-Generator: Launchpad (build 14969)\n" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:17 +msgid "OpenERP" +msgstr "OpenERP" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:22 +msgid "Database:" +msgstr "Tietokanta:" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:30 +msgid "Login:" +msgstr "Käyttäjätunnus:" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:32 +msgid "Password:" +msgstr "Salasana:" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:34 +msgid "Login" +msgstr "Kirjaudu" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:36 +msgid "Bad username or password" +msgstr "Virheellinen käyttäjätunnus tai salasana" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:42 +msgid "Powered by openerp.com" +msgstr "openerp.com mahdollistaa" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:49 +msgid "Home" +msgstr "Alkuun" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:57 +msgid "Favourite" +msgstr "Suosikki" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:58 +msgid "Preference" +msgstr "Preferenssi" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:123 +msgid "Logout" +msgstr "Kirjaudu ulos" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:132 +msgid "There are no records to show." +msgstr "Ei näytettäviä tietueita" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:183 +msgid "Open this resource" +msgstr "Avaa tämä resurssi" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:223 +#: addons/web_mobile/static/src/xml/web_mobile.xml:226 +msgid "Percent of tasks closed according to total of tasks to do..." +msgstr "Suljettujen tehtävien prosenttiosuus tehtävien kokonaismäärästä..." + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:264 +#: addons/web_mobile/static/src/xml/web_mobile.xml:268 +msgid "On" +msgstr "Päällä" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:265 +#: addons/web_mobile/static/src/xml/web_mobile.xml:269 +msgid "Off" +msgstr "Pois päältä" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:294 +msgid "Form View" +msgstr "Lomakenäkymä" diff --git a/addons/web_mobile/i18n/it.po b/addons/web_mobile/i18n/it.po index 783d5c6840d..7432baf3a3d 100644 --- a/addons/web_mobile/i18n/it.po +++ b/addons/web_mobile/i18n/it.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-07 10:13+0100\n" -"PO-Revision-Date: 2011-10-08 13:44+0000\n" -"Last-Translator: Nicola Riolini - Micronaet \n" +"PO-Revision-Date: 2012-02-16 22:00+0000\n" +"Last-Translator: Davide Corio - agilebg.com \n" "Language-Team: Italian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-08 06:39+0000\n" -"X-Generator: Launchpad (build 14747)\n" +"X-Launchpad-Export-Date: 2012-02-17 05:13+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:17 @@ -50,12 +50,12 @@ msgstr "Username o password errati" #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:42 msgid "Powered by openerp.com" -msgstr "" +msgstr "Powered by openerp.com" #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:49 msgid "Home" -msgstr "" +msgstr "Home" #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:57 @@ -65,7 +65,7 @@ msgstr "Preferito" #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:58 msgid "Preference" -msgstr "" +msgstr "Preferenze" #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:123 @@ -75,32 +75,33 @@ msgstr "Disconnetti" #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:132 msgid "There are no records to show." -msgstr "" +msgstr "Non ci sono record da mostrare." #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:183 msgid "Open this resource" -msgstr "" +msgstr "Apri questa risorsa" #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:223 #: addons/web_mobile/static/src/xml/web_mobile.xml:226 msgid "Percent of tasks closed according to total of tasks to do..." msgstr "" +"Percentuale di task chiusi in base al totale dai test da completare..." #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:264 #: addons/web_mobile/static/src/xml/web_mobile.xml:268 msgid "On" -msgstr "" +msgstr "Sì" #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:265 #: addons/web_mobile/static/src/xml/web_mobile.xml:269 msgid "Off" -msgstr "" +msgstr "No" #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:294 msgid "Form View" -msgstr "" +msgstr "Vista Form" diff --git a/addons/web_mobile/i18n/ka.po b/addons/web_mobile/i18n/ka.po new file mode 100644 index 00000000000..6b44f1673a7 --- /dev/null +++ b/addons/web_mobile/i18n/ka.po @@ -0,0 +1,106 @@ +# Georgian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-07 10:13+0100\n" +"PO-Revision-Date: 2012-03-15 19:04+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Georgian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-16 05:14+0000\n" +"X-Generator: Launchpad (build 14951)\n" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:17 +msgid "OpenERP" +msgstr "" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:22 +msgid "Database:" +msgstr "მონაცემთა ბაზა:" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:30 +msgid "Login:" +msgstr "მომხმარებელი:" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:32 +msgid "Password:" +msgstr "პაროლი:" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:34 +msgid "Login" +msgstr "შესვლა" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:36 +msgid "Bad username or password" +msgstr "არასწორი მომხმარებლის სახელი ან პაროლი" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:42 +msgid "Powered by openerp.com" +msgstr "მხარდაჭერილია openerp.com-ის მიერ" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:49 +msgid "Home" +msgstr "მთავარი" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:57 +msgid "Favourite" +msgstr "ფავორიტი" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:58 +msgid "Preference" +msgstr "პარამეტრები" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:123 +msgid "Logout" +msgstr "გამოსვლა" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:132 +msgid "There are no records to show." +msgstr "ჩანაწერები არ არის" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:183 +msgid "Open this resource" +msgstr "გახსენი ეს რესურსი" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:223 +#: addons/web_mobile/static/src/xml/web_mobile.xml:226 +msgid "Percent of tasks closed according to total of tasks to do..." +msgstr "სულ გასაკეთებელი ამოცანებიდან დახურული ამოცანების პროცენტი" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:264 +#: addons/web_mobile/static/src/xml/web_mobile.xml:268 +msgid "On" +msgstr "ჩართული" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:265 +#: addons/web_mobile/static/src/xml/web_mobile.xml:269 +msgid "Off" +msgstr "გამორთული" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:294 +msgid "Form View" +msgstr "ფორმის ხედი" diff --git a/addons/web_mobile/i18n/ro.po b/addons/web_mobile/i18n/ro.po new file mode 100644 index 00000000000..2491d1ab920 --- /dev/null +++ b/addons/web_mobile/i18n/ro.po @@ -0,0 +1,106 @@ +# Romanian translation for openerp-web +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-02-07 10:13+0100\n" +"PO-Revision-Date: 2012-03-19 23:11+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Romanian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-03-20 05:13+0000\n" +"X-Generator: Launchpad (build 14969)\n" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:17 +msgid "OpenERP" +msgstr "OpenERP" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:22 +msgid "Database:" +msgstr "Bază de date:" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:30 +msgid "Login:" +msgstr "Logare:" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:32 +msgid "Password:" +msgstr "Parolă:" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:34 +msgid "Login" +msgstr "Logare" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:36 +msgid "Bad username or password" +msgstr "Utilizatorul sau parola incorecte" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:42 +msgid "Powered by openerp.com" +msgstr "" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:49 +msgid "Home" +msgstr "Acasă" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:57 +msgid "Favourite" +msgstr "Preferat" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:58 +msgid "Preference" +msgstr "Preferințe" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:123 +msgid "Logout" +msgstr "" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:132 +msgid "There are no records to show." +msgstr "" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:183 +msgid "Open this resource" +msgstr "" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:223 +#: addons/web_mobile/static/src/xml/web_mobile.xml:226 +msgid "Percent of tasks closed according to total of tasks to do..." +msgstr "" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:264 +#: addons/web_mobile/static/src/xml/web_mobile.xml:268 +msgid "On" +msgstr "Pornit" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:265 +#: addons/web_mobile/static/src/xml/web_mobile.xml:269 +msgid "Off" +msgstr "Oprit" + +#. openerp-web +#: addons/web_mobile/static/src/xml/web_mobile.xml:294 +msgid "Form View" +msgstr "Forma afișare" diff --git a/addons/web_mobile/i18n/ru.po b/addons/web_mobile/i18n/ru.po index adc82cd7214..1d7bf82440b 100644 --- a/addons/web_mobile/i18n/ru.po +++ b/addons/web_mobile/i18n/ru.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-02-07 10:13+0100\n" -"PO-Revision-Date: 2012-01-13 11:44+0000\n" +"PO-Revision-Date: 2012-02-17 07:40+0000\n" "Last-Translator: Aleksei Motsik \n" "Language-Team: Russian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-02-08 06:39+0000\n" -"X-Generator: Launchpad (build 14747)\n" +"X-Launchpad-Export-Date: 2012-02-18 05:18+0000\n" +"X-Generator: Launchpad (build 14814)\n" #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:17 @@ -55,7 +55,7 @@ msgstr "На платформе openerp.com" #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:49 msgid "Home" -msgstr "" +msgstr "Домой" #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:57 @@ -80,13 +80,13 @@ msgstr "Нечего показывать." #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:183 msgid "Open this resource" -msgstr "" +msgstr "Открыть этот ресурс" #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:223 #: addons/web_mobile/static/src/xml/web_mobile.xml:226 msgid "Percent of tasks closed according to total of tasks to do..." -msgstr "" +msgstr "Процент закрытых задач от открытых..." #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:264 @@ -103,4 +103,4 @@ msgstr "Откл." #. openerp-web #: addons/web_mobile/static/src/xml/web_mobile.xml:294 msgid "Form View" -msgstr "" +msgstr "В виде формы" diff --git a/addons/web_mobile/static/openerp/dynamics/OpenERPmobile.css b/addons/web_mobile/static/openerp/dynamics/OpenERPmobile.css deleted file mode 100755 index b0a8b6f4e9b..00000000000 --- a/addons/web_mobile/static/openerp/dynamics/OpenERPmobile.css +++ /dev/null @@ -1,1662 +0,0 @@ -/*! - * jQuery Mobile v1.0a3 - * http://jquerymobile.com/ - * - * Copyright 2010, jQuery Project - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - */ -/* -* 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 -*/ - - -/* A ------------------------------------------------------------------------------------------------------------*/ - -.ui-bar-a { - border: 1px solid #2A2A2A; - background: #111111; - color: #ffffff; - font-weight: bold; - text-shadow: 0 -1px 1px #000000; - 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)); - -msfilter: "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 button { - font-family: Helvetica, Arial, sans-serif; -} -.ui-bar-a .ui-link-inherit { - color: #fff; -} -.ui-bar-a .ui-link { - color: #7cc4e7; - font-weight: bold; -} -.ui-body-a { - border: 1px solid #2A2A2A; - background: #222222; - color: #fff; - text-shadow: 0 1px 0 #000; - font-weight: normal; - background-image: -moz-linear-gradient(top, - #666666, - #222222); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #666666), - color-stop(1, #222222)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#666666', EndColorStr='#222222)')"; -} -.ui-body-a, -.ui-body-a input, -.ui-body-a select, -.ui-body-a textarea, -.ui-body-a button { - font-family: Helvetica, Arial, sans-serif; -} -.ui-body-a .ui-link-inherit { - color: #fff; -} -.ui-body-a .ui-link { - color: #2489CE; - font-weight: bold; -} -.ui-br { - border-bottom: 1px solid rgba(130,130,130,.3); -} -.ui-btn-up-a { - border: 1px solid #222; - background: #333333; - font-weight: bold; - color: #fff; - cursor: pointer; - text-shadow: 0 -1px 1px #000; - text-decoration: none; - background-image: -moz-linear-gradient(top, - #555555, - #333333); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #555555), - color-stop(1, #333333)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#555555', EndColorStr='#333333')"; -} -.ui-btn-up-a a.ui-link-inherit { - color: #fff; -} -.ui-btn-hover-a { - border: 1px solid #000; - background: #444444; - font-weight: bold; - color: #fff; - text-shadow: 0 -1px 1px #000; - text-decoration: none; - background-image: -moz-linear-gradient(top, - #666666, - #444444); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #666666), - color-stop(1, #444444)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#666666', EndColorStr='#444444')"; -} -.ui-btn-hover-a a.ui-link-inherit { - color: #fff; -} -.ui-btn-down-a { - border: 1px solid #000; - background: #3d3d3d; - font-weight: bold; - color: #fff; - text-shadow: 0 -1px 1px #000; - background-image: -moz-linear-gradient(top, - #333333, - #5a5a5a); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #333333), - color-stop(1, #5a5a5a)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#333333', EndColorStr='#5a5a5a')"; -} -.ui-btn-down-a a.ui-link-inherit { - color: #fff; -} -.ui-btn-up-a, -.ui-btn-hover-a, -.ui-btn-down-a { - font-family: Helvetica, Arial, sans-serif; -} - - -/* B ------------------------------------------------------------------------------------------------------------*/ - -.ui-bar-b { - border: 1px solid #456f9a; - background: #5e87b0; - color: #fff; - font-weight: bold; - text-shadow: 0 -1px 1px #254f7a; - background-image: -moz-linear-gradient(top, - #81a8ce, - #5e87b0); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #81a8ce), - color-stop(1, #5e87b0)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#81a8ce', EndColorStr='#5e87b0')"; -} -.ui-bar-b, -.ui-bar-b input, -.ui-bar-b select, -.ui-bar-b textarea, -.ui-bar-b button { - font-family: Helvetica, Arial, sans-serif; -} -.ui-bar-b .ui-link-inherit { - color: #fff; -} -.ui-bar-b .ui-link { - color: #7cc4e7; - font-weight: bold; -} - -.ui-body-b { - border: 1px solid #C6C6C6; - background: #cccccc; - color: #333333; - text-shadow: 0 1px 0 #fff; - font-weight: normal; - background-image: -moz-linear-gradient(top, - #e6e6e6, - #cccccc); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #e6e6e6), - color-stop(1, #cccccc)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#e6e6e6', EndColorStr='#cccccc')"; -} -.ui-body-b, -.ui-body-b input, -.ui-body-b select, -.ui-body-b textarea, -.ui-body-b button { - font-family: Helvetica, Arial, sans-serif; -} -.ui-body-b .ui-link-inherit { - color: #333333; -} -.ui-body-b .ui-link { - color: #2489CE; - font-weight: bold; -} -.ui-btn-up-b { - border: 1px solid #145072; - background: #2567ab; - font-weight: bold; - color: #fff; - cursor: pointer; - text-shadow: 0 -1px 1px #145072; - text-decoration: none; - background-image: -moz-linear-gradient(top, - #4e89c5, - #2567ab); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #5f9cc5), - color-stop(1, #396b9e)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#4e89c5', EndColorStr='#2567ab')"; -} -.ui-btn-up-b a.ui-link-inherit { - color: #fff; -} -.ui-btn-hover-b { - border: 1px solid #00516e; - background: #4b88b6; - font-weight: bold; - color: #fff; - text-shadow: 0 -1px 1px #014D68; - background-image: -moz-linear-gradient(top, - #72b0d4, - #4b88b6); - text-decoration: none; - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #72b0d4), - color-stop(1, #4b88b6)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#72b0d4', EndColorStr='#4b88b6')"; -} -.ui-btn-hover-b a.ui-link-inherit { - color: #fff; -} -.ui-btn-down-b { - border: 1px solid #225377; - background: #4e89c5; - font-weight: bold; - color: #fff; - text-shadow: 0 -1px 1px #225377; - background-image: -moz-linear-gradient(top, - #396b9e, - #4e89c5); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #396b9e), - color-stop(1, #4e89c5)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#396b9e', EndColorStr='#4e89c5')"; -} -.ui-btn-down-b a.ui-link-inherit { - color: #fff; -} -.ui-btn-up-b, -.ui-btn-hover-b, -.ui-btn-down-b { - font-family: Helvetica, Arial, sans-serif; -} - - -/* C ------------------------------------------------------------------------------------------------------------*/ - -.ui-bar-c { - border: 1px solid #B3B3B3; - background: #e9eaeb; - color: #3E3E3E; - font-weight: bold; - text-shadow: 0 1px 1px #fff; - background-image: -moz-linear-gradient(top, - #f0f0f0, - #e9eaeb); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #f0f0f0), - color-stop(1, #e9eaeb)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#f0f0f0', EndColorStr='#e9eaeb')"; -} -.ui-bar-c, -.ui-bar-c input, -.ui-bar-c select, -.ui-bar-c textarea, -.ui-bar-c button { - font-family: Helvetica, Arial, sans-serif; -} -.ui-body-c { - border: 1px solid #B3B3B3; - color: #333333; - text-shadow: 0 1px 0 #fff; - background: #f0f0f0; - background-image: -moz-linear-gradient(top, - #eeeeee, - #dddddd); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #eeeeee), - color-stop(1, #dddddd)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#eeeeee', EndColorStr='#dddddd')"; -} -.ui-body-c, -.ui-body-c input, -.ui-body-c select, -.ui-body-c textarea, -.ui-body-c button { - font-family: Helvetica, Arial, sans-serif; -} -.ui-body-c .ui-link-inherit { - color: #333333; -} -.ui-body-c .ui-link { - color: #2489CE; - font-weight: bold; -} - -.ui-btn-up-c { - border: 1px solid #ccc; - background: #eee; - font-weight: bold; - color: #444; - cursor: pointer; - text-shadow: 0 1px 1px #f6f6f6; - text-decoration: none; - background-image: -moz-linear-gradient(top, - #fefefe, - #eeeeee); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #fdfdfd), - color-stop(1, #eeeeee)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fdfdfd', EndColorStr='#eeeeee')"; -} -.ui-btn-up-c a.ui-link-inherit { - color: #2F3E46; -} - -.ui-btn-hover-c { - border: 1px solid #bbb; - background: #dadada; - font-weight: bold; - color: #101010; - text-decoration: none; - text-shadow: 0 1px 1px #fff; - background-image: -moz-linear-gradient(top, - #ededed, - #dadada); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #ededed), - color-stop(1, #dadada)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#ededed', EndColorStr='#dadada')"; -} -.ui-btn-hover-c a.ui-link-inherit { - color: #2F3E46; -} -.ui-btn-down-c { - border: 1px solid #808080; - background: #fdfdfd; - font-weight: bold; - color: #111111; - text-shadow: 0 1px 1px #ffffff; - background-image: -moz-linear-gradient(top, - #eeeeee, - #fdfdfd); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #eeeeee), - color-stop(1, #fdfdfd)); - -msfilter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#eeeeee', EndColorStr='#fdfdfd')"; -} -.ui-btn-down-c a.ui-link-inherit { - color: #2F3E46; -} -.ui-btn-up-c, -.ui-btn-hover-c, -.ui-btn-down-c { - font-family: Helvetica, Arial, sans-serif; -} - - -/* D ------------------------------------------------------------------------------------------------------------*/ - -.ui-bar-d { - border: 1px solid #ccc; - background: #bbb; - color: #333; - text-shadow: 0 1px 0 #eee; - background-image: -moz-linear-gradient(top, - #ddd, - #bbb); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #ddd), - color-stop(1, #bbb)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#dddddd', EndColorStr='#bbbbbb')"; -} -.ui-bar-d, -.ui-bar-d input, -.ui-bar-d select, -.ui-bar-d textarea, -.ui-bar-d button { - font-family: Helvetica, Arial, sans-serif; -} -.ui-bar-d .ui-link-inherit { - color: #333; -} -.ui-bar-d .ui-link { - color: #2489CE; - font-weight: bold; -} -.ui-body-d { - border: 1px solid #ccc; - color: #333333; - text-shadow: 0 1px 0 #fff; - background: #ffffff; -} -.ui-body-d, -.ui-body-d input, -.ui-body-d select, -.ui-body-d textarea, -.ui-body-d button { - font-family: Helvetica, Arial, sans-serif; -} -.ui-body-d .ui-link-inherit { - color: #333333; -} -.ui-body-d .ui-link { - color: #2489CE; - font-weight: bold; -} -.ui-btn-up-d { - border: 1px solid #ccc; - background: #fff; - font-weight: bold; - color: #444; - text-decoration: none; - text-shadow: 0 1px 1px #fff; -} -.ui-btn-up-d a.ui-link-inherit { - color: #333; -} -.ui-btn-hover-d { - border: 1px solid #aaa; - background: #eeeeee; - font-weight: bold; - color: #222; - cursor: pointer; - text-shadow: 0 1px 1px #fff; - text-decoration: none; - background-image: -moz-linear-gradient(top, - #fdfdfd, - #eeeeee); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #fdfdfd), - color-stop(1, #eeeeee)); - -msfilter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fdfdfd', EndColorStr='#eeeeee')"; -} -.ui-btn-hover-d a.ui-link-inherit { - color: #222; -} -.ui-btn-down-d { - border: 1px solid #aaaaaa; - background: #ffffff; - font-weight: bold; - color: #111; - text-shadow: 0 1px 1px #ffffff; - background-image: -moz-linear-gradient(top, - #eeeeee, - #ffffff); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #eeeeee), - color-stop(1, #ffffff)); - -msfilter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#eeeeee', EndColorStr='#ffffff')"; -} -.ui-btn-down-d a.ui-link-inherit { - border: 1px solid #808080; - background: #ced0d2; - font-weight: bold; - color: #111; - text-shadow: none; - background-image: -moz-linear-gradient(top, - #cccccc, - #eeeeee); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #cccccc), - color-stop(1, #eeeeee)); - -msfilter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#cccccc', EndColorStr='#eeeeee')"; -} -.ui-btn-up-d, -.ui-btn-hover-d, -.ui-btn-down-d { - font-family: Helvetica, Arial, sans-serif; -} - - -/* E ------------------------------------------------------------------------------------------------------------*/ - -.ui-bar-e { - border: 1px solid #F7C942; - background: #fadb4e; - color: white; - text-shadow: 0 1px 0 black; - background-image: -moz-linear-gradient(top, - #990000, - #cccccc); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #fceda7), - color-stop(1, #fadb4e)); - -msfilter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fceda7', EndColorStr='#fadb4e')"; -} -.ui-bar-e, -.ui-bar-e input, -.ui-bar-e select, -.ui-bar-e textarea, -.ui-bar-d button { - font-family: Helvetica, Arial, sans-serif; -} -.ui-bar-e .ui-link-inherit { - color: #333; -} -.ui-bar-e .ui-link { - color: #2489CE; - font-weight: bold; -} -.ui-body-e { - border: 1px solid #F7C942; - color: #333333; - text-shadow: 0 1px 0 #fff; - background: #faeb9e; - background-image: -moz-linear-gradient(top, - #fff, - #faeb9e); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #fff), - color-stop(1, #faeb9e)); - -msfilter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffffff', EndColorStr='#faeb9e')"; -} -.ui-body-e, -.ui-body-e input, -.ui-body-e select, -.ui-body-e textarea, -.ui-body-e button { - font-family: Helvetica, Arial, sans-serif; -} -.ui-body-e .ui-link-inherit { - color: #333333; -} -.ui-body-e .ui-link { - color: #2489CE; - font-weight: bold; -} -.ui-btn-up-e { - border: 1px solid #F7C942; - background: #fadb4e; - font-weight: bold; - color: #333; - cursor: pointer; - text-shadow: 0 1px 1px #fe3; - text-decoration: none; - text-shadow: 0 1px 0 #fff; - background-image: -moz-linear-gradient(top, - #fceda7, - #fadb4e); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #fceda7), - color-stop(1, #fadb4e)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fceda7', EndColorStr='#fadb4e')"; -} -.ui-btn-up-e a.ui-link-inherit { - color: #333; -} -.ui-btn-hover-e { - border: 1px solid #e79952; - background: #fbe26f; - font-weight: bold; - color: #111; - text-decoration: none; - text-shadow: 0 1px 1px #fff; - background-image: -moz-linear-gradient(top, - #fcf0b5, - #fbe26f); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #fcf0b5), - color-stop(1, #fbe26f)); - -msfilter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fcf0b5', EndColorStr='#fbe26f')"; -} - -.ui-btn-hover-e a.ui-link-inherit { - color: #333; -} -.ui-btn-down-e { - border: 1px solid #F7C942; - background: #fceda7; - font-weight: bold; - color: #111; - text-shadow: 0 1px 1px #ffffff; - background-image: -moz-linear-gradient(top, - #fadb4e, - #fceda7); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #fadb4e), - color-stop(1, #fceda7)); - -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fadb4e', EndColorStr='#fceda7')"; -} -.ui-btn-down-e a.ui-link-inherit { - color: #333; -} -.ui-btn-up-e, -.ui-btn-hover-e, -.ui-btn-down-e { - font-family: Helvetica, Arial, sans-serif; -} - - -/* links within "buttons" ------------------------------------------------------------------------------------------------------------*/ - -a.ui-link-inherit { - text-decoration: none !important; -} - - -/* Active class used as the "on" state across all themes ------------------------------------------------------------------------------------------------------------*/ - -.ui-btn-active { - border: 1px solid #155678; - background: #4596ce; - font-weight: bold; - color: #fff; - cursor: pointer; - text-shadow: 0 -1px 1px #145072; - text-decoration: none; - background-image: -moz-linear-gradient(top, - #85bae4, - #5393c5); - background-image: -webkit-gradient(linear,left top,left bottom, - color-stop(0, #85bae4), - color-stop(1, #5393c5)); - -msfilter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#85bae4', EndColorStr='#5393c5')"; - outline: none; -} -.ui-btn-active a.ui-link-inherit { - color: #fff; -} - - -/* button inner top highlight ------------------------------------------------------------------------------------------------------------*/ - -.ui-btn-inner { - border-top: 1px solid #fff; - border-color: rgba(255,255,255,.3); -} - - -/* corner rounding classes ------------------------------------------------------------------------------------------------------------*/ - -.ui-corner-tl { - -moz-border-radius-topleft: .6em; - -webkit-border-top-left-radius: .6em; - border-top-left-radius: .6em; -} -.ui-corner-tr { - -moz-border-radius-topright: .6em; - -webkit-border-top-right-radius: .6em; - border-top-right-radius: .6em; -} -.ui-corner-bl { - -moz-border-radius-bottomleft: .6em; - -webkit-border-bottom-left-radius: .6em; - border-bottom-left-radius: .6em; -} -.ui-corner-br { - -moz-border-radius-bottomright: .6em; - -webkit-border-bottom-right-radius: .6em; - border-bottom-right-radius: .6em; -} -.ui-corner-top { - -moz-border-radius-topleft: .6em; - -webkit-border-top-left-radius: .6em; - border-top-left-radius: .6em; - -moz-border-radius-topright: .6em; - -webkit-border-top-right-radius: .6em; - border-top-right-radius: .6em; -} -.ui-corner-bottom { - -moz-border-radius-bottomleft: .6em; - -webkit-border-bottom-left-radius: .6em; - border-bottom-left-radius: .6em; - -moz-border-radius-bottomright: .6em; - -webkit-border-bottom-right-radius: .6em; - border-bottom-right-radius: .6em; - } -.ui-corner-right { - -moz-border-radius-topright: .6em; - -webkit-border-top-right-radius: .6em; - border-top-right-radius: .6em; - -moz-border-radius-bottomright: .6em; - -webkit-border-bottom-right-radius: .6em; - border-bottom-right-radius: .6em; -} -.ui-corner-left { - -moz-border-radius-topleft: .6em; - -webkit-border-top-left-radius: .6em; - border-top-left-radius: .6em; - -moz-border-radius-bottomleft: .6em; - -webkit-border-bottom-left-radius: .6em; - border-bottom-left-radius: .6em; -} -.ui-corner-all { - -moz-border-radius: .6em; - -webkit-border-radius: .6em; - border-radius: .6em; -} - - - -/* Interaction cues ------------------------------------------------------------------------------------------------------------*/ -.ui-disabled { - opacity: .3; -} -.ui-disabled, -.ui-disabled a { - cursor: default !important; -} - -/* Icons ------------------------------------------------------------------------------------------------------------*/ - -.ui-icon { - background-image: url(images/icons-18-white.png); - background-repeat: no-repeat; - background-color: #666; - background-color: rgba(0,0,0,.4); - -moz-border-radius: 9px; - -webkit-border-radius: 9px; - border-radius: 9px; -} -.ui-icon-disc { - background-color: #666; - background-color: rgba(0,0,0,.3); - -moz-border-radius: 9px; - -webkit-border-radius: 9px; - border-radius: 9px; -} - -/* Alt icon color ------------------------------------------------------------------------------------------------------------*/ - -.ui-icon-black { - background-image: url(images/icons-18-black.png); -} -.ui-icon-black-disc { - background-color: #fff; - background-color: rgba(255,255,255,.3); - -moz-border-radius: 9px; - -webkit-border-radius: 9px; - border-radius: 9px; -} - -/* HD/"retina" sprite ------------------------------------------------------------------------------------------------------------*/ - -@media screen and (-webkit-min-device-pixel-ratio: 2), screen and (max--moz-device-pixel-ratio: 2) { - .ui-icon { - background-image: url(images/icons-36-white.png); - background-size: 630px 18px; -} - .ui-icon-black { - background-image: url(images/icons-36-black.png); -} -} - -/* plus minus */ -.ui-icon-plus { - background-position: -0 0; -} -.ui-icon-minus { - background-position: -36px 0; -} - -/* delete/close */ -.ui-icon-delete { - background-position: -72px 0; -} - -/* arrows */ -.ui-icon-arrow-r { - background-position: -108px 0; -} -.ui-icon-arrow-l { - background-position: -144px 0; -} -.ui-icon-arrow-u { - background-position: -180px 0; -} -.ui-icon-arrow-d { - background-position: -216px 0; -} - -/* misc */ -.ui-icon-check { - background-position: -252px 0; -} -.ui-icon-gear { - background-position: -288px 0; -} -.ui-icon-refresh { - background-position: -324px 0; -} -.ui-icon-forward { - background-position: -360px 0; -} -.ui-icon-back { - background-position: -396px 0; -} -.ui-icon-grid { - background-position: -432px 0; -} -.ui-icon-star { - background-position: -468px 0; -} -.ui-icon-alert { - background-position: -504px 0; -} -.ui-icon-info { - background-position: -540px 0; -} -.ui-icon-home { - background-position: -576px 0; -} -.ui-icon-search { - background-position: -612px 0; -} - - -/* checks,radios */ -.ui-icon-checkbox-off, -.ui-icon-checkbox-on, -.ui-icon-radio-off, -.ui-icon-radio-on { - background-color: transparent; - -moz-border-radius: 0; - -webkit-border-radius: 0; - border-radius: 0; - background-size: 20px 20px; -} -.ui-icon-checkbox-off { - background-image: url(images/form-check-off.png); -} -.ui-icon-checkbox-on { - background-image: url(images/form-check-on.png); -} -.ui-icon-radio-off { - background-image: url(images/form-radio-off.png);} -.ui-icon-radio-on { - background-image: url(images/form-radio-on.png); -} -.ui-icon-searchfield { - background-image: url(images/icon-search-black.png); - background-size: 16px 16px; -} -.ui-icon-save { - background-image: url(images/icone-save.png); - background-size: 16px 16px; -} -.ui-icon-folder { - background-image: url(images/icone-folder.png); - background-size: 16px 16px; -} - -/* loading icon */ -.ui-icon-loading { - background-image: url(images/ajax-loader.png); - width: 40px; - height: 40px; - -moz-border-radius: 20px; - -webkit-border-radius: 20px; - border-radius: 20px; - background-size: 35px 35px; -} - - -/* Button corner classes ------------------------------------------------------------------------------------------------------------*/ - -.ui-btn-corner-tl { - -moz-border-radius-topleft: 1em; - -webkit-border-top-left-radius: 1em; - border-top-left-radius: 1em; -} -.ui-btn-corner-tr { - -moz-border-radius-topright: 1em; - -webkit-border-top-right-radius: 1em; - border-top-right-radius: 1em; -} -.ui-btn-corner-bl { - -moz-border-radius-bottomleft: 1em; - -webkit-border-bottom-left-radius: 1em; - border-bottom-left-radius: 1em; -} -.ui-btn-corner-br { - -moz-border-radius-bottomright: 1em; - -webkit-border-bottom-right-radius: 1em; - border-bottom-right-radius: 1em; -} -.ui-btn-corner-top { - -moz-border-radius-topleft: 1em; - -webkit-border-top-left-radius: 1em; - border-top-left-radius: 1em; - -moz-border-radius-topright: 1em; - -webkit-border-top-right-radius: 1em; - border-top-right-radius: 1em; -} -.ui-btn-corner-bottom { - -moz-border-radius-bottomleft: 1em; - -webkit-border-bottom-left-radius: 1em; - border-bottom-left-radius: 1em; - -moz-border-radius-bottomright: 1em; - -webkit-border-bottom-right-radius: 1em; - border-bottom-right-radius: 1em; -} -.ui-btn-corner-right { - -moz-border-radius-topright: 1em; - -webkit-border-top-right-radius: 1em; - border-top-right-radius: 1em; - -moz-border-radius-bottomright: 1em; - -webkit-border-bottom-right-radius: 1em; - border-bottom-right-radius: 1em; -} -.ui-btn-corner-left { - -moz-border-radius-topleft: 1em; - -webkit-border-top-left-radius: 1em; - border-top-left-radius: 1em; - -moz-border-radius-bottomleft: 1em; - -webkit-border-bottom-left-radius: 1em; - border-bottom-left-radius: 1em; -} -.ui-btn-corner-all { - -moz-border-radius: 1em; - -webkit-border-radius: 1em; - border-radius: 1em; -} - -/* radius clip workaround for cleaning up corner trapping */ -.ui-corner-tl, -.ui-corner-tr, -.ui-corner-bl, -.ui-corner-br, -.ui-corner-top, -.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-br, -.ui-btn-corner-top, -.ui-btn-corner-bottom, -.ui-btn-corner-right, -.ui-btn-corner-left, -.ui-btn-corner-all { - -webkit-background-clip: padding-box; - -moz-background-clip: padding-box; - background-clip: padding-box; -} - -/* Overlay / modal ------------------------------------------------------------------------------------------------------------*/ - -.ui-overlay { - background: #666; - opacity: .5; - filter: Alpha(Opacity=50); - position: absolute; - width: 100%; - height: 100%; -} -.ui-overlay-shadow { - -moz-box-shadow: 0px 0px 12px rgba(0,0,0,.6); - -webkit-box-shadow: 0px 0px 12px rgba(0,0,0,.6); - box-shadow: 0px 0px 12px rgba(0,0,0,.6); -} -.ui-shadow { - -moz-box-shadow: 0px 1px 4px rgba(0,0,0,.3); - -webkit-box-shadow: 0px 1px 4px rgba(0,0,0,.3); - box-shadow: 0px 1px 4px rgba(0,0,0,.3); -} -.ui-bar-a .ui-shadow, -.ui-bar-b .ui-shadow , -.ui-bar-c .ui-shadow { - -moz-box-shadow: 0px 1px 0 rgba(255,255,255,.3); - -webkit-box-shadow: 0px 1px 0 rgba(255,255,255,.3); - box-shadow: 0px 1px 0 rgba(255,255,255,.3); -} -.ui-shadow-inset { - -moz-box-shadow: inset 0px 1px 4px rgba(0,0,0,.2); - -webkit-box-shadow: inset 0px 1px 4px rgba(0,0,0,.2); - box-shadow: inset 0px 1px 4px rgba(0,0,0,.2); -} -.ui-icon-shadow { - -moz-box-shadow: 0px 1px 0 rgba(255,255,255,.4); - -webkit-box-shadow: 0px 1px 0 rgba(255,255,255,.4); - box-shadow: 0px 1px 0 rgba(255,255,255,.4); -} - - -/* Focus state - set here for specificity ------------------------------------------------------------------------------------------------------------*/ - -.ui-focus { - -moz-box-shadow: 0px 0px 12px #387bbe; - -webkit-box-shadow: 0px 0px 12px #387bbe; - box-shadow: 0px 0px 12px #387bbe; -} - -/* unset box shadow in browsers that don't do it right ------------------------------------------------------------------------------------------------------------*/ - -.ui-mobile-nosupport-boxshadow * { - -moz-box-shadow: none !important; - -webkit-box-shadow: none !important; - box-shadow: none !important; -} - -/* ...and bring back focus */ -.ui-mobile-nosupport-boxshadow .ui-focus { - outline-width: 2px; -}/* -* 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 -*/ - -/* some unsets - more probably needed */ -.ui-mobile fieldset, .ui-page { padding: 0; margin: 0; } -.ui-mobile a img, .ui-mobile fieldset { border: 0; } - -/* responsive page widths */ -.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 .ui-page-active { display: block; overflow: visible; } - -/*orientations from js are available */ -.portrait, -.portrait .ui-page { min-height: 480px; } -.landscape, -.landscape .ui-page { min-height: 320px; } - -/* loading screen */ -.ui-loading .ui-mobile-viewport { overflow: hidden !important; } -.ui-loading .ui-loader { display: block; } -.ui-loading .ui-page { overflow: hidden; } -.ui-loader { display: none; position: absolute; opacity: .85; z-index: 10; left: 50%; width: 200px; margin-left: -130px; margin-top: -35px; padding: 10px 30px; } -.ui-loader h1 { font-size: 15px; text-align: center; } -.ui-loader .ui-icon { position: static; display: block; opacity: .9; margin: 0 auto; width: 35px; height: 35px; background-color: transparent; } - -/*fouc*/ -.ui-mobile-rendering > * { visibility: hidden; } - -/*headers, content panels*/ -.ui-bar, .ui-body { position: relative; padding: .4em 15px; overflow: hidden; display: block; clear:both; } -.ui-bar { font-size: 16px; margin: 0; } -.ui-bar h1, .ui-bar h2, .ui-bar h3, .ui-bar h4, .ui-bar h5, .ui-bar h6 { margin: 0; padding: 0; font-size: 16px; display: inline-block; } - -.ui-header, .ui-footer { display: block; } -.ui-page .ui-header, .ui-page .ui-footer { position: relative; } -.ui-header .ui-btn-left { position: absolute; left: 10px; top: .4em; } -.ui-header .ui-title, .ui-footer .ui-title { text-align: center; font-size: 16px; display: block; margin: .6em 90px .8em; padding: 0; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; outline: 0 !important; } -.ui-header .ui-btn-right { position: absolute; right: 10px; top: .4em; } -.ui-header .ui-btn-right-bis { position: absolute; right: 50px; top: .4em; } -.ui-header .ui-btn-right-bis2 { position: absolute; left: 50px; top: .4em} - -/*content area*/ -.ui-content { border-width: 0; overflow: visible; overflow-x: hidden; padding: 15px; } -.ui-page-fullscreen .ui-content { padding:0; } - -/* icons sizing */ -.ui-icon { width: 18px; height: 18px; } - -/* fullscreen class on ui-content div */ -.ui-fullscreen { } -.ui-fullscreen img { max-width: 100%; } - -/* non-js content hiding */ -.ui-nojs { position: absolute; left: -9999px; } -/* -* jQuery Mobile Framework -* Copyright (c) jQuery Project -* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses. -*/ -.spin { - -webkit-transform: rotate(360deg); - -webkit-animation-name: spin; - -webkit-animation-duration: 1s; - -webkit-animation-iteration-count: infinite; -} -@-webkit-keyframes spin { - from {-webkit-transform: rotate(0deg);} - to {-webkit-transform: rotate(360deg);} -} - -/* Transitions from jQtouch (with small modifications): http://www.jqtouch.com/ -Built by David Kaneda and maintained by Jonathan Stark. -*/ -.in, .out { - -webkit-animation-timing-function: ease-in-out; - -webkit-animation-duration: 350ms; -} - -.slide.in { - -webkit-transform: translateX(0); - -webkit-animation-name: slideinfromright; -} - -.slide.out { - -webkit-transform: translateX(-100%); - -webkit-animation-name: slideouttoleft; -} - -.slide.in.reverse { - -webkit-transform: translateX(0); - -webkit-animation-name: slideinfromleft; -} - -.slide.out.reverse { - -webkit-transform: translateX(100%); - -webkit-animation-name: slideouttoright; -} - -.slideup.in { - -webkit-transform: translateY(0); - -webkit-animation-name: slideinfrombottom; - z-index: 10; -} - -.slideup.out { - -webkit-animation-name: dontmove; - z-index: 0; -} - -.slideup.out.reverse { - -webkit-transform: translateY(100%); - z-index: 10; - -webkit-animation-name: slideouttobottom; -} - -.slideup.in.reverse { - z-index: 0; - -webkit-animation-name: dontmove; -} -.slidedown.in { - -webkit-transform: translateY(0); - -webkit-animation-name: slideinfromtop; - z-index: 10; -} - -.slidedown.out { - -webkit-animation-name: dontmove; - z-index: 0; -} - -.slidedown.out.reverse { - -webkit-transform: translateY(-100%); - z-index: 10; - -webkit-animation-name: slideouttotop; -} - -.slidedown.in.reverse { - z-index: 0; - -webkit-animation-name: dontmove; -} - -@-webkit-keyframes slideinfromright { - from { -webkit-transform: translateX(100%); } - to { -webkit-transform: translateX(0); } -} - -@-webkit-keyframes slideinfromleft { - from { -webkit-transform: translateX(-100%); } - to { -webkit-transform: translateX(0); } -} - -@-webkit-keyframes slideouttoleft { - from { -webkit-transform: translateX(0); } - to { -webkit-transform: translateX(-100%); } -} - -@-webkit-keyframes slideouttoright { - from { -webkit-transform: translateX(0); } - to { -webkit-transform: translateX(100%); } -} - - -@-webkit-keyframes slideinfromtop { - from { -webkit-transform: translateY(-100%); } - to { -webkit-transform: translateY(0); } -} - -@-webkit-keyframes slideinfrombottom { - from { -webkit-transform: translateY(100%); } - to { -webkit-transform: translateY(0); } -} - -@-webkit-keyframes slideouttobottom { - from { -webkit-transform: translateY(0); } - to { -webkit-transform: translateY(100%); } -} - -@-webkit-keyframes slideouttotop { - from { -webkit-transform: translateY(0); } - to { -webkit-transform: translateY(-100%); } -} -@-webkit-keyframes fadein { - from { opacity: 0; } - to { opacity: 1; } -} - -@-webkit-keyframes fadeout { - from { opacity: 1; } - to { opacity: 0; } -} - -.fade.in { - opacity: 1; - z-index: 10; - -webkit-animation-name: fadein; -} -.fade.out { - z-index: 0; - -webkit-animation-name: fadeout; -} - -/* The properties in this body rule are only necessary for the 'flip' transition. - * We need specify the perspective to create a projection matrix. This will add - * some depth as the element flips. The depth number represents the distance of - * the viewer from the z-plane. According to the CSS3 spec, 1000 is a moderate - * value. - */ -.ui-mobile-viewport-perspective { - -webkit-perspective: 1000; - position: absolute; -} - -.ui-mobile-viewport-transitioning, -.ui-mobile-viewport-transitioning .ui-page { - width: 100%; - height: 100%; - overflow: hidden; -} - -.flip { - -webkit-animation-duration: .65s; - -webkit-backface-visibility:hidden; - -webkit-transform:translateX(0); /* Needed to work around an iOS 3.1 bug that causes listview thumbs to disappear when -webkit-visibility:hidden is used. */ -} - -.flip.in { - -webkit-transform: rotateY(0) scale(1); - -webkit-animation-name: flipinfromleft; -} - -.flip.out { - -webkit-transform: rotateY(-180deg) scale(.8); - -webkit-animation-name: flipouttoleft; -} - -/* Shake it all about */ - -.flip.in.reverse { - -webkit-transform: rotateY(0) scale(1); - -webkit-animation-name: flipinfromright; -} - -.flip.out.reverse { - -webkit-transform: rotateY(180deg) scale(.8); - -webkit-animation-name: flipouttoright; -} - -@-webkit-keyframes flipinfromright { - from { -webkit-transform: rotateY(-180deg) scale(.8); } - to { -webkit-transform: rotateY(0) scale(1); } -} - -@-webkit-keyframes flipinfromleft { - from { -webkit-transform: rotateY(180deg) scale(.8); } - to { -webkit-transform: rotateY(0) scale(1); } -} - -@-webkit-keyframes flipouttoleft { - from { -webkit-transform: rotateY(0) scale(1); } - to { -webkit-transform: rotateY(-180deg) scale(.8); } -} - -@-webkit-keyframes flipouttoright { - from { -webkit-transform: rotateY(0) scale(1); } - to { -webkit-transform: rotateY(180deg) scale(.8); } -} - - -/* Hackish, but reliable. */ - -@-webkit-keyframes dontmove { - from { opacity: 1; } - to { opacity: 1; } -} - -.pop { - -webkit-transform-origin: 50% 50%; -} - -.pop.in { - -webkit-transform: scale(1); - opacity: 1; - -webkit-animation-name: popin; - z-index: 10; -} - -.pop.out.reverse { - -webkit-transform: scale(.2); - opacity: 0; - -webkit-animation-name: popout; - z-index: 10; -} - -.pop.in.reverse { - z-index: 0; - -webkit-animation-name: dontmove; -} - -@-webkit-keyframes popin { - from { - -webkit-transform: scale(.2); - opacity: 0; - } - to { - -webkit-transform: scale(1); - opacity: 1; - } -} - -@-webkit-keyframes popout { - from { - -webkit-transform: scale(1); - opacity: 1; - } - to { - -webkit-transform: scale(.2); - opacity: 0; - } -}/* -* jQuery Mobile Framework -* Copyright (c) jQuery Project -* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses. -*/ - -/* content configurations. */ -.ui-grid-a, .ui-grid-b, .ui-grid-c, .ui-grid-d { overflow: hidden; } -.ui-block-a, .ui-block-b, .ui-block-c, .ui-block-d, .ui-block-e { margin: 0; padding: 0; border: 0; float: left; } - -/* grid a: 50/50 */ -.ui-grid-a .ui-block-a, .ui-grid-a .ui-block-b { width: 50%; } -.ui-grid-a .ui-block-a { clear: left; } - -/* grid b: 33/33/33 */ -.ui-grid-b .ui-block-a, .ui-grid-b .ui-block-b, .ui-grid-b .ui-block-c { width: 33.333%; } -.ui-grid-b .ui-block-a { clear: left; } - -/* grid c: 25/25/25/25 */ -.ui-grid-c .ui-block-a, .ui-grid-c .ui-block-b, .ui-grid-c .ui-block-c, .ui-grid-c .ui-block-d { width: 25%; } -.ui-grid-c .ui-block-a { clear: left; } - -/* grid d: 20/20/20/20/20 */ -.ui-grid-d .ui-block-a, .ui-grid-d .ui-block-b, .ui-grid-d .ui-block-c, .ui-grid-d .ui-block-d, .ui-grid-d .ui-block-e { width: 20%; } -.ui-grid-d .ui-block-a { clear: left; }/* -* jQuery Mobile Framework -* Copyright (c) jQuery Project -* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses. -*/ -/* fixed page header & footer configuration */ -.ui-header, .ui-footer, .ui-page-fullscreen .ui-header, .ui-page-fullscreen .ui-footer { position: absolute; overflow: hidden; width: 100%; border-left-width: 0; border-right-width: 0; } -.ui-header-fixed, .ui-footer-fixed { - z-index: 1000; - -webkit-transform: translateZ(0); /* Force header/footer rendering to go through the same rendering pipeline as native page scrolling. */ -} -.ui-footer-duplicate, .ui-page-fullscreen .ui-fixed-inline { display: none; } -.ui-page-fullscreen .ui-header, .ui-page-fullscreen .ui-footer { opacity: .9; } -/* -* jQuery Mobile Framework -* Copyright (c) jQuery Project -* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses. -*/ -.ui-navbar { overflow: hidden; } -.ui-navbar ul, .ui-navbar-expanded ul { list-style:none; padding: 0; margin: 0; position: relative; display: block; border: 0;} -.ui-navbar-collapsed ul { float: left; width: 75%; margin-right: -2px; } -.ui-navbar-collapsed .ui-navbar-toggle { float: left; width: 25%; } -.ui-navbar li.ui-navbar-truncate { position: absolute; left: -9999px; top: -9999px; } -.ui-navbar li .ui-btn, .ui-navbar .ui-navbar-toggle .ui-btn { display: block; font-size: 12px; text-align: center; margin: 0; border-right-width: 0; } -.ui-navbar li .ui-btn { margin-right: -1px; } -.ui-navbar li .ui-btn:last-child { margin-right: 0; } -.ui-header .ui-navbar li .ui-btn, .ui-header .ui-navbar .ui-navbar-toggle .ui-btn, -.ui-footer .ui-navbar li .ui-btn, .ui-footer .ui-navbar .ui-navbar-toggle .ui-btn { border-top-width: 0; border-bottom-width: 0; } -.ui-navbar .ui-btn-inner { padding-left: 2px; padding-right: 2px; } -.ui-navbar-noicons li .ui-btn .ui-btn-inner, .ui-navbar-noicons .ui-navbar-toggle .ui-btn-inner { padding-top: .8em; padding-bottom: .9em; } -/*expanded page styles*/ -.ui-navbar-expanded .ui-btn { margin: 0; font-size: 14px; } -.ui-navbar-expanded .ui-btn-inner { padding-left: 5px; padding-right: 5px; } -.ui-navbar-expanded .ui-btn-icon-top .ui-btn-inner { padding: 45px 5px 15px; text-align: center; } -.ui-navbar-expanded .ui-btn-icon-top .ui-icon { top: 15px; } -.ui-navbar-expanded .ui-btn-icon-bottom .ui-btn-inner { padding: 15px 5px 45px; text-align: center; } -.ui-navbar-expanded .ui-btn-icon-bottom .ui-icon { bottom: 15px; } -.ui-navbar-expanded li .ui-btn .ui-btn-inner { min-height: 2.5em; } -.ui-navbar-expanded .ui-navbar-noicons .ui-btn .ui-btn-inner { padding-top: 1.8em; padding-bottom: 1.9em; } -/* -* jQuery Mobile Framework -* Copyright (c) jQuery Project -* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses. -*/ -.ui-btn { display: block; text-align: center; cursor:pointer; position: relative; margin: .5em 5px; padding: 0; } -.ui-btn:focus, .ui-btn:active { outline: none; } -.ui-header .ui-btn, .ui-footer .ui-btn, .ui-bar .ui-btn { display: inline-block; font-size: 13px; margin: 0; } -.ui-btn-inline { display: inline-block; } -.ui-btn-inner { padding: .6em 25px; display: block; height: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; position: relative; } -.ui-header .ui-btn-inner, .ui-footer .ui-btn-inner, .ui-bar .ui-btn-inner { padding: .4em 8px .5em; } -.ui-btn-icon-notext { display: inline-block; width: 20px; height: 20px; padding: 2px 1px 2px 3px; text-indent: -9999px; } -.ui-btn-icon-notext .ui-btn-inner { padding: 0; } -.ui-btn-icon-notext .ui-btn-text { position: absolute; left: -999px; } -.ui-btn-icon-left .ui-btn-inner { padding-left: 33px; } -.ui-header .ui-btn-icon-left .ui-btn-inner, -.ui-footer .ui-btn-icon-left .ui-btn-inner, -.ui-bar .ui-btn-icon-left .ui-btn-inner { padding-left: 27px; } -.ui-btn-icon-right .ui-btn-inner { padding-right: 33px; } -.ui-header .ui-btn-icon-right .ui-btn-inner, -.ui-footer .ui-btn-icon-right .ui-btn-inner, -.ui-bar .ui-btn-icon-right .ui-btn-inner { padding-right: 27px; } -.ui-btn-icon-top .ui-btn-inner { padding-top: 33px; } -.ui-header .ui-btn-icon-top .ui-btn-inner, -.ui-footer .ui-btn-icon-top .ui-btn-inner, -.ui-bar .ui-btn-icon-top .ui-btn-inner { padding-top: 27px; } -.ui-btn-icon-bottom .ui-btn-inner { padding-bottom: 33px; } -.ui-header .ui-btn-icon-bottom .ui-btn-inner, -.ui-footer .ui-btn-icon-bottom .ui-btn-inner, -.ui-bar .ui-btn-icon-bottom .ui-btn-inner { padding-bottom: 27px; } - -/*btn icon positioning*/ -.ui-btn-icon-notext .ui-icon { display: block; } -.ui-btn-icon-left .ui-icon, .ui-btn-icon-right .ui-icon { position: absolute; top: 50%; margin-top: -9px; } -.ui-btn-icon-top .ui-icon, .ui-btn-icon-bottom .ui-icon { position: absolute; left: 50%; margin-left: -9px; } -.ui-btn-icon-left .ui-icon { left: 10px; } -.ui-btn-icon-right .ui-icon {right: 10px; } -.ui-header .ui-btn-icon-left .ui-icon, -.ui-footer .ui-btn-icon-left .ui-icon, -.ui-bar .ui-btn-icon-left .ui-icon { left: 4px; } -.ui-header .ui-btn-icon-right .ui-icon, -.ui-footer .ui-btn-icon-right .ui-icon, -.ui-bar .ui-btn-icon-right .ui-icon { right: 4px; } -.ui-header .ui-btn-icon-top .ui-icon, -.ui-footer .ui-btn-icon-top .ui-icon, -.ui-bar .ui-btn-icon-top .ui-icon { top: 4px; } -.ui-header .ui-btn-icon-bottom .ui-icon, -.ui-footer .ui-btn-icon-bottom .ui-icon, -.ui-bar .ui-btn-icon-bottom .ui-icon { bottom: 4px; } -.ui-btn-icon-top .ui-icon { top: 5px; } -.ui-btn-icon-bottom .ui-icon { bottom: 5px; } -/*hiding native button,inputs */ -.ui-btn-hidden { position: absolute; top: 0; left: 0; width: 100%; height: 100%; -webkit-appearance: button; opacity: 0; cursor: pointer; } -/* -* jQuery Mobile Framework -* Copyright (c) jQuery Project -* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses. -*/ -.ui-collapsible-contain { margin: .5em 0; } -.ui-collapsible-heading { font-size: 16px; display: block; margin: 0 -8px; padding: 0; border-width: 0 0 1px 0; position: relative; } -.ui-collapsible-heading a { text-align: left; margin: 0; } -.ui-collapsible-heading a .ui-btn-inner { padding-left: 40px; } -.ui-collapsible-heading a span.ui-btn { position: absolute; left: 6px; top: 50%; margin: -12px 0 0 0; width: 20px; height: 20px; padding: 1px 0px 1px 2px; text-indent: -9999px; } -.ui-collapsible-heading a span.ui-btn .ui-btn-inner { padding: 0; } -.ui-collapsible-heading a span.ui-btn .ui-icon { left: 0; margin-top: -10px; } -.ui-collapsible-heading-status { position:absolute; left:-9999px; } -.ui-collapsible-content { display: block; padding: 10px 0 10px 8px; } -.ui-collapsible-content-collapsed { display: none; } - -.ui-collapsible-set { margin: .5em 0; } -.ui-collapsible-set .ui-collapsible-contain { margin: -1px 0 0; } -/* -* jQuery Mobile Framework -* Copyright (c) jQuery Project -* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses. -*/ -.ui-controlgroup, fieldset.ui-controlgroup { padding: 0; margin: .5em 0 1em; } -.ui-bar .ui-controlgroup { margin: 0 .3em; } -.ui-controlgroup-label { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .3em; } -.ui-controlgroup-controls { display: block; width: 95%;} -.ui-controlgroup li { list-style: none; } -.ui-controlgroup-vertical .ui-btn, -.ui-controlgroup-vertical .ui-checkbox, .ui-controlgroup-vertical .ui-radio { margin: 0; border-bottom-width: 0; } -.ui-controlgroup-vertical .ui-controlgroup-last { border-bottom-width: 1px; } -.ui-controlgroup-horizontal { padding: 0; } -.ui-controlgroup-horizontal .ui-btn, -.ui-controlgroup-horizontal .ui-checkbox, .ui-controlgroup-horizontal .ui-radio { margin: 0 -5px 0 0; display: inline-block; } -.ui-controlgroup-horizontal .ui-checkbox .ui-btn, .ui-controlgroup-horizontal .ui-radio .ui-btn, -.ui-controlgroup-horizontal .ui-checkbox:last-child, .ui-controlgroup-horizontal .ui-radio:last-child { margin-right: 0; } -.ui-controlgroup-horizontal .ui-controlgroup-last { margin-right: 0; } -.ui-controlgroup .ui-checkbox label, .ui-controlgroup .ui-radio label { font-size: 16px; } -/* conflicts with listview.. -.ui-controlgroup .ui-btn-icon-notext { width: 30px; height: 30px; text-indent: -9999px; } -.ui-controlgroup .ui-btn-icon-notext .ui-btn-inner { padding: 5px 6px 5px 5px; } -*/ - -.min-width-480px .ui-controlgroup-label { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0; } -.min-width-480px .ui-controlgroup-controls { width: 60%; display: inline-block; } /* -* jQuery Mobile Framework -* Copyright (c) jQuery Project -* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses. -*/ -.ui-dialog { min-height: 480px; } -.ui-dialog .ui-header, .ui-dialog .ui-content, .ui-dialog .ui-footer { margin: 15px; position: relative; } -.ui-dialog .ui-header, .ui-dialog .ui-footer { z-index: 10; width: auto; } -.ui-dialog .ui-content, .ui-dialog .ui-footer { margin-top: -15px; }/* -* jQuery Mobile Framework -* Copyright (c) jQuery Project -* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses. -*/ -.ui-checkbox, .ui-radio { position:relative; margin: .2em 0 .5em; z-index: 1; } -.ui-checkbox .ui-btn, .ui-radio .ui-btn { margin: 0; text-align: left; z-index: 2; } -.ui-checkbox .ui-btn-icon-left .ui-btn-inner,.ui-radio .ui-btn-icon-left .ui-btn-inner { padding-left: 45px; } -.ui-checkbox .ui-btn-icon-right .ui-btn-inner, .ui-radio .ui-btn-icon-right .ui-btn-inner { padding-right: 45px; } -.ui-checkbox .ui-btn-icon-left .ui-icon, .ui-radio .ui-btn-icon-left .ui-icon {left: 15px; } -.ui-checkbox .ui-btn-icon-right .ui-icon, .ui-radio .ui-btn-icon-right .ui-icon {right: 15px; } -/* input, label positioning */ -.ui-checkbox input,.ui-radio input { position:absolute; left:20px; top:50%; width: 10px; height: 10px; margin:-5px 0 0 0; outline: 0 !important; z-index: 1; }/* -* jQuery Mobile Framework -* Copyright (c) jQuery Project -* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses. -*/ -.ui-field-contain { background: none; padding: 1.5em 0; margin: 0; border-bottom-width: 1px; overflow: visible; } -.ui-field-contain:first-child { border-top-width: 0; } -.min-width-480px .ui-field-contain { border-width: 0; padding: 0; margin: 1em 0; }/* -* jQuery Mobile Framework -* Copyright (c) jQuery Project -* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses. -*/ -.ui-select { display: block; position: relative; } -.ui-select select { position: absolute; left: -9999px; top: -9999px; } -.ui-select .ui-btn select { cursor: pointer; -webkit-appearance: button; left: 0; top:0; width: 100%; height: 100%; opacity: 0.001; } -.ui-select .ui-btn select.ui-select-nativeonly { opacity: 1; } - -.ui-select .ui-btn-icon-right .ui-btn-inner { padding-right: 45px; } -.ui-select .ui-btn-icon-right .ui-icon { right: 15px; } - -/* labels */ -label.ui-select { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .3em; display: block; } - -/*listbox*/ -.ui-select .ui-btn-text, .ui-selectmenu .ui-btn-text { display: inline-block; min-height: 1em; } -.ui-select .ui-btn-text { text-overflow: ellipsis; overflow: hidden; width: 85% } - -.ui-selectmenu { position: absolute; padding: 0; z-index: 100 !important; width: 80%; max-width: 350px; padding: 6px; } -.ui-selectmenu .ui-listview { margin: 0; } -.ui-selectmenu .ui-btn.ui-li-divider { cursor: default; } -.ui-selectmenu-hidden { top: -9999px; left: -9999px; } -.ui-selectmenu-screen { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 99; } -.ui-screen-hidden, .ui-selectmenu-list .ui-li .ui-icon { display: none; } -.ui-selectmenu-list .ui-li .ui-icon { display: block; } -.ui-li.ui-selectmenu-placeholder { display: none; } - -.min-width-480px label.ui-select { display: inline-block; width: 20%; margin: 0 2% 0 0; } -.min-width-480px .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; } -/* -* jQuery Mobile Framework -* Copyright (c) jQuery Project -* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses. -*/ -label.ui-input-text { font-size: 16px; line-height: 1.4; display: block; font-weight: normal; margin: 0 0 .3em; } -input.ui-input-text, textarea.ui-input-text { background-image: none; padding: .4em; line-height: 1.4; font-size: 16px; display: block; width: 95%; } -input.ui-input-text { -webkit-appearance: none; } -textarea.ui-input-text { height: 50px; -webkit-transition: height 200ms linear; -moz-transition: height 200ms linear; -o-transition: height 200ms linear; transition: height 200ms linear; } -.ui-input-search { padding: 0 30px; width: 77%; background-position: 8px 50%; background-repeat: no-repeat; position: relative; } -.ui-input-search input.ui-input-text { border: none; width: 98%; padding: .4em 0; margin: 0; display: block; background: transparent none; outline: 0 !important; } -.ui-input-search .ui-input-clear { position: absolute; right: 0; top: 50%; margin-top: -14px; } -.ui-input-search .ui-input-clear-hidden { display: none; } - -/* orientation adjustments - incomplete!*/ -.min-width-480px label.ui-input-text { vertical-align: top; } -.min-width-480px label.ui-input-text { display: inline-block; width: 20%; margin: 0 2% 0 0; } -.min-width-480px input.ui-input-text, -.min-width-480px textarea.ui-input-text, -.min-width-480px .ui-input-search { width: 60%; display: inline-block; } -.min-width-480px .ui-input-search { width: 50%; }/* -* jQuery Mobile Framework -* Copyright (c) jQuery Project -* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses. -*/ -.ui-listview { margin: 0; counter-reset: listnumbering; } -.ui-content .ui-listview { margin: -15px; } -.ui-content .ui-listview-inset { margin: 1em 0; } -.ui-listview, .ui-li { list-style:none; padding:0; zoom: 1; } -.ui-li { display: block; margin:0; position: relative; overflow: hidden; text-align: left; border-width: 0; border-top-width: 1px; } -.ui-li .ui-btn-text { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; } -.ui-li-divider, .ui-li-static { padding: .5em 15px; font-size: 14px; font-weight: bold; counter-reset: listnumbering; } -ol.ui-listview .ui-link-inherit:before, .ui-li-dec { font-size: .8em; display: inline-block; padding-right: .3em; font-weight: normal;counter-increment: listnumbering; content: counter(listnumbering) ". "; } -ol.ui-listview .ui-li-jsnumbering:before { content: "" !important; } /* to avoid chance of duplication */ -.ui-listview-inset .ui-li { border-right-width: 1px; border-left-width: 1px; } -.ui-li:last-child { border-bottom-width: 1px; } -.ui-li .ui-btn-inner { display: block; position: relative; padding: .7em 75px .7em 15px; } -.ui-li-has-thumb .ui-btn-inner { min-height: 60px; padding-left: 100px; } -.ui-li-has-icon .ui-btn-inner { min-height: 20px; padding-left: 40px; } -.ui-li-heading { font-size: 16px; font-weight: bold; display: block; margin: .6em 0; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; } -.ui-li-desc { font-size: 12px; font-weight: normal; display: block; margin: -.5em 0 .6em; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; } -.ui-li-thumb, .ui-li-icon { position: absolute; left: 1px; top: 0; max-height: 80px; max-width: 80px; } -.ui-li-icon { max-height: 40px; max-width: 40px; left: 10px; top: .9em; } -.ui-li-thumb, .ui-li-icon, .ui-li-content { float: left; margin-right: 10px; } - -.ui-li-aside { float: right; width: 50%; text-align: right; margin: .3em 0; } -.min-width-480px .ui-li-aside { width: 45%; } -.ui-li-has-alt .ui-btn-inner { padding-right: 95px; } -.ui-li-count { position: absolute; font-size: 11px; font-weight: bold; padding: .2em .5em; top: 50%; margin-top: -.9em; right: 38px; } -.ui-li-divider .ui-li-count { right: 10px; } -.ui-li-has-alt .ui-li-count { right: 55px; } -.ui-li-link-alt { position: absolute; width: 40px; height: 100%; border-width: 0; border-left-width: 1px; top: 0; right: 0; margin: 0; padding: 0; } -.ui-li-link-alt .ui-btn { overflow: hidden; position: absolute; right: 8px; top: 50%; margin: -11px 0 0 0; border-bottom-width: 1px; } -.ui-li-link-alt .ui-btn-inner { padding: 0; position: static; } -.ui-li-link-alt .ui-btn .ui-icon { right: 50%; margin-right: -9px; } - -.ui-listview-filter { border-width: 0; overflow: hidden; margin: -15px -15px 15px -15px } -.ui-listview-filter .ui-input-search { margin: 5px; width: auto; display: block; } - -/* Odd iPad positioning issue. */ -@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) { - .ui-li .ui-btn-text { overflow: visible; } -}/* -* jQuery Mobile Framework -* Copyright (c) jQuery Project -* Dual licensed under the MIT (MIT-LICENSE.txt) or GPL (GPL-LICENSE.txt) licenses. -*/ -label.ui-slider { display: block; } -input.ui-slider-input, .min-width-480px input.ui-slider-input { display: inline-block; width: 50px; } -select.ui-slider-switch { display: none; } -div.ui-slider { position: relative; display: inline-block; overflow: visible; height: 15px; padding: 0; margin: 0 2% 0 20px; top: 4px; width: 66%; } -a.ui-slider-handle { position: absolute; z-index: 10; top: 50%; width: 28px; height: 28px; margin-top: -15px; margin-left: -15px; } -a.ui-slider-handle .ui-btn-inner { padding-left: 0; padding-right: 0; } -.min-width-480px label.ui-slider { display: inline-block; width: 20%; margin: 0 2% 0 0; } -.min-width-480px 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%; } -div.ui-slider-handle-snapping { -webkit-transition: left 100ms linear; } -div.ui-slider-labelbg { position: absolute; top:0; margin: 0; border-width: 0; } -div.ui-slider-switch div.ui-slider-labelbg-a { width: 60%; height: 100%; left: 0; } -div.ui-slider-switch div.ui-slider-labelbg-b { width: 60%; height: 100%; right: 0; } -.ui-slider-switch-a div.ui-slider-labelbg-a, .ui-slider-switch-b div.ui-slider-labelbg-b { z-index: 1; } -.ui-slider-switch-a div.ui-slider-labelbg-b, .ui-slider-switch-b div.ui-slider-labelbg-a { z-index: 10; } - -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 } diff --git a/addons/web_mobile/static/openerp/dynamics/images/ajax-loader.png b/addons/web_mobile/static/openerp/dynamics/images/ajax-loader.png deleted file mode 100755 index 811a2cdd1b4..00000000000 Binary files a/addons/web_mobile/static/openerp/dynamics/images/ajax-loader.png and /dev/null differ diff --git a/addons/web_mobile/static/openerp/dynamics/images/form-check-off.png b/addons/web_mobile/static/openerp/dynamics/images/form-check-off.png deleted file mode 100755 index 54e2fe0f80d..00000000000 Binary files a/addons/web_mobile/static/openerp/dynamics/images/form-check-off.png and /dev/null differ diff --git a/addons/web_mobile/static/openerp/dynamics/images/form-check-on.png b/addons/web_mobile/static/openerp/dynamics/images/form-check-on.png deleted file mode 100755 index e6daaaf8b10..00000000000 Binary files a/addons/web_mobile/static/openerp/dynamics/images/form-check-on.png and /dev/null differ diff --git a/addons/web_mobile/static/openerp/dynamics/images/form-radio-off.png b/addons/web_mobile/static/openerp/dynamics/images/form-radio-off.png deleted file mode 100755 index 32bd43392e2..00000000000 Binary files a/addons/web_mobile/static/openerp/dynamics/images/form-radio-off.png and /dev/null differ diff --git a/addons/web_mobile/static/openerp/dynamics/images/form-radio-on.png b/addons/web_mobile/static/openerp/dynamics/images/form-radio-on.png deleted file mode 100755 index ddc40497055..00000000000 Binary files a/addons/web_mobile/static/openerp/dynamics/images/form-radio-on.png and /dev/null differ diff --git a/addons/web_mobile/static/openerp/dynamics/images/icon-search-black.png b/addons/web_mobile/static/openerp/dynamics/images/icon-search-black.png deleted file mode 100755 index 5721120f8df..00000000000 Binary files a/addons/web_mobile/static/openerp/dynamics/images/icon-search-black.png and /dev/null differ diff --git a/addons/web_mobile/static/openerp/dynamics/images/icone-folder.png b/addons/web_mobile/static/openerp/dynamics/images/icone-folder.png deleted file mode 100755 index c75b3475790..00000000000 Binary files a/addons/web_mobile/static/openerp/dynamics/images/icone-folder.png and /dev/null differ diff --git a/addons/web_mobile/static/openerp/dynamics/images/icone-save.png b/addons/web_mobile/static/openerp/dynamics/images/icone-save.png deleted file mode 100755 index 9bf9b5c7eb7..00000000000 Binary files a/addons/web_mobile/static/openerp/dynamics/images/icone-save.png and /dev/null differ diff --git a/addons/web_mobile/static/openerp/dynamics/images/icons-18-black.png b/addons/web_mobile/static/openerp/dynamics/images/icons-18-black.png deleted file mode 100755 index 3657baea879..00000000000 Binary files a/addons/web_mobile/static/openerp/dynamics/images/icons-18-black.png and /dev/null differ diff --git a/addons/web_mobile/static/openerp/dynamics/images/icons-18-white.png b/addons/web_mobile/static/openerp/dynamics/images/icons-18-white.png deleted file mode 100755 index ccca7b44b7b..00000000000 Binary files a/addons/web_mobile/static/openerp/dynamics/images/icons-18-white.png and /dev/null differ diff --git a/addons/web_mobile/static/openerp/dynamics/images/icons-36-black.png b/addons/web_mobile/static/openerp/dynamics/images/icons-36-black.png deleted file mode 100755 index 79b6d601bbc..00000000000 Binary files a/addons/web_mobile/static/openerp/dynamics/images/icons-36-black.png and /dev/null differ diff --git a/addons/web_mobile/static/openerp/dynamics/images/icons-36-white.png b/addons/web_mobile/static/openerp/dynamics/images/icons-36-white.png deleted file mode 100755 index e1b9c04ea95..00000000000 Binary files a/addons/web_mobile/static/openerp/dynamics/images/icons-36-white.png and /dev/null differ diff --git a/addons/web_mobile/static/openerp/dynamics/jquer.mobile-1.0a3.js b/addons/web_mobile/static/openerp/dynamics/jquer.mobile-1.0a3.js deleted file mode 100755 index e9ecf3d7eb3..00000000000 --- a/addons/web_mobile/static/openerp/dynamics/jquer.mobile-1.0a3.js +++ /dev/null @@ -1,4492 +0,0 @@ -/*! - * jQuery Mobile v1.0a3 - * http://jquerymobile.com/ - * - * Copyright 2010, jQuery Project - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - */ -/*! - * jQuery UI Widget @VERSION - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Widget - */ -(function( $, undefined ) { - -// jQuery 1.4+ -if ( $.cleanData ) { - var _cleanData = $.cleanData; - $.cleanData = function( elems ) { - for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { - $( elem ).triggerHandler( "remove" ); - } - _cleanData( elems ); - }; -} else { - var _remove = $.fn.remove; - $.fn.remove = function( selector, keepData ) { - return this.each(function() { - if ( !keepData ) { - if ( !selector || $.filter( selector, [ this ] ).length ) { - $( "*", this ).add( [ this ] ).each(function() { - $( this ).triggerHandler( "remove" ); - }); - } - } - return _remove.call( $(this), selector, keepData ); - }); - }; -} - -$.widget = function( name, base, prototype ) { - var namespace = name.split( "." )[ 0 ], - fullName; - name = name.split( "." )[ 1 ]; - fullName = namespace + "-" + name; - - if ( !prototype ) { - prototype = base; - base = $.Widget; - } - - // create selector for plugin - $.expr[ ":" ][ fullName ] = function( elem ) { - return !!$.data( elem, name ); - }; - - $[ namespace ] = $[ namespace ] || {}; - $[ namespace ][ name ] = function( options, element ) { - // allow instantiation without initializing for simple inheritance - if ( arguments.length ) { - this._createWidget( options, element ); - } - }; - - var basePrototype = new base(); - // we need to make the options hash a property directly on the new instance - // otherwise we'll modify the options hash on the prototype that we're - // inheriting from -// $.each( basePrototype, function( key, val ) { -// if ( $.isPlainObject(val) ) { -// basePrototype[ key ] = $.extend( {}, val ); -// } -// }); - basePrototype.options = $.extend( true, {}, basePrototype.options ); - $[ namespace ][ name ].prototype = $.extend( true, basePrototype, { - namespace: namespace, - widgetName: name, - widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name, - widgetBaseClass: fullName - }, prototype ); - - $.widget.bridge( name, $[ namespace ][ name ] ); -}; - -$.widget.bridge = function( name, object ) { - $.fn[ name ] = function( options ) { - var isMethodCall = typeof options === "string", - args = Array.prototype.slice.call( arguments, 1 ), - returnValue = this; - - // allow multiple hashes to be passed on init - options = !isMethodCall && args.length ? - $.extend.apply( null, [ true, options ].concat(args) ) : - options; - - // prevent calls to internal methods - if ( isMethodCall && options.charAt( 0 ) === "_" ) { - return returnValue; - } - - if ( isMethodCall ) { - this.each(function() { - var instance = $.data( this, name ); - if ( !instance ) { - throw "cannot call methods on " + name + " prior to initialization; " + - "attempted to call method '" + options + "'"; - } - if ( !$.isFunction( instance[options] ) ) { - throw "no such method '" + options + "' for " + name + " widget instance"; - } - var methodValue = instance[ options ].apply( instance, args ); - if ( methodValue !== instance && methodValue !== undefined ) { - returnValue = methodValue; - return false; - } - }); - } else { - this.each(function() { - var instance = $.data( this, name ); - if ( instance ) { - instance.option( options || {} )._init(); - } else { - $.data( this, name, new object( options, this ) ); - } - }); - } - - return returnValue; - }; -}; - -$.Widget = function( options, element ) { - // allow instantiation without initializing for simple inheritance - if ( arguments.length ) { - this._createWidget( options, element ); - } -}; - -$.Widget.prototype = { - widgetName: "widget", - widgetEventPrefix: "", - options: { - disabled: false - }, - _createWidget: function( options, element ) { - // $.widget.bridge stores the plugin instance, but we do it anyway - // so that it's stored even before the _create function runs - $.data( element, this.widgetName, this ); - this.element = $( element ); - this.options = $.extend( true, {}, - this.options, - this._getCreateOptions(), - options ); - - var self = this; - this.element.bind( "remove." + this.widgetName, function() { - self.destroy(); - }); - - this._create(); - this._trigger( "create" ); - this._init(); - }, - _getCreateOptions: function() { - var options = {}; - if ( $.metadata ) { - options = $.metadata.get( element )[ this.widgetName ]; - } - return options; - }, - _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( key, value ) { - var options = key; - - if ( arguments.length === 0 ) { - // don't return a reference to the internal hash - return $.extend( {}, this.options ); - } - - if (typeof key === "string" ) { - if ( value === undefined ) { - return this.options[ key ]; - } - options = {}; - options[ key ] = value; - } - - this._setOptions( options ); - - return this; - }, - _setOptions: function( options ) { - var self = this; - $.each( options, function( key, value ) { - self._setOption( key, value ); - }); - - return this; - }, - _setOption: function( key, value ) { - this.options[ key ] = value; - - if ( key === "disabled" ) { - this.widget() - [ value ? "addClass" : "removeClass"]( - this.widgetBaseClass + "-disabled" + " " + - "ui-state-disabled" ) - .attr( "aria-disabled", value ); - } - - return this; - }, - - enable: function() { - return this._setOption( "disabled", false ); - }, - disable: function() { - return this._setOption( "disabled", true ); - }, - - _trigger: function( type, event, data ) { - var callback = this.options[ type ]; - - event = $.Event( event ); - event.type = ( type === this.widgetEventPrefix ? - type : - this.widgetEventPrefix + type ).toLowerCase(); - data = data || {}; - - // copy original event properties over to the new event - // this would happen if we could call $.event.fix instead of $.Event - // but we don't have a way to force an event to be fixed multiple times - if ( event.originalEvent ) { - for ( var i = $.event.props.length, prop; i; ) { - prop = $.event.props[ --i ]; - event[ prop ] = event.originalEvent[ prop ]; - } - } - - this.element.trigger( event, data ); - - return !( $.isFunction(callback) && - callback.call( this.element[0], event, data ) === false || - event.isDefaultPrevented() ); - } -}; - -})( jQuery ); -/* -* jQuery Mobile Framework : widget factory extentions for mobile -* Copyright (c) jQuery Project -* Dual licensed under the MIT or GPL Version 2 licenses. -* http://jquery.org/license -*/ -(function($, undefined ) { - -$.widget( "mobile.widget", { - _getCreateOptions: function() { - var elem = this.element, - options = {}; - $.each( this.options, function( option ) { - var value = elem.data( option.replace( /[A-Z]/g, function( c ) { - return "-" + c.toLowerCase(); - } ) ); - if ( value !== undefined ) { - options[ option ] = value; - } - }); - return options; - } -}); - -})( jQuery ); -/* -* jQuery Mobile Framework : resolution and CSS media query related helpers and behavior -* Copyright (c) jQuery Project -* Dual licensed under the MIT or GPL Version 2 licenses. -* http://jquery.org/license -*/ -(function($, undefined ) { - -var $window = $(window), - $html = $( "html" ), - - //media-query-like width breakpoints, which are translated to classes on the html element - resolutionBreakpoints = [320,480,768,1024]; - - -/* $.mobile.media method: pass a CSS media type or query and get a bool return - note: this feature relies on actual media query support for media queries, though types will work most anywhere - examples: - $.mobile.media('screen') //>> tests for screen media type - $.mobile.media('screen and (min-width: 480px)') //>> tests for screen media type with window width > 480px - $.mobile.media('@media screen and (-webkit-min-device-pixel-ratio: 2)') //>> tests for webkit 2x pixel ratio (iPhone 4) -*/ -$.mobile.media = (function() { - // TODO: use window.matchMedia once at least one UA implements it - var cache = {}, - testDiv = $( "
    " ), - fakeBody = $( "" ).append( testDiv ); - - return function( query ) { - if ( !( query in cache ) ) { - var styleBlock = document.createElement('style'), - cssrule = "@media " + query + " { #jquery-mediatest { position:absolute; } }"; - //must set type for IE! - styleBlock.type = "text/css"; - if (styleBlock.styleSheet){ - styleBlock.styleSheet.cssText = cssrule; - } - else { - styleBlock.appendChild(document.createTextNode(cssrule)); - } - - $html.prepend( fakeBody ).prepend( styleBlock ); - cache[ query ] = testDiv.css( "position" ) === "absolute"; - fakeBody.add( styleBlock ).remove(); - } - return cache[ query ]; - }; -})(); - -/* - private function for adding/removing breakpoint classes to HTML element for faux media-query support - It does not require media query support, instead using JS to detect screen width > cross-browser support - This function is called on orientationchange, resize, and mobileinit, and is bound via the 'htmlclass' event namespace -*/ -function detectResolutionBreakpoints(){ - var currWidth = $window.width(), - minPrefix = "min-width-", - maxPrefix = "max-width-", - minBreakpoints = [], - maxBreakpoints = [], - unit = "px", - breakpointClasses; - - $html.removeClass( minPrefix + resolutionBreakpoints.join(unit + " " + minPrefix) + unit + " " + - maxPrefix + resolutionBreakpoints.join( unit + " " + maxPrefix) + unit ); - - $.each(resolutionBreakpoints,function( i, breakPoint ){ - if( currWidth >= breakPoint ){ - minBreakpoints.push( minPrefix + breakPoint + unit ); - } - if( currWidth <= breakPoint ){ - maxBreakpoints.push( maxPrefix + breakPoint + unit ); - } - }); - - if( minBreakpoints.length ){ breakpointClasses = minBreakpoints.join(" "); } - if( maxBreakpoints.length ){ breakpointClasses += " " + maxBreakpoints.join(" "); } - - $html.addClass( breakpointClasses ); -}; - -/* $.mobile.addResolutionBreakpoints method: - pass either a number or an array of numbers and they'll be added to the min/max breakpoint classes - Examples: - $.mobile.addResolutionBreakpoints( 500 ); - $.mobile.addResolutionBreakpoints( [500, 1200] ); -*/ -$.mobile.addResolutionBreakpoints = function( newbps ){ - if( $.type( newbps ) === "array" ){ - resolutionBreakpoints = resolutionBreakpoints.concat( newbps ); - } - else { - resolutionBreakpoints.push( newbps ); - } - resolutionBreakpoints.sort(function(a,b){ return a-b; }); - detectResolutionBreakpoints(); -}; - -/* on mobileinit, add classes to HTML element - and set handlers to update those on orientationchange and resize*/ -$(document).bind("mobileinit.htmlclass", function(){ - /* bind to orientationchange and resize - to add classes to HTML element for min/max breakpoints and orientation */ - $window.bind("orientationchange.htmlclass resize.htmlclass", function(event){ - //add orientation class to HTML element on flip/resize. - if(event.orientation){ - $html.removeClass( "portrait landscape" ).addClass( event.orientation ); - } - //add classes to HTML element for min/max breakpoints - detectResolutionBreakpoints(); - }); -}); - -/* Manually trigger an orientationchange event when the dom ready event fires. - This will ensure that any viewport meta tag that may have been injected - has taken effect already, allowing us to properly calculate the width of the - document. -*/ -$(function(){ - //trigger event manually - $window.trigger( "orientationchange.htmlclass" ); -}); - -})(jQuery);/* -* jQuery Mobile Framework : support tests -* 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 -*/ -(function($, undefined ) { - - - -var fakeBody = $( "" ).prependTo( "html" ), - fbCSS = fakeBody[0].style, - vendors = ['webkit','moz','o'], - webos = window.palmGetResource || window.PalmServiceBridge, //only used to rule out scrollTop - bb = window.blackberry; //only used to rule out box shadow, as it's filled opaque on BB - -//thx Modernizr -function propExists( prop ){ - var uc_prop = prop.charAt(0).toUpperCase() + prop.substr(1), - props = (prop + ' ' + vendors.join(uc_prop + ' ') + uc_prop).split(' '); - for(var v in props){ - if( fbCSS[ v ] !== undefined ){ - return true; - } - } -}; - -//test for dynamic-updating base tag support (allows us to avoid href,src attr rewriting) -function baseTagTest(){ - var fauxBase = location.protocol + '//' + location.host + location.pathname + "ui-dir/", - base = $("head base"), - fauxEle = null, - href = ''; - if (!base.length) { - base = fauxEle = $("", {"href": fauxBase}).appendTo("head"); - } - else { - href = base.attr("href"); - } - var link = $( "" ).prependTo( fakeBody ), - rebase = link[0].href; - base[0].href = href ? href : location.pathname; - if (fauxEle) { - fauxEle.remove(); - } - return rebase.indexOf(fauxBase) === 0; -}; - -$.extend( $.support, { - orientation: "orientation" in window, - touch: "ontouchend" in document, - cssTransitions: "WebKitTransitionEvent" in window, - pushState: !!history.pushState, - mediaquery: $.mobile.media('only all'), - cssPseudoElement: !!propExists('content'), - boxShadow: !!propExists('boxShadow') && !bb, - scrollTop: ("pageXOffset" in window || "scrollTop" in document.documentElement || "scrollTop" in fakeBody[0]) && !webos, - dynamicBaseTag: baseTagTest() -}); - -fakeBody.remove(); - -//for ruling out shadows via css -if( !$.support.boxShadow ){ $('html').addClass('ui-mobile-nosupport-boxshadow'); } - -})( jQuery );/* -* jQuery Mobile Framework : events -* Copyright (c) jQuery Project -* Dual licensed under the MIT or GPL Version 2 licenses. -* http://jquery.org/license -*/ -(function($, undefined ) { - -// add new event shortcuts -$.each( "touchstart touchmove touchend orientationchange tap taphold swipe swipeleft swiperight scrollstart scrollstop".split( " " ), function( i, name ) { - $.fn[ name ] = function( fn ) { - return fn ? this.bind( name, fn ) : this.trigger( name ); - }; - $.attrFn[ name ] = true; -}); - -var supportTouch = $.support.touch, - scrollEvent = "touchmove scroll", - touchStartEvent = supportTouch ? "touchstart" : "mousedown", - touchStopEvent = supportTouch ? "touchend" : "mouseup", - touchMoveEvent = supportTouch ? "touchmove" : "mousemove"; - -// also handles scrollstop -$.event.special.scrollstart = { - enabled: true, - - setup: function() { - var thisObject = this, - $this = $( thisObject ), - scrolling, - timer; - - function trigger( event, state ) { - scrolling = state; - var originalType = event.type; - event.type = scrolling ? "scrollstart" : "scrollstop"; - $.event.handle.call( thisObject, event ); - event.type = originalType; - } - - // iPhone triggers scroll after a small delay; use touchmove instead - $this.bind( scrollEvent, function( event ) { - if ( !$.event.special.scrollstart.enabled ) { - return; - } - - if ( !scrolling ) { - trigger( event, true ); - } - - clearTimeout( timer ); - timer = setTimeout(function() { - trigger( event, false ); - }, 50 ); - }); - } -}; - -// also handles taphold -$.event.special.tap = { - setup: function() { - var thisObject = this, - $this = $( thisObject ); - - $this - .bind( "mousedown touchstart", function( event ) { - if ( event.which && event.which !== 1 || - //check if event fired once already by a device that fires both mousedown and touchstart (while supporting both events) - $this.data( "prevEvent") && $this.data( "prevEvent") !== event.type ) { - return false; - } - - //save event type so only this type is let through for a temp duration, - //allowing quick repetitive taps but not duplicative events - $this.data( "prevEvent", event.type ); - setTimeout(function(){ - $this.removeData( "prevEvent" ); - }, 800); - - var moved = false, - touching = true, - origTarget = event.target, - origEvent = event.originalEvent, - origPos = event.type == "touchstart" ? [origEvent.touches[0].pageX, origEvent.touches[0].pageY] : [ event.pageX, event.pageY ], - originalType, - timer; - - - function moveHandler( event ) { - if( event.type == "scroll" ){ - moved = true; - return; - } - var newPageXY = event.type == "touchmove" ? event.originalEvent.touches[0] : event; - if ((Math.abs(origPos[0] - newPageXY.pageX) > 10) || - (Math.abs(origPos[1] - newPageXY.pageY) > 10)) { - moved = true; - } - } - - timer = setTimeout(function() { - if ( touching && !moved ) { - originalType = event.type; - event.type = "taphold"; - $.event.handle.call( thisObject, event ); - event.type = originalType; - } - }, 750 ); - - //scroll now cancels tap - $(window).one("scroll", moveHandler); - - $this - .bind( "mousemove touchmove", moveHandler ) - .one( "mouseup touchend", function( event ) { - $this.unbind( "mousemove touchmove", moveHandler ); - $(window).unbind("scroll", moveHandler); - clearTimeout( timer ); - touching = false; - - /* ONLY trigger a 'tap' event if the start target is - * the same as the stop target. - */ - if ( !moved && ( origTarget == event.target ) ) { - originalType = event.type; - event.type = "tap"; - $.event.handle.call( thisObject, event ); - event.type = originalType; - } - }); - }); - } -}; - -// also handles swipeleft, swiperight -$.event.special.swipe = { - setup: function() { - var thisObject = this, - $this = $( thisObject ); - - $this - .bind( touchStartEvent, function( event ) { - var data = event.originalEvent.touches ? - event.originalEvent.touches[ 0 ] : - event, - start = { - time: (new Date).getTime(), - coords: [ data.pageX, data.pageY ], - origin: $( event.target ) - }, - stop; - - function moveHandler( event ) { - if ( !start ) { - return; - } - - var data = event.originalEvent.touches ? - event.originalEvent.touches[ 0 ] : - event; - stop = { - time: (new Date).getTime(), - coords: [ data.pageX, data.pageY ] - }; - - // prevent scrolling - if ( Math.abs( start.coords[0] - stop.coords[0] ) > 10 ) { - event.preventDefault(); - } - } - - $this - .bind( touchMoveEvent, moveHandler ) - .one( touchStopEvent, function( event ) { - $this.unbind( touchMoveEvent, moveHandler ); - if ( start && stop ) { - if ( stop.time - start.time < 1000 && - Math.abs( start.coords[0] - stop.coords[0]) > 30 && - Math.abs( start.coords[1] - stop.coords[1]) < 75 ) { - start.origin - .trigger( "swipe" ) - .trigger( start.coords[0] > stop.coords[0] ? "swipeleft" : "swiperight" ); - } - } - start = stop = undefined; - }); - }); - } -}; - -(function($){ - // "Cowboy" Ben Alman - - var win = $(window), - special_event, - get_orientation, - last_orientation; - - $.event.special.orientationchange = special_event = { - setup: function(){ - // If the event is supported natively, return false so that jQuery - // will bind to the event using DOM methods. - if ( $.support.orientation ) { return false; } - - // Get the current orientation to avoid initial double-triggering. - last_orientation = get_orientation(); - - // Because the orientationchange event doesn't exist, simulate the - // event by testing window dimensions on resize. - win.bind( "resize", handler ); - }, - teardown: function(){ - // If the event is not supported natively, return false so that - // jQuery will unbind the event using DOM methods. - if ( $.support.orientation ) { return false; } - - // Because the orientationchange event doesn't exist, unbind the - // resize event handler. - win.unbind( "resize", handler ); - }, - add: function( handleObj ) { - // Save a reference to the bound event handler. - var old_handler = handleObj.handler; - - handleObj.handler = function( event ) { - // Modify event object, adding the .orientation property. - event.orientation = get_orientation(); - - // Call the originally-bound event handler and return its result. - return old_handler.apply( this, arguments ); - }; - } - }; - - // If the event is not supported natively, this handler will be bound to - // the window resize event to simulate the orientationchange event. - function handler() { - // Get the current orientation. - var orientation = get_orientation(); - - if ( orientation !== last_orientation ) { - // The orientation has changed, so trigger the orientationchange event. - last_orientation = orientation; - win.trigger( "orientationchange" ); - } - }; - - // Get the current page orientation. This method is exposed publicly, should it - // be needed, as jQuery.event.special.orientationchange.orientation() - special_event.orientation = get_orientation = function() { - var elem = document.documentElement; - return elem && elem.clientWidth / elem.clientHeight < 1.1 ? "portrait" : "landscape"; - }; - -})(jQuery); - -$.each({ - scrollstop: "scrollstart", - taphold: "tap", - swipeleft: "swipe", - swiperight: "swipe" -}, function( event, sourceEvent ) { - $.event.special[ event ] = { - setup: function() { - $( this ).bind( sourceEvent, $.noop ); - } - }; -}); - -})( jQuery ); -/*! - * jQuery hashchange event - v1.3 - 7/21/2010 - * http://benalman.com/projects/jquery-hashchange-plugin/ - * - * Copyright (c) 2010 "Cowboy" Ben Alman - * Dual licensed under the MIT and GPL licenses. - * http://benalman.com/about/license/ - */ - -// Script: jQuery hashchange event -// -// *Version: 1.3, Last updated: 7/21/2010* -// -// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/ -// GitHub - http://github.com/cowboy/jquery-hashchange/ -// Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js -// (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped) -// -// About: License -// -// Copyright (c) 2010 "Cowboy" Ben Alman, -// Dual licensed under the MIT and GPL licenses. -// http://benalman.com/about/license/ -// -// About: Examples -// -// These working examples, complete with fully commented code, illustrate a few -// ways in which this plugin can be used. -// -// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/ -// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/ -// -// About: Support and Testing -// -// Information about what version or versions of jQuery this plugin has been -// tested with, what browsers it has been tested in, and where the unit tests -// reside (so you can test it yourself). -// -// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2 -// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5, -// Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5. -// Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/ -// -// About: Known issues -// -// While this jQuery hashchange event implementation is quite stable and -// robust, there are a few unfortunate browser bugs surrounding expected -// hashchange event-based behaviors, independent of any JavaScript -// window.onhashchange abstraction. See the following examples for more -// information: -// -// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/ -// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/ -// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/ -// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/ -// -// Also note that should a browser natively support the window.onhashchange -// event, but not report that it does, the fallback polling loop will be used. -// -// About: Release History -// -// 1.3 - (7/21/2010) Reorganized IE6/7 Iframe code to make it more -// "removable" for mobile-only development. Added IE6/7 document.title -// support. Attempted to make Iframe as hidden as possible by using -// techniques from http://www.paciellogroup.com/blog/?p=604. Added -// support for the "shortcut" format $(window).hashchange( fn ) and -// $(window).hashchange() like jQuery provides for built-in events. -// Renamed jQuery.hashchangeDelay to and -// lowered its default value to 50. Added -// and properties plus document-domain.html -// file to address access denied issues when setting document.domain in -// IE6/7. -// 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin -// from a page on another domain would cause an error in Safari 4. Also, -// IE6/7 Iframe is now inserted after the body (this actually works), -// which prevents the page from scrolling when the event is first bound. -// Event can also now be bound before DOM ready, but it won't be usable -// before then in IE6/7. -// 1.1 - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug -// where browser version is incorrectly reported as 8.0, despite -// inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag. -// 1.0 - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special -// window.onhashchange functionality into a separate plugin for users -// who want just the basic event & back button support, without all the -// extra awesomeness that BBQ provides. This plugin will be included as -// part of jQuery BBQ, but also be available separately. - -(function($,window,undefined){ - '$:nomunge'; // Used by YUI compressor. - - // Reused string. - var str_hashchange = 'hashchange', - - // Method / object references. - doc = document, - fake_onhashchange, - special = $.event.special, - - // Does the browser support window.onhashchange? Note that IE8 running in - // IE7 compatibility mode reports true for 'onhashchange' in window, even - // though the event isn't supported, so also test document.documentMode. - doc_mode = doc.documentMode, - supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 ); - - // Get location.hash (or what you'd expect location.hash to be) sans any - // leading #. Thanks for making this necessary, Firefox! - function get_fragment( url ) { - url = url || location.href; - return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' ); - }; - - // Method: jQuery.fn.hashchange - // - // Bind a handler to the window.onhashchange event or trigger all bound - // window.onhashchange event handlers. This behavior is consistent with - // jQuery's built-in event handlers. - // - // Usage: - // - // > jQuery(window).hashchange( [ handler ] ); - // - // Arguments: - // - // handler - (Function) Optional handler to be bound to the hashchange - // event. This is a "shortcut" for the more verbose form: - // jQuery(window).bind( 'hashchange', handler ). If handler is omitted, - // all bound window.onhashchange event handlers will be triggered. This - // is a shortcut for the more verbose - // jQuery(window).trigger( 'hashchange' ). These forms are described in - // the section. - // - // Returns: - // - // (jQuery) The initial jQuery collection of elements. - - // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and - // $(elem).hashchange() for triggering, like jQuery does for built-in events. - $.fn[ str_hashchange ] = function( fn ) { - return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange ); - }; - - // Property: jQuery.fn.hashchange.delay - // - // The numeric interval (in milliseconds) at which the - // polling loop executes. Defaults to 50. - - // Property: jQuery.fn.hashchange.domain - // - // If you're setting document.domain in your JavaScript, and you want hash - // history to work in IE6/7, not only must this property be set, but you must - // also set document.domain BEFORE jQuery is loaded into the page. This - // property is only applicable if you are supporting IE6/7 (or IE8 operating - // in "IE7 compatibility" mode). - // - // In addition, the property must be set to the - // path of the included "document-domain.html" file, which can be renamed or - // modified if necessary (note that the document.domain specified must be the - // same in both your main JavaScript as well as in this file). - // - // Usage: - // - // jQuery.fn.hashchange.domain = document.domain; - - // Property: jQuery.fn.hashchange.src - // - // If, for some reason, you need to specify an Iframe src file (for example, - // when setting document.domain as in ), you can - // do so using this property. Note that when using this property, history - // won't be recorded in IE6/7 until the Iframe src file loads. This property - // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7 - // compatibility" mode). - // - // Usage: - // - // jQuery.fn.hashchange.src = 'path/to/file.html'; - - $.fn[ str_hashchange ].delay = 50; - /* - $.fn[ str_hashchange ].domain = null; - $.fn[ str_hashchange ].src = null; - */ - - // Event: hashchange event - // - // Fired when location.hash changes. In browsers that support it, the native - // HTML5 window.onhashchange event is used, otherwise a polling loop is - // initialized, running every milliseconds to - // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7 - // compatibility" mode), a hidden Iframe is created to allow the back button - // and hash-based history to work. - // - // Usage as described in : - // - // > // Bind an event handler. - // > jQuery(window).hashchange( function(e) { - // > var hash = location.hash; - // > ... - // > }); - // > - // > // Manually trigger the event handler. - // > jQuery(window).hashchange(); - // - // A more verbose usage that allows for event namespacing: - // - // > // Bind an event handler. - // > jQuery(window).bind( 'hashchange', function(e) { - // > var hash = location.hash; - // > ... - // > }); - // > - // > // Manually trigger the event handler. - // > jQuery(window).trigger( 'hashchange' ); - // - // Additional Notes: - // - // * The polling loop and Iframe are not created until at least one handler - // is actually bound to the 'hashchange' event. - // * If you need the bound handler(s) to execute immediately, in cases where - // a location.hash exists on page load, via bookmark or page refresh for - // example, use jQuery(window).hashchange() or the more verbose - // jQuery(window).trigger( 'hashchange' ). - // * The event can be bound before DOM ready, but since it won't be usable - // before then in IE6/7 (due to the necessary Iframe), recommended usage is - // to bind it inside a DOM ready handler. - - // Override existing $.event.special.hashchange methods (allowing this plugin - // to be defined after jQuery BBQ in BBQ's source code). - special[ str_hashchange ] = $.extend( special[ str_hashchange ], { - - // Called only when the first 'hashchange' event is bound to window. - setup: function() { - // If window.onhashchange is supported natively, there's nothing to do.. - if ( supports_onhashchange ) { return false; } - - // Otherwise, we need to create our own. And we don't want to call this - // until the user binds to the event, just in case they never do, since it - // will create a polling loop and possibly even a hidden Iframe. - $( fake_onhashchange.start ); - }, - - // Called only when the last 'hashchange' event is unbound from window. - teardown: function() { - // If window.onhashchange is supported natively, there's nothing to do.. - if ( supports_onhashchange ) { return false; } - - // Otherwise, we need to stop ours (if possible). - $( fake_onhashchange.stop ); - } - - }); - - // fake_onhashchange does all the work of triggering the window.onhashchange - // event for browsers that don't natively support it, including creating a - // polling loop to watch for hash changes and in IE 6/7 creating a hidden - // Iframe to enable back and forward. - fake_onhashchange = (function(){ - var self = {}, - timeout_id, - - // Remember the initial hash so it doesn't get triggered immediately. - last_hash = get_fragment(), - - fn_retval = function(val){ return val; }, - history_set = fn_retval, - history_get = fn_retval; - - // Start the polling loop. - self.start = function() { - timeout_id || poll(); - }; - - // Stop the polling loop. - self.stop = function() { - timeout_id && clearTimeout( timeout_id ); - timeout_id = undefined; - }; - - // This polling loop checks every $.fn.hashchange.delay milliseconds to see - // if location.hash has changed, and triggers the 'hashchange' event on - // window when necessary. - function poll() { - var hash = get_fragment(), - history_hash = history_get( last_hash ); - - if ( hash !== last_hash ) { - history_set( last_hash = hash, history_hash ); - - $(window).trigger( str_hashchange ); - - } else if ( history_hash !== last_hash ) { - location.href = location.href.replace( /#.*/, '' ) + history_hash; - } - - timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay ); - }; - - // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv - // vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv - // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv - $.browser.msie && !supports_onhashchange && (function(){ - // Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8 - // when running in "IE7 compatibility" mode. - - var iframe, - iframe_src; - - // When the event is bound and polling starts in IE 6/7, create a hidden - // Iframe for history handling. - self.start = function(){ - if ( !iframe ) { - iframe_src = $.fn[ str_hashchange ].src; - iframe_src = iframe_src && iframe_src + get_fragment(); - - // Create hidden Iframe. Attempt to make Iframe as hidden as possible - // by using techniques from http://www.paciellogroup.com/blog/?p=604. - iframe = $('