diff --git a/addons/web/__openerp__.py b/addons/web/__openerp__.py index 5c95b327605..d66409dbe51 100644 --- a/addons/web/__openerp__.py +++ b/addons/web/__openerp__.py @@ -1,6 +1,11 @@ { "name" : "web", - "category" : "Hidden", + "category": "Hidden", + "description": + """ + OpenERP Web core module. + This module provides the core of the OpenERP web client. + """, "depends" : [], 'active': True, 'post_load' : 'wsgi_postload', @@ -10,7 +15,7 @@ "static/lib/datejs/parser.js", "static/lib/datejs/sugarpak.js", "static/lib/datejs/extras.js", - "static/lib/jquery/jquery-1.6.2.js", + "static/lib/jquery/jquery-1.6.4.js", "static/lib/jquery.MD5/jquery.md5.js", "static/lib/jquery.form/jquery.form.js", "static/lib/jquery.validate/jquery.validate.js", diff --git a/addons/web/common/xml2json.py b/addons/web/common/xml2json.py index 16022624fe7..1f2e74691b9 100644 --- a/addons/web/common/xml2json.py +++ b/addons/web/common/xml2json.py @@ -16,7 +16,7 @@ class Xml2Json(object): return Xml2Json.convert_element(root) @staticmethod - def convert_element(el, skip_whitespaces=True): + def convert_element(el, preserve_whitespaces=False): res = {} if el.tag[0] == "{": ns, name = el.tag.rsplit("}", 1) @@ -28,11 +28,11 @@ class Xml2Json(object): for k, v in el.items(): res["attrs"][k] = v kids = [] - if el.text and (not skip_whitespaces or el.text.strip() != ''): + if el.text and (preserve_whitespaces or el.text.strip() != ''): kids.append(el.text) for kid in el: - kids.append(Xml2Json.convert_element(kid)) - if kid.tail and (not skip_whitespaces or kid.tail.strip() != ''): + kids.append(Xml2Json.convert_element(kid, preserve_whitespaces)) + if kid.tail and (preserve_whitespaces or kid.tail.strip() != ''): kids.append(kid.tail) res["children"] = kids return res diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 6af0268b3bf..f811f77b34c 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -841,12 +841,12 @@ class View(openerpweb.Controller): context = req.session.eval_context(req.context) fvg = Model.fields_view_get(view_id, view_type, context, toolbar, submenu) # todo fme?: check that we should pass the evaluated context here - self.process_view(req.session, fvg, context, transform) + self.process_view(req.session, fvg, context, transform, (view_type == 'kanban')) if toolbar and transform: self.process_toolbar(req, fvg['toolbar']) return fvg - def process_view(self, session, fvg, context, transform): + def process_view(self, session, fvg, context, transform, preserve_whitespaces=False): # depending on how it feels, xmlrpclib.ServerProxy can translate # XML-RPC strings to ``str`` or ``unicode``. ElementTree does not # enjoy unicode strings which can not be trivially converted to @@ -864,7 +864,7 @@ class View(openerpweb.Controller): xml = self.transform_view(arch, session, evaluation_context) else: xml = ElementTree.fromstring(arch) - fvg['arch'] = web.common.xml2json.Xml2Json.convert_element(xml) + fvg['arch'] = web.common.xml2json.Xml2Json.convert_element(xml, preserve_whitespaces) for field in fvg['fields'].itervalues(): if field.get('views'): @@ -1064,6 +1064,44 @@ class SearchView(View): }, context) return to_return + @openerpweb.jsonrequest + def add_to_dashboard(self, req, menu_id, action_id, context_to_save, domain, view_mode, name=''): + ctx = web.common.nonliterals.CompoundContext(context_to_save) + ctx.session = req.session + ctx = ctx.evaluate() + domain = web.common.nonliterals.CompoundDomain(domain) + domain.session = req.session + domain = domain.evaluate() + + dashboard_action = load_actions_from_ir_values(req, 'action', 'tree_but_open', + [('ir.ui.menu', menu_id)], False) + if dashboard_action: + action = dashboard_action[0][2] + if action['res_model'] == 'board.board' and action['views'][0][1] == 'form': + # Maybe should check the content instead of model board.board ? + view_id = action['views'][0][0] + board = req.session.model(action['res_model']).fields_view_get(view_id, 'form') + if board and 'arch' in board: + xml = ElementTree.fromstring(board['arch']) + column = xml.find('./board/column') + if column: + new_action = ElementTree.Element('action', { + 'name' : str(action_id), + 'string' : name, + 'view_mode' : view_mode, + 'context' : str(ctx), + 'domain' : str(domain) + }) + column.insert(0, new_action) + arch = ElementTree.tostring(xml, 'utf-8') + return req.session.model('ir.ui.view.custom').create({ + 'user_id': req.session._uid, + 'ref_id': view_id, + 'arch': arch + }, req.session.eval_context(req.context)) + + return False + class Binary(openerpweb.Controller): _cp_path = "/web/binary" @@ -1348,7 +1386,7 @@ class Export(View): context = req.session.eval_context(req.context) Model = req.session.model(model) - ids = ids or Model.search(domain, context=context) + ids = ids or Model.search(domain, 0, False, False, context) field_names = map(operator.itemgetter('name'), fields) import_data = Model.export_data(ids, field_names, context).get('datas',[]) diff --git a/addons/web/po/bn.po b/addons/web/po/bn.po new file mode 100644 index 00000000000..59e01adc03b --- /dev/null +++ b/addons/web/po/bn.po @@ -0,0 +1,677 @@ +# Bengali translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:38+0200\n" +"PO-Revision-Date: 2011-11-24 12:45+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Bengali \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2011-11-25 05:35+0000\n" +"X-Generator: Launchpad (build 14376)\n" + +#: addons/web/static/src/js/view_form.js:355 +msgid "" +"Warning, the record has been modified, your changes will be discarded." +msgstr "" + +#: addons/web/static/src/js/view_form.js:1659 +msgid "   Search More..." +msgstr "" + +#: addons/web/static/src/js/view_form.js:1672 +#, python-format +msgid "   Create \"%s\"" +msgstr "" + +#: addons/web/static/src/js/view_form.js:1678 +msgid "   Create and Edit..." +msgstr "" + +#: addons/web/static/src/js/views.js:568 +msgid "You must choose at least one record." +msgstr "" + +#: addons/web/static/src/js/views.js:569 +msgid "Warning" +msgstr "" + +#: addons/web/static/src/js/views.js:609 +msgid "Translations" +msgstr "" + +#: addons/web/static/src/js/views.js:614 addons/web/static/src/xml/base.xml:0 +msgid "Save" +msgstr "" + +#: addons/web/static/src/js/views.js:615 +msgid "Close" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "x" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#{title}" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#{text}" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Powered by" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "openerp.com" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Loading..." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Drop" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Backup" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Restore" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Password" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Back to Login" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CREATE DATABASE" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Master password:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New database name:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Load Demonstration data:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Default language:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Admin password:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm password:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "DROP DATABASE" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Database:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Master Password:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "BACKUP DATABASE" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "RESTORE DATABASE" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "File:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CHANGE MASTER PASSWORD" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New master password:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm new master password:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "User:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Password:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Database" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Login" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Bad username or password" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"We think that daily job activities can be more intuitive, efficient, " +"automated, .. and even fun." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP's vision to be:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Full featured" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Today's enterprise challenges are multiple. We provide one module for each " +"need." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Open Source" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"To Build a great product, we rely on the knowledge of thousands of " +"contributors." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "User Friendly" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"In order to be productive, people need clean and easy to use interface." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "(" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid ")" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "LOGOUT" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "«" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "»" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "oe_secondary_menu_item" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "oe_secondary_submenu_item" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Hide this tip" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Disable all tips" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "View#" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Fields" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "View labels" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Sidebar Relates" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Field" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid ":" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Translate view" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Translate sidebar" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delete" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "First" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "<" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid ">" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Last" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "♻" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & Edit" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create & Edit" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Duplicate" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Readonly/Editable" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "<<" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "0" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "/" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid ">>" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Add" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Unhandled widget" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "?" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Done" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Open..." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create..." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Search..." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "..." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Uploading ..." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Select" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save As" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Clear" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Advanced Filter" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "-- Filters --" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "-- Actions --" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save Filter" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Manage Filters" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Filter Name:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "(Any existing filter with the same name will be replaced)" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Any of the following conditions must match" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "All the following conditions must match" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "None of the following conditions must match" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Add condition" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "and" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Cancel" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & New" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & Close" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +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 "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export Type:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Compatible Export" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export all Data" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export Formats" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Available fields" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Fields to export" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save fields list" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Remove" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Remove All" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Name" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid " " +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save as:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Ok" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Saved exports:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Old Password:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New Password:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm Password:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "1. Import a .CSV file" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +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 "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CSV File:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "2. Check your file format" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Options" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Does your file have titles?" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Separator:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delimiter:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Encoding:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "UTF-8" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Latin 1" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Lines to skip" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "The import failed due to:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Here is a preview of the file we could not import:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP Web" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Version" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Copyright © 2011-TODAY OpenERP SA. All Rights Reserved." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP is a trademark of the" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP SA Company" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Licenced under the terms of" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "GNU Affero General Public License" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "About OpenERP" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"is a free enterprise-scale software system that is designed to boost\n" +" productivity and profit through data integration. It connects, " +"improves and\n" +" manages business processes in areas such as sales, finance, " +"supply chain,\n" +" project management, production, services, CRM, etc..." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"The system is platform-independent, and can be installed on Windows, Mac OS " +"X,\n" +" and various Linux and other Unix-based distributions. Its " +"architecture enables\n" +" new functionality to be rapidly created, modifications to be " +"made to a\n" +" production system and migration to a new version to be " +"straightforward." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Depending on your needs, OpenERP is available through a web or application " +"client." +msgstr "" diff --git a/addons/web/po/de.po b/addons/web/po/de.po index 72778500484..66d8d950384 100644 --- a/addons/web/po/de.po +++ b/addons/web/po/de.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2011-10-07 10:38+0200\n" -"PO-Revision-Date: 2011-10-10 20:59+0000\n" -"Last-Translator: Felix Schubert \n" +"PO-Revision-Date: 2011-12-03 10:42+0000\n" +"Last-Translator: Ferdinand @ Camptocamp \n" "Language-Team: German \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-11-21 05:50+0000\n" -"X-Generator: Launchpad (build 14299)\n" +"X-Launchpad-Export-Date: 2011-12-04 05:07+0000\n" +"X-Generator: Launchpad (build 14418)\n" #: addons/web/static/src/js/view_form.js:355 msgid "" @@ -373,7 +373,7 @@ msgstr "Hinzufügen" #: addons/web/static/src/xml/base.xml:0 msgid "Unhandled widget" -msgstr "" +msgstr "unbekanntes Oberflächenelement" #: addons/web/static/src/xml/base.xml:0 msgid "?" diff --git a/addons/web/po/hr.po b/addons/web/po/hr.po new file mode 100644 index 00000000000..6a1fc61d322 --- /dev/null +++ b/addons/web/po/hr.po @@ -0,0 +1,677 @@ +# Croatian translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:38+0200\n" +"PO-Revision-Date: 2011-11-28 14:05+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: 2011-11-29 05:49+0000\n" +"X-Generator: Launchpad (build 14399)\n" + +#: addons/web/static/src/js/view_form.js:355 +msgid "" +"Warning, the record has been modified, your changes will be discarded." +msgstr "Upozorenje, zapis je promjenjen. Promjene se neće zapisati." + +#: addons/web/static/src/js/view_form.js:1659 +msgid "   Search More..." +msgstr "   Traži dalje..." + +#: addons/web/static/src/js/view_form.js:1672 +#, python-format +msgid "   Create \"%s\"" +msgstr "   Kreiraj \"%s\"" + +#: addons/web/static/src/js/view_form.js:1678 +msgid "   Create and Edit..." +msgstr "   Kreiraj i uredi..." + +#: addons/web/static/src/js/views.js:568 +msgid "You must choose at least one record." +msgstr "Odaberite barem jedan zapis." + +#: addons/web/static/src/js/views.js:569 +msgid "Warning" +msgstr "Upozorenje" + +#: addons/web/static/src/js/views.js:609 +msgid "Translations" +msgstr "Prijevodi" + +#: addons/web/static/src/js/views.js:614 addons/web/static/src/xml/base.xml:0 +msgid "Save" +msgstr "Snimi" + +#: addons/web/static/src/js/views.js:615 +msgid "Close" +msgstr "Zatvori" + +#: addons/web/static/src/xml/base.xml:0 +msgid "x" +msgstr "x" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#{title}" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#{text}" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Powered by" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "openerp.com" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Loading..." +msgstr "Učitavanje..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create" +msgstr "Kreiraj" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Drop" +msgstr "Obriši" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Backup" +msgstr "Arhiviranje/Backup" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Restore" +msgstr "Obnovi" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Password" +msgstr "Zaporka" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Back to Login" +msgstr "Nazad na prijavu" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CREATE DATABASE" +msgstr "Nova baza podataka" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Master password:" +msgstr "Glavna zaporka" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New database name:" +msgstr "Naziv nove baze podataka:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Load Demonstration data:" +msgstr "Učitaj demonstracijske podatke:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Default language:" +msgstr "Zadani jezik:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Admin password:" +msgstr "Lozinka administratora" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm password:" +msgstr "Potvrda lozinke:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "DROP DATABASE" +msgstr "Briši bazu podataka" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Database:" +msgstr "Baza podataka:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Master Password:" +msgstr "Glavna lozinka" + +#: addons/web/static/src/xml/base.xml:0 +msgid "BACKUP DATABASE" +msgstr "Backup baze podataka" + +#: addons/web/static/src/xml/base.xml:0 +msgid "RESTORE DATABASE" +msgstr "Obnovi bazu podatka (restore)" + +#: addons/web/static/src/xml/base.xml:0 +msgid "File:" +msgstr "Datoteka:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CHANGE MASTER PASSWORD" +msgstr "Promjeni glavnu zaporku" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New master password:" +msgstr "Nova glavna zaporka:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm new master password:" +msgstr "Potvrdi glavnu zaporku:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "User:" +msgstr "Korisnik:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Password:" +msgstr "Zaporka:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Database" +msgstr "Baza podataka" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Login" +msgstr "Korisničko ime" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Bad username or password" +msgstr "Neispravno korisničko ime ili lozinka" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"We think that daily job activities can be more intuitive, efficient, " +"automated, .. and even fun." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP's vision to be:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Full featured" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Today's enterprise challenges are multiple. We provide one module for each " +"need." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Open Source" +msgstr "Otvorenog koda" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"To Build a great product, we rely on the knowledge of thousands of " +"contributors." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "User Friendly" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"In order to be productive, people need clean and easy to use interface." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "(" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid ")" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "LOGOUT" +msgstr "ODJAVA" + +#: addons/web/static/src/xml/base.xml:0 +msgid "«" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "»" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "oe_secondary_menu_item" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "oe_secondary_submenu_item" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Hide this tip" +msgstr "Sakrij savjet" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Disable all tips" +msgstr "Sakrij sve savjete" + +#: addons/web/static/src/xml/base.xml:0 +msgid "View#" +msgstr "Pogled#" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Fields" +msgstr "Polja" + +#: addons/web/static/src/xml/base.xml:0 +msgid "View labels" +msgstr "Labele" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Sidebar Relates" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Field" +msgstr "Polje" + +#: addons/web/static/src/xml/base.xml:0 +msgid ":" +msgstr ":" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Translate view" +msgstr "Prevedi pogled" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Translate sidebar" +msgstr "Prevedi sidebar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delete" +msgstr "Obriši" + +#: addons/web/static/src/xml/base.xml:0 +msgid "First" +msgstr "Prvi" + +#: addons/web/static/src/xml/base.xml:0 +msgid "<" +msgstr "<" + +#: addons/web/static/src/xml/base.xml:0 +msgid ">" +msgstr ">" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Last" +msgstr "Posljednji" + +#: addons/web/static/src/xml/base.xml:0 +msgid "♻" +msgstr "♻" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & Edit" +msgstr "Snimi i uredi" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create & Edit" +msgstr "Novi i uredi" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New" +msgstr "Novi" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Duplicate" +msgstr "Dupliciraj" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Readonly/Editable" +msgstr "Čitanje/Pisanje" + +#: addons/web/static/src/xml/base.xml:0 +msgid "<<" +msgstr "<<" + +#: addons/web/static/src/xml/base.xml:0 +msgid "0" +msgstr "0" + +#: addons/web/static/src/xml/base.xml:0 +msgid "/" +msgstr "/" + +#: addons/web/static/src/xml/base.xml:0 +msgid ">>" +msgstr ">>" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Add" +msgstr "Dodaj" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Unhandled widget" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "?" +msgstr "?" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#" +msgstr "#" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Done" +msgstr "Izvršeno" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Open..." +msgstr "Otvori…" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create..." +msgstr "Kreiraj..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Search..." +msgstr "Traži…" + +#: addons/web/static/src/xml/base.xml:0 +msgid "..." +msgstr "..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Uploading ..." +msgstr "Učitavanje..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Select" +msgstr "Odaberi" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save As" +msgstr "Spremi kao" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Clear" +msgstr "Očisti" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Advanced Filter" +msgstr "Napredni filter" + +#: addons/web/static/src/xml/base.xml:0 +msgid "-- Filters --" +msgstr "-- Filteri --" + +#: addons/web/static/src/xml/base.xml:0 +msgid "-- Actions --" +msgstr "-- Akcije --" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save Filter" +msgstr "Spremi filter" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Manage Filters" +msgstr "Uredi filtere" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Filter Name:" +msgstr "Naziv" + +#: addons/web/static/src/xml/base.xml:0 +msgid "(Any existing filter with the same name will be replaced)" +msgstr "(Zamjenit će postojeći filter istog naziva)" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Any of the following conditions must match" +msgstr "Barem jedan od uvjeta zadovoljava" + +#: addons/web/static/src/xml/base.xml:0 +msgid "All the following conditions must match" +msgstr "Svi uvjeti zadovoljavaju" + +#: addons/web/static/src/xml/base.xml:0 +msgid "None of the following conditions must match" +msgstr "Niti jedan od uvjeta zadovoljava" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Add condition" +msgstr "Dodaj uvjet" + +#: addons/web/static/src/xml/base.xml:0 +msgid "and" +msgstr "i" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Cancel" +msgstr "Odustani" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & New" +msgstr "Spremi i novi" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & Close" +msgstr "Snimi i zatvori" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export" +msgstr "Izvoz" + +#: addons/web/static/src/xml/base.xml:0 +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 "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export Type:" +msgstr "Vrsta izvoza:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Compatible Export" +msgstr "Izvoz kompatibilan uvozu" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export all Data" +msgstr "Izvoz svih podataka" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export Formats" +msgstr "Formati izvoza" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Available fields" +msgstr "Dostupna polja" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Fields to export" +msgstr "Polja za izvoz" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save fields list" +msgstr "Snimi popis polja" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Remove" +msgstr "Ukloni" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Remove All" +msgstr "Ukloni sve" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Name" +msgstr "Naziv" + +#: addons/web/static/src/xml/base.xml:0 +msgid " " +msgstr " " + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save as:" +msgstr "Spremi kao:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Ok" +msgstr "U redu" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Saved exports:" +msgstr "Snimljeni izvozi" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Old Password:" +msgstr "Stara lozinka:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New Password:" +msgstr "Nova lozinka:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm Password:" +msgstr "Potvrda lozinke:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import" +msgstr "Uvoz" + +#: addons/web/static/src/xml/base.xml:0 +msgid "1. Import a .CSV file" +msgstr "Uvezi .CSV datoteku" + +#: addons/web/static/src/xml/base.xml:0 +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 "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CSV File:" +msgstr "CSV datoteka:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "2. Check your file format" +msgstr "2. Provjera formata datoteke" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Options" +msgstr "Opcije uvoza" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Does your file have titles?" +msgstr "Datoteka ima naslove" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Separator:" +msgstr "Razdjelnik:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delimiter:" +msgstr "Graničnik:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Encoding:" +msgstr "Kodna stranica:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "UTF-8" +msgstr "UTF-8" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Latin 1" +msgstr "Latin 1" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Lines to skip" +msgstr "Preskočiti linija" + +#: addons/web/static/src/xml/base.xml:0 +msgid "The import failed due to:" +msgstr "Uvoz nije izvršen:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Here is a preview of the file we could not import:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP Web" +msgstr "OpenERP Web" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Version" +msgstr "Verzija" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Copyright © 2011-TODAY OpenERP SA. All Rights Reserved." +msgstr "Copyright © 2011-TODAY OpenERP SA. All Rights Reserved." + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP is a trademark of the" +msgstr "OpenERP is a trademark of the" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP SA Company" +msgstr "OpenERP SA Company" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Licenced under the terms of" +msgstr "Licenced under the terms of" + +#: addons/web/static/src/xml/base.xml:0 +msgid "GNU Affero General Public License" +msgstr "GNU Affero General Public License" + +#: addons/web/static/src/xml/base.xml:0 +msgid "About OpenERP" +msgstr "O OpenERP" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP" +msgstr "OpenERP" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"is a free enterprise-scale software system that is designed to boost\n" +" productivity and profit through data integration. It connects, " +"improves and\n" +" manages business processes in areas such as sales, finance, " +"supply chain,\n" +" project management, production, services, CRM, etc..." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"The system is platform-independent, and can be installed on Windows, Mac OS " +"X,\n" +" and various Linux and other Unix-based distributions. Its " +"architecture enables\n" +" new functionality to be rapidly created, modifications to be " +"made to a\n" +" production system and migration to a new version to be " +"straightforward." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Depending on your needs, OpenERP is available through a web or application " +"client." +msgstr "" diff --git a/addons/web/po/nl.po b/addons/web/po/nl.po new file mode 100644 index 00000000000..a365691f314 --- /dev/null +++ b/addons/web/po/nl.po @@ -0,0 +1,694 @@ +# Dutch translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:38+0200\n" +"PO-Revision-Date: 2011-12-01 13:56+0000\n" +"Last-Translator: Douwe Wullink (Dypalio) \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: 2011-12-02 05:27+0000\n" +"X-Generator: Launchpad (build 14414)\n" + +#: addons/web/static/src/js/view_form.js:355 +msgid "" +"Warning, the record has been modified, your changes will be discarded." +msgstr "Letop: het record is gewijzigd; uw wijzigingen gaan verloren." + +#: addons/web/static/src/js/view_form.js:1659 +msgid "   Search More..." +msgstr "   Zoek verder..." + +#: addons/web/static/src/js/view_form.js:1672 +#, python-format +msgid "   Create \"%s\"" +msgstr "   Maak \"%s\"" + +#: addons/web/static/src/js/view_form.js:1678 +msgid "   Create and Edit..." +msgstr "   Maak en wijzig..." + +#: addons/web/static/src/js/views.js:568 +msgid "You must choose at least one record." +msgstr "U moet tenminste één record kiezen." + +#: addons/web/static/src/js/views.js:569 +msgid "Warning" +msgstr "Waarschuwing" + +#: addons/web/static/src/js/views.js:609 +msgid "Translations" +msgstr "Vertalingen" + +#: addons/web/static/src/js/views.js:614 addons/web/static/src/xml/base.xml:0 +msgid "Save" +msgstr "Opslaan" + +#: addons/web/static/src/js/views.js:615 +msgid "Close" +msgstr "Sluiten" + +#: addons/web/static/src/xml/base.xml:0 +msgid "x" +msgstr "x" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#{title}" +msgstr "#{title}" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#{text}" +msgstr "#{text}" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Powered by" +msgstr "Powered by" + +#: addons/web/static/src/xml/base.xml:0 +msgid "openerp.com" +msgstr "openerp.com" + +#: addons/web/static/src/xml/base.xml:0 +msgid "." +msgstr "." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Loading..." +msgstr "Laden..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create" +msgstr "Maken" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Drop" +msgstr "Verwijderen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Backup" +msgstr "Backup" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Restore" +msgstr "Terugzetten" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Password" +msgstr "Wachtwoord" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Back to Login" +msgstr "Terug naar aanmelding" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CREATE DATABASE" +msgstr "DATABASE MAKEN" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Master password:" +msgstr "Master wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New database name:" +msgstr "Naam nieuwe database:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Load Demonstration data:" +msgstr "Demonstratiegegevens laden:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Default language:" +msgstr "Standaardtaal:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Admin password:" +msgstr "Admin wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm password:" +msgstr "Bevestig wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "DROP DATABASE" +msgstr "DATABASE VERWIJDEREN" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Database:" +msgstr "Database:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Master Password:" +msgstr "Master wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "BACKUP DATABASE" +msgstr "DATABASE BACKUP" + +#: addons/web/static/src/xml/base.xml:0 +msgid "RESTORE DATABASE" +msgstr "DATABASE TERUGZETTEN" + +#: addons/web/static/src/xml/base.xml:0 +msgid "File:" +msgstr "Bestand:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CHANGE MASTER PASSWORD" +msgstr "MASTER WACHTWOORD WIJZIGEN" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New master password:" +msgstr "Nieuw master wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm new master password:" +msgstr "Bevestig nieuw master wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "User:" +msgstr "Gebruiker:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Password:" +msgstr "Wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Database" +msgstr "Database" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Login" +msgstr "Aanmelden" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Bad username or password" +msgstr "Verkeerde gebruikersnaam of wachtwoord" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"We think that daily job activities can be more intuitive, efficient, " +"automated, .. and even fun." +msgstr "" +"Wij denken dat dagelijks werk intuïtiever, efficiënter, automatischer kan " +"zijn, ...en zelfs leuk." + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP's vision to be:" +msgstr "OpenERP's visie is:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Full featured" +msgstr "Uitgebreide functionaliteit" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Today's enterprise challenges are multiple. We provide one module for each " +"need." +msgstr "" +"Bedrijven kennen vandaag de dag veel uitdagingen. We hebben een module voor " +"elke behoefte." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Open Source" +msgstr "Open Source" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"To Build a great product, we rely on the knowledge of thousands of " +"contributors." +msgstr "" +"Om een prima product te bouwen, rekenen we op de kennis van duizenden " +"bijdragers." + +#: addons/web/static/src/xml/base.xml:0 +msgid "User Friendly" +msgstr "Gebruikersvriendelijk" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"In order to be productive, people need clean and easy to use interface." +msgstr "" +"Om productief te zijn hebben mensen een net en simpel gebruikersinterface " +"nodig." + +#: addons/web/static/src/xml/base.xml:0 +msgid "(" +msgstr "(" + +#: addons/web/static/src/xml/base.xml:0 +msgid ")" +msgstr ")" + +#: addons/web/static/src/xml/base.xml:0 +msgid "LOGOUT" +msgstr "AFMELDEN" + +#: addons/web/static/src/xml/base.xml:0 +msgid "«" +msgstr "«" + +#: addons/web/static/src/xml/base.xml:0 +msgid "»" +msgstr "»" + +#: addons/web/static/src/xml/base.xml:0 +msgid "oe_secondary_menu_item" +msgstr "oe_secondary_menu_item" + +#: addons/web/static/src/xml/base.xml:0 +msgid "oe_secondary_submenu_item" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Hide this tip" +msgstr "Verberg deze tip" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Disable all tips" +msgstr "Alle tips uitzetten" + +#: addons/web/static/src/xml/base.xml:0 +msgid "View#" +msgstr "View#" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Fields" +msgstr "Velden" + +#: addons/web/static/src/xml/base.xml:0 +msgid "View labels" +msgstr "Weergave labels" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Sidebar Relates" +msgstr "Sidebar koppelingen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Field" +msgstr "Veld" + +#: addons/web/static/src/xml/base.xml:0 +msgid ":" +msgstr ":" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Translate view" +msgstr "Vertaal weergave" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Translate sidebar" +msgstr "Sidebar vertalen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delete" +msgstr "Verwijderen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "First" +msgstr "Eerste" + +#: addons/web/static/src/xml/base.xml:0 +msgid "<" +msgstr "<" + +#: addons/web/static/src/xml/base.xml:0 +msgid ">" +msgstr ">" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Last" +msgstr "Laatste" + +#: addons/web/static/src/xml/base.xml:0 +msgid "♻" +msgstr "♻" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & Edit" +msgstr "Opslaan & Wijzigen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create & Edit" +msgstr "Maken & Wijzigen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New" +msgstr "Nieuw" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Duplicate" +msgstr "Dupliceren" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Readonly/Editable" +msgstr "Leesbaar/Wijzigbaar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "<<" +msgstr "<<" + +#: addons/web/static/src/xml/base.xml:0 +msgid "0" +msgstr "0" + +#: addons/web/static/src/xml/base.xml:0 +msgid "/" +msgstr "/" + +#: addons/web/static/src/xml/base.xml:0 +msgid ">>" +msgstr ">>" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Add" +msgstr "Toevoegen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Unhandled widget" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "?" +msgstr "?" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#" +msgstr "#" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Done" +msgstr "Gereed" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Open..." +msgstr "Openen..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create..." +msgstr "Aanmaken…" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Search..." +msgstr "Zoeken…" + +#: addons/web/static/src/xml/base.xml:0 +msgid "..." +msgstr "..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Uploading ..." +msgstr "Uploaden ..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Select" +msgstr "Selecteren" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save As" +msgstr "Opslaan als" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Clear" +msgstr "Wissen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Advanced Filter" +msgstr "Geavanceerd filter" + +#: addons/web/static/src/xml/base.xml:0 +msgid "-- Filters --" +msgstr "-- Filters --" + +#: addons/web/static/src/xml/base.xml:0 +msgid "-- Actions --" +msgstr "-- Acties --" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save Filter" +msgstr "Filter opslaan" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Manage Filters" +msgstr "Filters beheren" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Filter Name:" +msgstr "Filternaam:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "(Any existing filter with the same name will be replaced)" +msgstr "(Een bestaand filter met dezelfde naam wordt vervangen)" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Any of the following conditions must match" +msgstr "Één van de volgende voorwaarden moet voldoen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "All the following conditions must match" +msgstr "Alle volgende voorwaarden moeten voldoen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "None of the following conditions must match" +msgstr "Geen van de volgende voorwaarden mag voldoen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Add condition" +msgstr "Voorwaarde toevoegen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "and" +msgstr "en" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Cancel" +msgstr "Annuleren" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & New" +msgstr "Opslaan & Nieuw" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & Close" +msgstr "Opslaan & Sluiten" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export" +msgstr "Exporteren" + +#: addons/web/static/src/xml/base.xml:0 +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 "" +"Deze assistent exporteert alle gegevens die aan de huidige zoekcriteria " +"voldoen naar een CSV bestand.\n" +" U kunt alle gegevens exporteren of alleen de velden die na " +"wijziging opnieuw kunnen worden geïmporteerd." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export Type:" +msgstr "Soort export:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Compatible Export" +msgstr "Import compatibele export" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export all Data" +msgstr "Alle gegevens exporteren" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export Formats" +msgstr "Export Formaten" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Available fields" +msgstr "Beschikbare velden" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Fields to export" +msgstr "Te exporteren velden" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save fields list" +msgstr "Veldenlijst opslaan" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Remove" +msgstr "Verwijderen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Remove All" +msgstr "Alles verwijderen" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Name" +msgstr "Naam" + +#: addons/web/static/src/xml/base.xml:0 +msgid " " +msgstr " " + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save as:" +msgstr "Opslaan als:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Ok" +msgstr "Ok" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Saved exports:" +msgstr "Opgeslagen exports:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Old Password:" +msgstr "Oud wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New Password:" +msgstr "Nieuw wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm Password:" +msgstr "Bevestig wachtwoord:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import" +msgstr "Importeren" + +#: addons/web/static/src/xml/base.xml:0 +msgid "1. Import a .CSV file" +msgstr "1. Importeer een .CSV bestand" + +#: addons/web/static/src/xml/base.xml:0 +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 "" +"Selecteer een .CSV bestand voor import. Voor een voorbeeld van een " +"importbestand,\n" +" kunt u de export tool gebruiken met de \"Import Compatibel\" optie." + +#: addons/web/static/src/xml/base.xml:0 +msgid "CSV File:" +msgstr "CSV bestand:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "2. Check your file format" +msgstr "2. Controleer uw bestandsformaat" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Options" +msgstr "Importeeropties" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Does your file have titles?" +msgstr "Heeft uw bestand titels?" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Separator:" +msgstr "Scheidingsteken:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delimiter:" +msgstr "Veldscheidingsteken:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Encoding:" +msgstr "Codering:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "UTF-8" +msgstr "UTF-8" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Latin 1" +msgstr "Latin 1" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Lines to skip" +msgstr "Regels om over te slaan" + +#: addons/web/static/src/xml/base.xml:0 +msgid "The import failed due to:" +msgstr "Importeren mislukt wegens:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Here is a preview of the file we could not import:" +msgstr "Hier is een voorbeeld van het bestand dat we niet konden importeren:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP Web" +msgstr "OpenERP Web" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Version" +msgstr "Versie" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Copyright © 2011-TODAY OpenERP SA. All Rights Reserved." +msgstr "Copyright © 2011-VANDAAG OpenERP SA. Alle rechten voorbehouden." + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP is a trademark of the" +msgstr "OpenERP is een handelsmerk van" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP SA Company" +msgstr "OpenERP SA" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Licenced under the terms of" +msgstr "Gelicentieerd onder voorwaarden van" + +#: addons/web/static/src/xml/base.xml:0 +msgid "GNU Affero General Public License" +msgstr "GNU Affero General Public License" + +#: addons/web/static/src/xml/base.xml:0 +msgid "About OpenERP" +msgstr "Over OpenERP" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP" +msgstr "OpenERP" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"is a free enterprise-scale software system that is designed to boost\n" +" productivity and profit through data integration. It connects, " +"improves and\n" +" manages business processes in areas such as sales, finance, " +"supply chain,\n" +" project management, production, services, CRM, etc..." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"The system is platform-independent, and can be installed on Windows, Mac OS " +"X,\n" +" and various Linux and other Unix-based distributions. Its " +"architecture enables\n" +" new functionality to be rapidly created, modifications to be " +"made to a\n" +" production system and migration to a new version to be " +"straightforward." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Depending on your needs, OpenERP is available through a web or application " +"client." +msgstr "" +"Naar behoefte is OpenERP als webapplicatie of als client-serverapplicatie " +"beschikbaar." diff --git a/addons/web/po/zh_TW.po b/addons/web/po/zh_TW.po new file mode 100644 index 00000000000..5f1d4123bb1 --- /dev/null +++ b/addons/web/po/zh_TW.po @@ -0,0 +1,677 @@ +# Chinese (Traditional) translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:38+0200\n" +"PO-Revision-Date: 2011-12-04 16:06+0000\n" +"Last-Translator: Walter Cheuk \n" +"Language-Team: Chinese (Traditional) \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2011-12-05 05:44+0000\n" +"X-Generator: Launchpad (build 14418)\n" + +#: addons/web/static/src/js/view_form.js:355 +msgid "" +"Warning, the record has been modified, your changes will be discarded." +msgstr "" + +#: addons/web/static/src/js/view_form.js:1659 +msgid "   Search More..." +msgstr "   搜尋更多..." + +#: addons/web/static/src/js/view_form.js:1672 +#, python-format +msgid "   Create \"%s\"" +msgstr "   建立「%s」" + +#: addons/web/static/src/js/view_form.js:1678 +msgid "   Create and Edit..." +msgstr "   建立並編輯..." + +#: addons/web/static/src/js/views.js:568 +msgid "You must choose at least one record." +msgstr "要選擇至少一個紀錄。" + +#: addons/web/static/src/js/views.js:569 +msgid "Warning" +msgstr "警告" + +#: addons/web/static/src/js/views.js:609 +msgid "Translations" +msgstr "翻譯" + +#: addons/web/static/src/js/views.js:614 addons/web/static/src/xml/base.xml:0 +msgid "Save" +msgstr "儲存" + +#: addons/web/static/src/js/views.js:615 +msgid "Close" +msgstr "關閉" + +#: addons/web/static/src/xml/base.xml:0 +msgid "x" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#{title}" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#{text}" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Powered by" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "openerp.com" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Loading..." +msgstr "載入..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create" +msgstr "建立" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Drop" +msgstr "捨棄" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Backup" +msgstr "備份" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Restore" +msgstr "還原" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Password" +msgstr "密碼" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Back to Login" +msgstr "返回登入畫面" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CREATE DATABASE" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Master password:" +msgstr "主密碼:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New database name:" +msgstr "新資料庫名稱:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Load Demonstration data:" +msgstr "載入演示資料:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Default language:" +msgstr "預設語言:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Admin password:" +msgstr "管理員密碼:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm password:" +msgstr "確認密碼:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "DROP DATABASE" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Database:" +msgstr "資料庫:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Master Password:" +msgstr "主密碼:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "BACKUP DATABASE" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "RESTORE DATABASE" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "File:" +msgstr "檔案:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CHANGE MASTER PASSWORD" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New master password:" +msgstr "新主密碼:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm new master password:" +msgstr "確認新主密碼:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "User:" +msgstr "使用者:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Password:" +msgstr "密碼:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Database" +msgstr "資料庫" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Login" +msgstr "登入" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Bad username or password" +msgstr "使用者名稱或密碼不對" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"We think that daily job activities can be more intuitive, efficient, " +"automated, .. and even fun." +msgstr "我們認為日常工作可以更直觀、更有效率、更自動化......以至更有趣。" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP's vision to be:" +msgstr "OpenERP 的願景為:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Full featured" +msgstr "完整功能" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Today's enterprise challenges are multiple. We provide one module for each " +"need." +msgstr "今時今日企業面對的問題很多。我們為每件工作皆提供處理的模組。" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Open Source" +msgstr "開源碼" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"To Build a great product, we rely on the knowledge of thousands of " +"contributors." +msgstr "要製作好用的產品,我們靠的是成千上萬的自願貢獻者。" + +#: addons/web/static/src/xml/base.xml:0 +msgid "User Friendly" +msgstr "易用" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"In order to be productive, people need clean and easy to use interface." +msgstr "要工作更有效率,人們要更簡潔、更易用的介面。" + +#: addons/web/static/src/xml/base.xml:0 +msgid "(" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid ")" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "LOGOUT" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "«" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "»" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "oe_secondary_menu_item" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "oe_secondary_submenu_item" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Hide this tip" +msgstr "隱藏此提示" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Disable all tips" +msgstr "停用所有提示" + +#: addons/web/static/src/xml/base.xml:0 +msgid "View#" +msgstr "檢視#" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Fields" +msgstr "欄位" + +#: addons/web/static/src/xml/base.xml:0 +msgid "View labels" +msgstr "檢視標籤" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Sidebar Relates" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Field" +msgstr "欄位" + +#: addons/web/static/src/xml/base.xml:0 +msgid ":" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Translate view" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Translate sidebar" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delete" +msgstr "刪除" + +#: addons/web/static/src/xml/base.xml:0 +msgid "First" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "<" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid ">" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Last" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "♻" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & Edit" +msgstr "儲存並編輯" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create & Edit" +msgstr "建立並編輯" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New" +msgstr "新增" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Duplicate" +msgstr "製作複本" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Readonly/Editable" +msgstr "唯讀/可編輯" + +#: addons/web/static/src/xml/base.xml:0 +msgid "<<" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "0" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "/" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid ">>" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Add" +msgstr "添加" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Unhandled widget" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "?" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "#" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Done" +msgstr "完成" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Open..." +msgstr "開啟..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create..." +msgstr "建立..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Search..." +msgstr "搜尋..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "..." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Uploading ..." +msgstr "上載 ..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Select" +msgstr "選取" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save As" +msgstr "另存為" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Clear" +msgstr "清除" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Advanced Filter" +msgstr "進階篩選" + +#: addons/web/static/src/xml/base.xml:0 +msgid "-- Filters --" +msgstr "-- 篩選 --" + +#: addons/web/static/src/xml/base.xml:0 +msgid "-- Actions --" +msgstr "-- 動作 --" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save Filter" +msgstr "儲存篩選" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Manage Filters" +msgstr "管理篩選" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Filter Name:" +msgstr "篩選名稱:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "(Any existing filter with the same name will be replaced)" +msgstr "(會取代所有同名篩選)" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Any of the following conditions must match" +msgstr "以下任何條件都要符合" + +#: addons/web/static/src/xml/base.xml:0 +msgid "All the following conditions must match" +msgstr "以下所有條件都要符合" + +#: addons/web/static/src/xml/base.xml:0 +msgid "None of the following conditions must match" +msgstr "以下無一條件需要符合" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Add condition" +msgstr "添加條件" + +#: addons/web/static/src/xml/base.xml:0 +msgid "and" +msgstr "和" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Cancel" +msgstr "取消" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & New" +msgstr "儲存並新增" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & Close" +msgstr "儲存並關閉" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export" +msgstr "匯出" + +#: addons/web/static/src/xml/base.xml:0 +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 "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export Type:" +msgstr "匯出類型:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Compatible Export" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export all Data" +msgstr "匯出所有資料" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export Formats" +msgstr "匯出格式" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Available fields" +msgstr "可提供欄位" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Fields to export" +msgstr "要匯出欄位" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save fields list" +msgstr "儲存欄位清單" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Remove" +msgstr "移除" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Remove All" +msgstr "全部移除" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Name" +msgstr "名稱" + +#: addons/web/static/src/xml/base.xml:0 +msgid " " +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save as:" +msgstr "另存為:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Ok" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Saved exports:" +msgstr "已儲存匯出:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Old Password:" +msgstr "舊密碼:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New Password:" +msgstr "新密碼:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm Password:" +msgstr "確認密碼:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import" +msgstr "匯入" + +#: addons/web/static/src/xml/base.xml:0 +msgid "1. Import a .CSV file" +msgstr "1. 匯入 .CSV 檔" + +#: addons/web/static/src/xml/base.xml:0 +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 "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "CSV File:" +msgstr "CSV 檔:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "2. Check your file format" +msgstr "2. 檢查檔案格式" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Options" +msgstr "匯入選項" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Does your file have titles?" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Separator:" +msgstr "分隔符號:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delimiter:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Encoding:" +msgstr "編碼:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "UTF-8" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Latin 1" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Lines to skip" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "The import failed due to:" +msgstr "匯入失敗,原因為:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Here is a preview of the file we could not import:" +msgstr "無法匯入檔案的預覽:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP Web" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Version" +msgstr "版本" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Copyright © 2011-TODAY OpenERP SA. All Rights Reserved." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP is a trademark of the" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP SA Company" +msgstr "OpenERP SA 公司" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Licenced under the terms of" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "GNU Affero General Public License" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "About OpenERP" +msgstr "有關 OpenERP" + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"is a free enterprise-scale software system that is designed to boost\n" +" productivity and profit through data integration. It connects, " +"improves and\n" +" manages business processes in areas such as sales, finance, " +"supply chain,\n" +" project management, production, services, CRM, etc..." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"The system is platform-independent, and can be installed on Windows, Mac OS " +"X,\n" +" and various Linux and other Unix-based distributions. Its " +"architecture enables\n" +" new functionality to be rapidly created, modifications to be " +"made to a\n" +" production system and migration to a new version to be " +"straightforward." +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Depending on your needs, OpenERP is available through a web or application " +"client." +msgstr "" diff --git a/addons/web/static/lib/jquery.tipTip/jquery.tipTip.js b/addons/web/static/lib/jquery.tipTip/jquery.tipTip.js index 0b3a24d4beb..d5295f1e155 100644 --- a/addons/web/static/lib/jquery.tipTip/jquery.tipTip.js +++ b/addons/web/static/lib/jquery.tipTip/jquery.tipTip.js @@ -94,7 +94,7 @@ function active_tiptip(){ opts.enter.call(this); - var org_title = typeof opts.content === 'function' ? opts.content() : opts.content; + var org_title = typeof opts.content === 'function' ? opts.content.call(org_elem, opts) : opts.content; org_title = org_title || org_elem.attr(opts.attribute); tiptip_content.html(org_title); tiptip_holder.hide().removeAttr("class").css("margin","0"); diff --git a/addons/web/static/lib/jquery/jquery-1.6.2.js b/addons/web/static/lib/jquery/jquery-1.6.4.js similarity index 96% rename from addons/web/static/lib/jquery/jquery-1.6.2.js rename to addons/web/static/lib/jquery/jquery-1.6.4.js index f3201aacb6f..11e6d067962 100644 --- a/addons/web/static/lib/jquery/jquery-1.6.2.js +++ b/addons/web/static/lib/jquery/jquery-1.6.4.js @@ -1,5 +1,5 @@ /*! - * jQuery JavaScript Library v1.6.2 + * jQuery JavaScript Library v1.6.4 * http://jquery.com/ * * Copyright 2011, John Resig @@ -11,7 +11,7 @@ * Copyright 2011, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * - * Date: Thu Jun 30 14:16:56 2011 -0400 + * Date: Mon Sep 12 18:54:48 2011 -0400 */ (function( window, undefined ) { @@ -37,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/, @@ -66,11 +66,12 @@ var jQuery = function( selector, context ) { rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, // Matches dashed string for camelizing - rdashAlpha = /-([a-z])/ig, + rdashAlpha = /-([a-z]|[0-9])/ig, + rmsPrefix = /^-ms-/, // Used by jQuery.camelCase as callback to replace() fcamelCase = function( all, letter ) { - return letter.toUpperCase(); + return ( letter + "" ).toUpperCase(); }, // Keep a UserAgent string for use with jQuery.browser @@ -212,7 +213,7 @@ jQuery.fn = jQuery.prototype = { selector: "", // The current version of jQuery being used - jquery: "1.6.2", + jquery: "1.6.4", // The default length of a jQuery object is 0 length: 0, @@ -521,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; } @@ -574,24 +580,23 @@ jQuery.extend({ }, // 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; }, @@ -611,10 +616,10 @@ jQuery.extend({ } }, - // Converts a dashed string to camelCased string; - // Used by both the css and data modules + // 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( rdashAlpha, fcamelCase ); + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); }, nodeName: function( elem, name ) { @@ -699,6 +704,9 @@ jQuery.extend({ }, inArray: function( elem, array ) { + if ( !array ) { + return -1; + } if ( indexOf ) { return indexOf.call( array, elem ); @@ -1071,7 +1079,7 @@ jQuery.extend({ if ( returned && jQuery.isFunction( returned.promise ) ) { returned.promise().then( newDefer.resolve, newDefer.reject ); } else { - newDefer[ action ]( returned ); + newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); } }); } else { @@ -1173,6 +1181,7 @@ jQuery.support = (function() { div.setAttribute("className", "t"); div.innerHTML = "
a"; + all = div.getElementsByTagName( "*" ); a = div.getElementsByTagName( "a" )[ 0 ]; @@ -1293,13 +1302,14 @@ jQuery.support = (function() { width: 0, height: 0, border: 0, - margin: 0 + margin: 0, + background: "none" }; if ( body ) { jQuery.extend( testElementStyle, { position: "absolute", - left: -1000, - top: -1000 + left: "-1000px", + top: "-1000px" }); } for ( i in testElementStyle ) { @@ -1404,7 +1414,7 @@ jQuery.boxModel = jQuery.support.boxModel; var rbrace = /^(?:\{.*\}|\[.*\])$/, - rmultiDash = /([a-z])([A-Z])/g; + rmultiDash = /([A-Z])/g; jQuery.extend({ cache: {}, @@ -1436,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 @@ -1452,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; } @@ -1511,10 +1523,24 @@ jQuery.extend({ return thisCache[ internalKey ] && thisCache[ internalKey ].events; } - return getByName ? - // Check for both converted-to-camel and non-converted data property names - thisCache[ jQuery.camelCase( name ) ] || 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 */ ) { @@ -1522,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, @@ -1537,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 @@ -1566,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; @@ -1690,7 +1729,8 @@ 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 ) { - var name = "data-" + key.replace( rmultiDash, "$1-$2" ).toLowerCase(); + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); data = elem.getAttribute( name ); @@ -1910,8 +1950,7 @@ var rclass = /[\n\t\r]/g, rfocusable = /^(?:button|input|object|select|textarea)$/i, rclickable = /^a(?:rea)?$/i, rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, - rinvalidChar = /\:|^on/, - formHook, boolHook; + nodeHook, boolHook; jQuery.fn.extend({ attr: function( name, value ) { @@ -2049,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; } } @@ -2229,14 +2268,11 @@ jQuery.extend({ if ( !hooks ) { // Use boolHook for boolean attributes if ( rboolean.test( name ) ) { - hooks = boolHook; - // Use formHook for forms and if the name contains certain characters - } else if ( formHook && name !== "className" && - (jQuery.nodeName( elem, "form" ) || rinvalidChar.test( name )) ) { - - hooks = formHook; + // Use nodeHook if available( IE6/7 ) + } else if ( nodeHook ) { + hooks = nodeHook; } } } @@ -2273,14 +2309,9 @@ jQuery.extend({ var propName; if ( elem.nodeType === 1 ) { name = jQuery.attrFix[ name ] || name; - - if ( jQuery.support.getSetAttribute ) { - // Use removeAttribute in browsers that support it - elem.removeAttribute( name ); - } else { - jQuery.attr( elem, name, "" ); - elem.removeAttributeNode( elem.getAttributeNode( 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 ) { @@ -2308,33 +2339,20 @@ jQuery.extend({ } } }, - 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; - } - }, // Use the value property for back compat - // Use the formHook for button elements in IE6/7 (#1954) + // Use the nodeHook for button elements in IE6/7 (#1954) value: { get: function( elem, name ) { - if ( formHook && jQuery.nodeName( elem, "button" ) ) { - return formHook.get( 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 ( formHook && jQuery.nodeName( elem, "button" ) ) { - return formHook.set( 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; @@ -2383,7 +2401,7 @@ jQuery.extend({ } } else { - if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== undefined ) { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { return ret; } else { @@ -2392,14 +2410,33 @@ jQuery.extend({ } }, - propHooks: {} + 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; + } + } + } }); +// 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 - return jQuery.prop( elem, name ) ? + // 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; }, @@ -2425,12 +2462,10 @@ boolHook = { // IE6/7 do not support getting/setting some attributes with get/setAttribute if ( !jQuery.support.getSetAttribute ) { - - // propFix is more comprehensive and contains all fixes - jQuery.attrFix = jQuery.propFix; - // Use this for any attribute on a form in IE6/7 - formHook = jQuery.attrHooks.name = jQuery.attrHooks.title = jQuery.valHooks.button = { + // 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 ); @@ -2440,13 +2475,13 @@ if ( !jQuery.support.getSetAttribute ) { undefined; }, set: function( elem, value, name ) { - // Check form objects in IE (multiple bugs related) - // Only use nodeValue if the attribute node exists on the form + // Set the existing or create a new attribute node var ret = elem.getAttributeNode( name ); - if ( ret ) { - ret.nodeValue = value; - return value; + if ( !ret ) { + ret = document.createAttribute( name ); + elem.setAttributeNode( ret ); } + return (ret.nodeValue = value + ""); } }; @@ -2505,6 +2540,7 @@ if ( !jQuery.support.optSelected ) { parent.parentNode.selectedIndex; } } + return null; } }); } @@ -3235,8 +3271,9 @@ if ( !jQuery.support.submitBubbles ) { setup: function( data, namespaces ) { 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 ); @@ -3245,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 ); @@ -3270,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; @@ -5295,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 @@ -6048,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] ); + } } } @@ -6248,14 +6294,14 @@ function evalScript( i, elem ) { + var ralpha = /alpha\([^)]*\)/i, ropacity = /opacity=([^)]*)/, // fixed for IE9, see #8346 rupper = /([A-Z]|^ms)/g, rnumpx = /^-?\d+(?:px)?$/i, rnum = /^-?\d/, - rrelNum = /^[+\-]=/, - rrelNumFilter = /[^+\-\.\de]+/g, + rrelNum = /^([\-+])=([\-+.\de]+)/, cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssWidth = [ "Left", "Right" ], @@ -6332,18 +6378,18 @@ jQuery.extend({ if ( value !== undefined ) { type = typeof value; - // Make sure that NaN and null values aren't set. See: #7116 - if ( type === "number" && isNaN( value ) || value == null ) { - return; - } - // convert relative number strings (+= or -=) to relative numbers. #7345 - if ( type === "string" && rrelNum.test( value ) ) { - value = +value.replace( rrelNumFilter, "" ) + parseFloat( jQuery.css( elem, name ) ); + 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 ( value == null || type === "number" && isNaN( value ) ) { + return; + } + // If a number was passed in, add 'px' to the (except for certain CSS properties) if ( type === "number" && !jQuery.cssNumber[ origName ] ) { value += "px"; @@ -6459,18 +6505,29 @@ if ( !jQuery.support.opacity ) { set: function( elem, value ) { var style = elem.style, - currentStyle = elem.currentStyle; + 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 = currentStyle && currentStyle.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, "" ) ) === "" ) { + // 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; @@ -6625,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 = /^(?:about|app|app\-storage|.+\-extension|file|widget):$/, + rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, rnoContent = /^(?:GET|HEAD)$/, rprotocol = /^\/\//, rquery = /\?/, @@ -6662,7 +6719,10 @@ 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 window.location if document.domain has been set @@ -6755,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 ) { @@ -6898,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; }, @@ -6942,7 +7011,7 @@ jQuery.extend({ html: "text/html", text: "text/plain", json: "application/json, text/javascript", - "*": "*/*" + "*": allTypes }, contents: { @@ -6972,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 } }, @@ -7082,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 ) { @@ -7105,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; @@ -7161,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 ) { @@ -7183,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" ); @@ -7264,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 @@ -7301,7 +7382,7 @@ jQuery.extend({ jqXHR.setRequestHeader( "Accept", s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? - s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) : + s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : s.accepts[ "*" ] ); @@ -7347,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 { @@ -7995,10 +8076,7 @@ var elemdisplay = {}, // opacity animations [ "opacity" ] ], - fxNow, - requestAnimationFrame = window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.oRequestAnimationFrame; + fxNow; jQuery.fn.extend({ show: function( speed, easing, callback ) { @@ -8374,8 +8452,7 @@ jQuery.fx.prototype = { // Start an animation from one number to another custom: function( from, to, unit ) { var self = this, - fx = jQuery.fx, - raf; + fx = jQuery.fx; this.startTime = fxNow || createFxNow(); this.start = from; @@ -8391,20 +8468,7 @@ jQuery.fx.prototype = { t.elem = this.elem; if ( t() && jQuery.timers.push(t) && !timerId ) { - // Use requestAnimationFrame instead of setInterval if available - if ( requestAnimationFrame ) { - timerId = true; - raf = function() { - // When timerId gets set to null at any point, this stops - if ( timerId ) { - requestAnimationFrame( raf ); - fx.tick(); - } - }; - requestAnimationFrame( raf ); - } else { - timerId = setInterval( fx.tick, fx.interval ); - } + timerId = setInterval( fx.tick, fx.interval ); } }, @@ -8947,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 ) { diff --git a/addons/web/static/lib/qunit/qunit-2011-23-22.css b/addons/web/static/lib/qunit/qunit-2011-23-22.css deleted file mode 100644 index cc791a9b099..00000000000 --- a/addons/web/static/lib/qunit/qunit-2011-23-22.css +++ /dev/null @@ -1,248 +0,0 @@ -/** 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; -} - -#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; -} - -#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/qunit/qunit-2011-23-22.js b/addons/web/static/lib/qunit/qunit-2011-23-22.js deleted file mode 100644 index 18f8ae1715c..00000000000 --- a/addons/web/static/lib/qunit/qunit-2011-23-22.js +++ /dev/null @@ -1,1456 +0,0 @@ -/* - * QUnit - 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; - - 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) { - QUnit.moduleDone({ - 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 }; - QUnit.moduleStart({ - name: this.module - }); - } - - config.current = this; - this.testEnvironment = extend({ - setup: function() { - }, - teardown: function() { - } - }, this.moduleTestEnvironment); - if (this.testEnvironmentArg) { - extend(this.testEnvironment, this.testEnvironmentArg); - } - - QUnit.testStart({ - name: this.testName - }); - - // 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() { - 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) { - start(); - } - } - }, - teardown: function() { - try { - checkPollution(); - this.testEnvironment.teardown.call(this.testEnvironment); - } catch(e) { - QUnit.ok(false, "Teardown failed on " + this.testName + ": " + e.message); - } - }, - finish: function() { - if (this.expected && 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.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); - } - - QUnit.testDone({ - name: this.testName, - 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); - } - ; - } - - }; - - 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 = 0; - } - - 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 = escapeHtml(msg); - QUnit.log(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() { - config.semaphore--; - 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.timeout) { - clearTimeout(config.timeout); - } - - config.blocking = false; - process(); - }, 13); - } else { - config.blocking = false; - process(); - } - }, - - stop: function(timeout) { - config.semaphore++; - config.blocking = true; - - if (timeout && defined.setTimeout) { - clearTimeout(config.timeout); - config.timeout = window.setTimeout(function() { - QUnit.ok(false, "Test timed out"); - QUnit.start(); - }, timeout); - } - } - }; - -// 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, - - // by default, run previously failed tests first - // very useful in combination with "Hide passed tests" checked - reorder: true, - - noglobals: false, - notrycatch: false - }; - -// 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 ]; - if (current[ 0 ] in config) { - config[ 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("#main, #qunit-fixture").html(config.fixture); - } else { - var main = id('main') || id('qunit-fixture'); - if (main) { - main.innerHTML = config.fixture; - } - } - }, - - /** - * Trigger an event on an element. - * - * @example triggerEvent( document.body, "click" ); - * - * @param {Element} 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 = Object.prototype.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 = escapeHtml(message) || (result ? "okay" : "failed"); - message = '' + message + ""; - expected = escapeHtml(QUnit.jsDump.parse(expected)); - actual = escapeHtml(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:
' + source + '
"; - - QUnit.log(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) { - querystring += encodeURIComponent(key) + "=" + - encodeURIComponent(params[ key ]) + "&"; - } - return window.location.pathname + querystring.slice(0, -1); - }, - - // Logging callbacks; all receive a single argument with the listed properties - // run test/logs.html for any related changes - begin: function() { - }, - // done: { failed, passed, total, runtime } - done: function() { - }, - // log: { result, actual, expected, message } - log: function() { - }, - // testStart: { name } - testStart: function() { - }, - // testDone: { name, failed, passed, total } - testDone: function() { - }, - // moduleStart: { name } - moduleStart: function() { - }, - // moduleDone: { name, failed, passed, total } - moduleDone: function() { - } - }); - - if (typeof document === "undefined" || document.readyState === "complete") { - config.autorun = true; - } - - addEvent(window, "load", function() { - QUnit.begin({}); - - // Initialize the config, saving the execution queue - var oldconfig = extend({}, config); - QUnit.init(); - extend(config, oldconfig); - - config.blocking = false; - - var userAgent = id("qunit-userAgent"); - if (userAgent) { - userAgent.innerHTML = navigator.userAgent; - } - var banner = id("qunit-header"); - if (banner) { - banner.innerHTML = ' ' + banner.innerHTML + ' ' + - '' + - ''; - 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 (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('main') || id('qunit-fixture'); - if (main) { - config.fixture = main.innerHTML; - } - - if (config.autostart) { - QUnit.start(); - } - }); - - function done() { - config.autorun = true; - - // Log the last module results - if (config.currentModule) { - QUnit.moduleDone({ - 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; - } - - QUnit.done({ - 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]; - } - } - } - - function escapeHtml(s) { - if (!s) { - return ""; - } - s = s + ""; - return s.replace(/[\&"<>\\]/g, function(s) { - switch (s) { - case "&": return "&"; - case "\\": return "\\\\"; - case '"': return '\"'; - case "<": return "<"; - case ">": return ">"; - default: return s; - } - }); - } - - function synchronize(callback) { - config.queue.push(callback); - - if (config.autorun && !config.blocking) { - process(); - } - } - - function process() { - var start = (new Date()).getTime(); - - while (config.queue.length && !config.blocking) { - if (config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate)) { - config.queue.shift()(); - } else { - window.setTimeout(process, 13); - break; - } - } - if (!config.blocking && !config.queue.length) { - done(); - } - } - - function saveGlobal() { - config.pollution = []; - - if (config.noglobals) { - for (var key in window) { - 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]; - } else { - 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); - } - -// Test for equality any JavaScript type. -// Discussions and reference: http://philrathe.com/articles/equiv -// Test suites: http://philrathe.com/tests/equiv -// 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 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) { - 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) { - var i = arr.length, ret = Array(i); - this.up(); - while (i--) - ret[i] = this.parse(arr[i]); - this.down(); - return join('[', ret, ']'); - } - - var reName = /^function (\w+)/; - - var jsDump = { - parse:function(obj, type) { //type is used mostly internally, you can fix a (custom)type in advance - var parser = this.parsers[ type || this.typeOf(obj) ]; - type = typeof parser; - - return type == 'function' ? parser.call(this, obj) : - 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 (typeof obj === "object" && typeof obj.length === "number" && obj.length >= 0) { - 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) { - var ret = [ ]; - QUnit.jsDump.up(); - for (var key in map) - ret.push(QUnit.jsDump.parse(key, 'key') + ': ' + QUnit.jsDump.parse(map[key])); - 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; - } - - /* - * 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 = new Object(); - var os = new Object(); - - for (var i = 0; i < n.length; i++) { - if (ns[n[i]] == null) - ns[n[i]] = { - rows: new Array(), - 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: new Array(), - n: null - }; - os[o[i]].rows.push(i); - } - - for (var i in ns) { - 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/qunit/qunit.css b/addons/web/static/lib/qunit/qunit.css new file mode 100755 index 00000000000..bcecc4c0daf --- /dev/null +++ b/addons/web/static/lib/qunit/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/qunit/qunit.js b/addons/web/static/lib/qunit/qunit.js new file mode 100755 index 00000000000..6d2a8a7b8ab --- /dev/null +++ b/addons/web/static/lib/qunit/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/qweb/qweb2.js b/addons/web/static/lib/qweb/qweb2.js index a6a6da5a6d7..093b3651fa0 100644 --- a/addons/web/static/lib/qweb/qweb2.js +++ b/addons/web/static/lib/qweb/qweb2.js @@ -373,6 +373,12 @@ QWeb2.Engine = (function() { if (!this.jQuery) { return this.tools.exception("Can't extend template " + template + " without jQuery"); } + var template_dest = this.templates[template], + msie_trololo = false; + if (template_dest.xml !== undefined) { + template_dest = this.jQuery(template_dest.xml); + msie_trololo = true; + } for (var i = 0, ilen = extend_node.childNodes.length; i < ilen; i++) { var child = extend_node.childNodes[i]; if (child.nodeType === 1) { @@ -382,7 +388,7 @@ QWeb2.Engine = (function() { target, error_msg = "Error while extending template '" + template; if (jquery) { - target = this.jQuery(jquery, this.templates[template]); + target = this.jQuery(jquery, template_dest); } else if (xpath) { // NOTE: due to the XPath implementation, extending a template will only work once // when using XPath because XPathResult won't match objects with other constructor than 'Element' @@ -415,6 +421,9 @@ QWeb2.Engine = (function() { } } } + if (msie_trololo) { + this.templates[template] = template_dest[0]; + } } }); return Engine; diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index cad536c0f1f..067ea09cd38 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -1,4 +1,3 @@ -/* TODO: separate openerp web client page css from openerp views css */ body.openerp { padding: 0; margin: 0; @@ -6,10 +5,17 @@ body.openerp { min-width: 1000px; overflow-y: scroll; font-size: 80%; + font-family: Ubuntu, Helvetica, sans-serif; } body.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; } .oe_box { @@ -29,6 +35,17 @@ body.openerp, .openerp textarea, .openerp input, .openerp select, .openerp optio .openerp .oe-listview .oe-number { text-align: right !important; } +.oe-listview-header-columns { + background: #444; /* 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; } @@ -261,7 +278,7 @@ label.error { 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 #6E2A24; + border: 1px solid #5E1A14; border-radius: 4px; -moz-border-radius: 4px; -webkit-border-radius: 4px; @@ -272,7 +289,7 @@ label.error { text-transform: uppercase; line-height: 20px; font-weight: bold; - font-size: 85%; + font-size: 75%; white-space: nowrap; } @@ -331,6 +348,7 @@ label.error { height: 100%; display: block; position: relative; + font-size:85%; } .openerp .secondary_menu.oe_folded { width: 20px; @@ -371,6 +389,10 @@ label.error { 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:hover, .openerp a.oe_secondary_submenu_item.leaf.active { @@ -383,7 +405,7 @@ label.error { 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 5px; + padding: 0 5px 2px 10px; line-height: 20px; color: #3f3d3d; text-decoration: none; @@ -431,6 +453,8 @@ label.error { margin: 0; padding: 4px 10px; text-shadow: 0 1px 0 #111111; + font-weight:normal; + line-height:14px; } .openerp .header_title small { color: #ccc; @@ -464,15 +488,11 @@ label.error { filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#929292', endColorstr='#4D4D4D',GradientType=0 ); } .openerp .header_corner ul.block { - /*float: left;*/ list-style: none; height: 34px; margin: 0; padding: 0 0 0 2px; - /*background: url(../images/top-sep-a.png) no-repeat;*/ line-height: 33px; - /*font-size: 1em;*/ - /*text-transform: uppercase;*/ } .openerp .header_corner ul.block li { float: left; @@ -498,6 +518,10 @@ label.error { font-weight: bold; } +.openerp .logout { + font-size:80%; +} + /* Footer */ .openerp div.oe_footer { background: none repeat scroll 0 0 #CCCCCC; @@ -530,7 +554,7 @@ label.error { } .openerp h2.oe_view_title { - font-size: 175%; + font-size: 110%; font-weight: normal; margin: 2px 0; color: #252424; @@ -541,12 +565,15 @@ label.error { .openerp .oe_vm_switch { float: right; } +.openerp .oe-view-manager-header .oe_view_title { + font-size:150%; +} /* SearchView */ .openerp .filter_label, .openerp .filter_icon { - border: 1px solid #666; border-left-width: 0; 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 ); @@ -558,13 +585,13 @@ label.error { filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#F0F0F0', endColorstr='#A1A7CE',GradientType=0 ); } .openerp .filter_label:active, .openerp .filter_icon:active { - background: #AAAAAA; + 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: #AAAAAA; + background: #aaa; } .openerp .filter_icon { height: 22px; @@ -588,13 +615,16 @@ label.error { white-space: nowrap; } .openerp .filter_label_group button:first-child { - border-left: 1px solid #666; -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 { + border-right: none; } .openerp .filter_label_group button:last-child { -webkit-border-top-right-radius: 7px; @@ -603,6 +633,20 @@ label.error { -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: 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; } .openerp .searchview_group_string { @@ -628,8 +672,16 @@ label.error { .openerp .searchview_group.expanded .searchview_group_content { display: block; } -.openerp .searchview_group_content { - padding-left: 10px; + +.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 { @@ -715,20 +767,23 @@ label.error { text-align: left; padding: 1px 2px; } -.openerp .oe-listview th.oe-record-selector, -.openerp .oe-listview td.oe-button, -.openerp .oe-listview td.oe-record-delete { - padding: 0 1px; + +.openerp .oe-record-delete button{ + border: none; + height: 12px; + width: 12px; + background: url("/web/static/src/img/iconset-b-remove.png") no-repeat scroll center center transparent; + cursor: pointer; } /* Could use :not selectors if they were supported by MSIE8... */ .openerp .oe-listview tbody td { - border-left: 1px solid #dadada; + 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+td, -.openerp .oe-listview tbody th.oe-record-selector+td, +.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; } @@ -738,15 +793,36 @@ label.error { } .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: 1em; + height: 60%; + margin: -6px 0 0; display: inline; display: inline-block; + vertical-align: middle; +} + +.openerp .oe-listview table tbody td { + border-bottom: 1px solid #E3E3E3; +} + +.openerp .oe-listview .oe-record-selector { + border-bottom: 1px solid #E3E3E3; } .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%; @@ -778,6 +854,8 @@ label.error { } .openerp .oe-list-pager .oe-pager-state { cursor: pointer; + font-size: 90%; + color: #555; } .openerp .oe-listview .oe-group-name { @@ -794,6 +872,8 @@ label.error { .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; @@ -846,28 +926,62 @@ label.error { } .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 0 1px 0; + border-width: 0; border-radius: 0; -moz-border-radius: 0; -webkit-border-radius: 0; - line-height: 0.5em; + 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: 0 1px 1px 1px; + border-width: 1px; } .openerp .oe_form_notebook .ui-tabs-selected { background: #f9f9f9; } +/* Unedit Form */ +.openerp .field_char, .openerp .field_date, .openerp .field_float, .openerp .oe_form_field_many2one a { + vertical-align: middle; + padding-top: 3px; + font-size: 90%; + color: #222; +} +.openerp .oe_form_field_many2one a { + color: #9A0404; + line-height: 12px; +} + + /* Form */ + +.openerp .oe_form_frame_cell input[type="checkbox"] { + margin-top: 3px; + vertical-align: center; +} +.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; } @@ -889,6 +1003,9 @@ label.error { padding: 2px; position: relative; } +.openerp td.oe_form_field_boolean { + padding-top: 4px; +} .openerp td.oe_form_frame_cell.oe_form_group { padding: 0; } @@ -900,14 +1017,31 @@ label.error { } .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_forms input[type="text"], .openerp .oe_forms input[type="password"], .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; } @@ -926,8 +1060,12 @@ label.error { } .openerp .oe_forms label.oe_label, .openerp .oe_forms label.oe_label_help { - margin: 3px 0 0 10px; + margin: 4px 0 0 3px; } +.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; @@ -949,13 +1087,29 @@ label.error { margin: 3px 0 0 0; } +/* Uneditable Form View */ +.openerp .oe_form_readonly { + +} +.openerp .oe_form_readonly .field_char, .openerp .oe_form_readonly .oe_form_field_email { + padding-top: 4px; + background-color: white; +} + +.openerp .oe_form_readonly .field_selection { + padding-top: 2px; + background-color: white; +} + + /* Inputs */ .openerp .oe_forms input[type="text"], .openerp .oe_forms input[type="password"], .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 0 2px; + padding: 0 2px; + margin: 0 2px; border: 1px solid #999; -moz-border-radius: 3px; -webkit-border-radius: 3px; @@ -964,6 +1118,10 @@ label.error { min-width: 90px; color: #1f1f1f; } +.openerp .oe_forms select{ + padding-top: 2px; +} + .openerp .oe_forms textarea { resize:vertical; } @@ -979,6 +1137,9 @@ label.error { min-width: 100%; width: 100%; } +.openerp .oe_forms .button { + height: 22px; +} @-moz-document url-prefix() { /* Strange firefox behaviour on width: 100% + white-space: nowrap */ .openerp .oe_forms .oe_button { @@ -1055,10 +1216,14 @@ label.error { border: 0 solid #666; } .openerp .separator.horizontal { - font-weight: bold; + font-weight: bold; border-bottom-width: 1px; margin: 3px 4px 3px 1px; - height: 15px; + 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; @@ -1095,6 +1260,14 @@ label.error { background: white; min-width: 90px; } +.openerp tbody.ui-widget-content { + margin-bottom: 10px; + border-spacing: 4px; +} +.openerp .ui-widget-header { + background-image: none; + background-color: white; +} /* Sidebar */ .openerp .view-manager-main-table { @@ -1108,16 +1281,13 @@ label.error { vertical-align: top; } -.openerp .view-manager-main-content { - width: 100%; -} .openerp .oe-view-manager-header { overflow: auto; } .openerp .oe-view-manager-header h2 { float: left; } -.openerp .oe-view-manager-header blockquote { +.openerp .oe_view_manager_menu_tips blockquote { display: none; font-size: 85%; margin: 0; @@ -1126,14 +1296,14 @@ label.error { padding: 1px 10px; color: #4C4C4C; } -.openerp .oe-view-manager-header blockquote p { +.openerp .oe_view_manager_menu_tips blockquote p { margin: 0; padding: 6px 1px 4px; } -.openerp .oe-view-manager-header blockquote div { +.openerp .oe_view_manager_menu_tips blockquote div { text-align: right; } -.openerp .oe-view-manager-header blockquote div button { +.openerp .oe_view_manager_menu_tips blockquote div button { border: none; background: none; padding: 0 4px; @@ -1310,14 +1480,6 @@ label.error { background: 1px 3px url(/web/static/src/img/icons/gtk-print.png) no-repeat; } -.openerp .oe-running-kitten { - display: none; -} - -.openerp.kitten-mode-activated .oe-running-kitten { - display: inherit; -} - .openerp.kitten-mode-activated .main_table { background: url(http://placekitten.com/g/1500/800) repeat; } @@ -1373,6 +1535,7 @@ label.error { } .openerp .oe_forms .oe-m2o input[type="text"] { padding-right: 20px; + padding-top: 2px; } .openerp .oe-m2o-drop-down-button { margin-left: -23px; @@ -1382,12 +1545,12 @@ label.error { margin-bottom: -4px; cursor: pointer; } -.openerp .oe-m2o-cm-button img { - margin-left: 4px; -} .openerp .oe-m2o-disabled-cm { color: grey; } +.openerp ul[role="listbox"] li a { + font-size:80%; +} .parent_top { vertical-align: text-top; } @@ -1433,20 +1596,19 @@ label.error { /* 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 bottom; + 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 bottom; + background: url(/web/static/src/img/remove-shortcut.png) no-repeat center center; } -/* ================ */ .oe-shortcuts { position: absolute; - margin: 0; padding: 6px 15px; top: 37px; @@ -1471,9 +1633,14 @@ label.error { color: #fff; text-align: center; border-left: 1px solid #909090; - padding: 4px; - font-size: 90%; + 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; @@ -1543,4 +1710,3 @@ ul.oe-arrow-list li.oe-arrow-list-selected .oe-arrow-list-after { .openerp .oe_view_editor_tree_grid a { display: block; } - diff --git a/addons/web/static/src/css/data_import.css b/addons/web/static/src/css/data_import.css index e5d1c9a910c..a63a52802f0 100644 --- a/addons/web/static/src/css/data_import.css +++ b/addons/web/static/src/css/data_import.css @@ -27,7 +27,7 @@ .openerp .oe-import fieldset.oe-closed table { display: none; } -.openerp .separator.horizontal { +.openerp .oe-import .separator.horizontal { font-weight: bold; border-bottom-width: 1px; margin: 6px 4px 6px 1px; diff --git a/addons/web/static/src/img/icons/lead-stage-won.png b/addons/web/static/src/img/icons/kanban-apply.png similarity index 100% rename from addons/web/static/src/img/icons/lead-stage-won.png rename to addons/web/static/src/img/icons/kanban-apply.png diff --git a/addons/web/static/src/img/icons/lead-stage-pending.png b/addons/web/static/src/img/icons/kanban-pause.png similarity index 100% rename from addons/web/static/src/img/icons/lead-stage-pending.png rename to addons/web/static/src/img/icons/kanban-pause.png diff --git a/addons/web/static/src/img/icons/lead-stage-lost.png b/addons/web/static/src/img/icons/kanban-stop.png similarity index 100% rename from addons/web/static/src/img/icons/lead-stage-lost.png rename to addons/web/static/src/img/icons/kanban-stop.png diff --git a/addons/web/static/src/img/iconset-b-remove.png b/addons/web/static/src/img/iconset-b-remove.png new file mode 100644 index 00000000000..497f03b4ceb Binary files /dev/null and b/addons/web/static/src/img/iconset-b-remove.png differ diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js index d271fbc430e..c9255d31949 100644 --- a/addons/web/static/src/js/core.js +++ b/addons/web/static/src/js/core.js @@ -1029,7 +1029,8 @@ openerp.web.TranslationDataBase = openerp.web.Class.extend(/** @lends openerp.we set_bundle: function(translation_bundle) { var self = this; this.db = {}; - var modules = _.keys(translation_bundle.modules).sort(); + var modules = _.keys(translation_bundle.modules); + modules.sort(); if (_.include(modules, "web")) { modules = ["web"].concat(_.without(modules, "web")); } @@ -1076,7 +1077,8 @@ openerp.web._t = new openerp.web.TranslationDataBase().build_translation_functio openerp.web.qweb = new QWeb2.Engine(); openerp.web.qweb.debug = (window.location.search.indexOf('?debug') !== -1); openerp.web.qweb.default_dict = { - '_' : _ + '_' : _, + '_t' : openerp.web._t } openerp.web.qweb.format_text_node = function(s) { // Note that 'this' is the Qweb Node of the text @@ -1094,6 +1096,7 @@ openerp.web.qweb.format_text_node = function(s) { /** Setup default connection */ openerp.connection = new openerp.web.Connection(); +openerp.web.qweb.default_dict['__debug__'] = openerp.connection.debug; }; diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index 1f2520ee774..d9bb8149ea8 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -265,14 +265,25 @@ openerp.web.DataSet = openerp.web.Widget.extend( /** @lends openerp.web.DataSet return this; }, select_id: function(id) { - var idx = _.indexOf(this.ids, id); - if (idx === -1) { + var idx = this.get_id_index(id); + if (idx === null) { return false; } else { this.index = idx; return true; } }, + get_id_index: function(id) { + for (var i=0, ii=this.ids.length; i 32))) { this.template = "WidgetParagraph"; this.colspan = parseInt(this.node.attrs.colspan || 1, 10); + // Widgets default to right-aligned, but paragraph defaults to + // left-aligned + if (isNaN(parseFloat(this.node.attrs.align))) { + this.align = 'left'; + } } else { this.colspan = 1; this.width = '1%'; @@ -1214,6 +1224,7 @@ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.f this.name = node.attrs.name; this.value = undefined; view.fields[this.name] = this; + view.fields_order.push(this.name); this.type = node.attrs.widget || view.fields_view.fields[node.attrs.name].type; this.element_name = "field_" + this.name + "_" + this.type; @@ -1605,7 +1616,7 @@ openerp.web.form.FieldSelection = openerp.web.form.Field.extend({ init: function(view, node) { var self = this; this._super(view, node); - this.values = this.field.selection; + this.values = _.clone(this.field.selection); _.each(this.values, function(v, i) { if (v[0] === false && v[1] === '') { self.values.splice(i, 1); @@ -2553,18 +2564,30 @@ openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends ope this.dataset.parent_view = this.options.parent_view; this.dataset.on_default_get.add(this.on_default_get); if (this.options.initial_view == "search") { - this.setup_search_view(); + self.rpc('/web/session/eval_domain_and_context', { + domains: [], + contexts: [this.context] + }, function (results) { + var search_defaults = {}; + _.each(results.context, function (value, key) { + var match = /^search_default_(.*)$/.exec(key); + if (match) { + search_defaults[match[1]] = value; + } + }); + self.setup_search_view(search_defaults); + }); } else { // "form" this.new_object(); } }, - setup_search_view: function() { + setup_search_view: function(search_defaults) { var self = this; if (this.searchview) { this.searchview.stop(); } this.searchview = new openerp.web.SearchView(this, - this.dataset, false, {}); + this.dataset, false, search_defaults); this.searchview.on_search.add(function(domains, contexts, groupbys) { if (self.initial_ids) { self.do_search(domains.concat([[["id", "in", self.initial_ids]], self.domain]), @@ -2813,6 +2836,7 @@ openerp.web.form.FieldReference = openerp.web.form.Field.extend({ this.view_id = 'reference_' + _.uniqueId(); this.widgets = {}; this.fields = {}; + this.fields_order = []; this.selection = new openerp.web.form.FieldSelection(this, { attrs: { name: 'selection', widget: 'selection' @@ -3060,6 +3084,9 @@ openerp.web.form.FieldStatus = openerp.web.form.Field.extend({ openerp.web.form.FieldReadonly = openerp.web.form.Field.extend({ +}); +openerp.web.form.WidgetFrameReadonly = openerp.web.form.WidgetFrame.extend({ + template: 'WidgetFrame.readonly' }); openerp.web.form.FieldCharReadonly = openerp.web.form.FieldReadonly.extend({ template: 'FieldChar.readonly', @@ -3109,7 +3136,7 @@ openerp.web.form.FieldSelectionReadonly = openerp.web.form.FieldReadonly.extend( // lifted straight from r/w version var self = this; this._super(view, node); - this.values = this.field.selection; + this.values = _.clone(this.field.selection); _.each(this.values, function(v, i) { if (v[0] === false && v[1] === '') { self.values.splice(i, 1); @@ -3213,6 +3240,7 @@ openerp.web.form.FieldOne2ManyReadonly = openerp.web.form.FieldOne2Many.extend({ force_readonly: true }); openerp.web.form.readonly = openerp.web.form.widgets.clone({ + 'frame': 'openerp.web.form.WidgetFrameReadonly', 'char': 'openerp.web.form.FieldCharReadonly', 'email': 'openerp.web.form.FieldEmailReadonly', 'url': 'openerp.web.form.FieldUrlReadonly', diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index 728b090d679..8f8215d0768 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -462,6 +462,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView# * @param {Object} results results of evaluating domain and process for a search */ do_search: function (domain, context, group_by) { + this.page = 0; this.groups.datagroup = new openerp.web.DataGroup( this, this.model, domain, context, group_by); this.groups.datagroup.sort = this.dataset._sort; @@ -661,8 +662,8 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView# * * @param {Number} count number of columns to add * @param {Object} options - * @param {"before"|"after"} [position="after"] insertion position for the new columns - * @param {Object} [except] content row to not pad + * @param {"before"|"after"} [options.position="after"] insertion position for the new columns + * @param {Object} [options.except] content row to not pad */ pad_columns: function (count, options) { options = options || {}; diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 5a26ef58b03..e8af1290e48 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -91,6 +91,14 @@ session.web.ActionManager = session.web.Widget.extend({ return this[type](action, on_close); }, ir_actions_act_window: function (action, on_close) { + if (_(['base.module.upgrade', 'base.setup.installer']) + .contains(action.res_model)) { + var old_close = on_close; + on_close = function () { + session.webclient.do_reload(); + if (old_close) { old_close(); } + }; + } if (action.target === 'new') { if (this.dialog == null) { this.dialog = new session.web.Dialog(this, { title: action.name, width: '80%' }); @@ -121,12 +129,6 @@ session.web.ActionManager = session.web.Widget.extend({ if (!this.dialog && on_closed) { on_closed(); } - if (this.dialog && action.context) { - var model = action.context.active_model; - if (model === 'base.module.upgrade' || model === 'base.setup.installer' || model === 'base.module.upgrade') { - session.webclient.do_reload(); - } - } this.dialog_stop(); }, ir_actions_server: function (action, on_closed) { @@ -278,7 +280,7 @@ session.web.ViewManager = session.web.Widget.extend(/** @lends session.web.View } } $.when(view_promise).then(function () { - self.$element.find('.oe_view_title:first').text( + self.$element.find('.oe_view_title_text:first').text( self.display_title()); }); return view_promise; @@ -424,8 +426,8 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner }); if (this.action.help && !this.flags.low_profile) { var Users = new session.web.DataSet(self, 'res.users'), - header = this.$element.find('.oe-view-manager-header'); - header.delegate('blockquote button', 'click', function() { + $tips = this.$element.find('.oe_view_manager_menu_tips'); + $tips.delegate('blockquote button', 'click', function() { var $this = $(this); //noinspection FallthroughInSwitchStatementJS switch ($this.attr('name')) { @@ -442,7 +444,7 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner if (!(user && user.id === self.session.uid)) { return; } - header.find('blockquote').toggle(user.menu_tips); + $tips.find('blockquote').toggle(user.menu_tips); }); } } @@ -470,10 +472,10 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner view_id = (fvg && fvg.view_id) || '--'; self.$element.find('.oe_get_xml_view span').text(view_id); if (!self.action.name && fvg) { - self.$element.find('.oe_view_title').text(fvg.arch.attrs.string || fvg.name); + self.$element.find('.oe_view_title_text').text(fvg.arch.attrs.string || fvg.name); } - var $title = self.$element.find('.oe_view_title'), + var $title = self.$element.find('.oe_view_title_text'), $search_prefix = $title.find('span.oe_searchable_view'); if (controller.searchable !== false) { if (!$search_prefix.length) { diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index fce34e6ce9a..b3486f15b98 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -360,10 +360,6 @@
  • -
  • - - -
  • LOGOUT @@ -418,11 +414,12 @@ + +

    - +

    @@ -443,21 +440,30 @@
    - -
    -

    -
    - - -
    -
    - + + + +
    +

    +
    + + +
    +
    + + +
    + + + + @@ -534,16 +540,17 @@ t-att-id="'treerow_' + record.id" t-att-data-id="record.id" t-att-data-level="level + 1"> - + + t-att-class="class"> + @@ -642,7 +649,7 @@ - + @@ -727,6 +734,11 @@ + + + this.attr('class', this.attr('class')+' oe_form_readonly'); + +
    @@ -1126,15 +1138,17 @@ - - - - - - - - - + + + + + + + + + +
    @@ -1143,6 +1157,16 @@

    (Any existing filter with the same name will be replaced)

    + +
    +

    Select Dashboard to add this filter to:

    + +

    Title of new Dashboard item:

    + +
    +
    @@ -1660,7 +1684,7 @@
    -

    The import failed due to:

    +

    The import failed due to:

    Here is a preview of the file we could not import:

    @@ -1710,4 +1734,4 @@
    - \ No newline at end of file + diff --git a/addons/web/static/test/formats.js b/addons/web/static/test/formats.js index d530571583c..cde11a188c0 100644 --- a/addons/web/static/test/formats.js +++ b/addons/web/static/test/formats.js @@ -63,6 +63,13 @@ $(document).ready(function () { // var res = openerp.web.parse_value(val.toString("HH:mm:ss"), {type:"time"}); // equal(val.toString("HH:mm:ss"), res.toString("HH:mm:ss")); // }); + test('parse_integer', function () { + var val = openerp.web.parse_value('123,456', {type: 'integer'}); + equal(val, 123456); + openerp.web._t.database.parameters.thousands_sep = '|'; + var val2 = openerp.web.parse_value('123|456', {type: 'integer'}); + equal(val2, 123456); + }); test("parse_float", function () { var str = "134,112.1234"; var val = openerp.web.parse_value(str, {type:"float"}); @@ -70,6 +77,12 @@ $(document).ready(function () { var str = "-134,112.1234"; var val = openerp.web.parse_value(str, {type:"float"}); equal(val, -134112.1234); + _.extend(openerp.web._t.database.parameters, { + decimal_point: ',', + thousands_sep: '.' + }); + var val3 = openerp.web.parse_value('123.456,789', {type: 'float'}); + equal(val3, 123456.789); }); test('intersperse', function () { var g = openerp.web.intersperse; @@ -100,6 +113,8 @@ $(document).ready(function () { equal(g("12345678", [2, 0, 1], '.'), '12.34.56.78'); equal(g("12345678", [2, 0, 0], '.'), '12.34.56.78'); equal(g("12345678", [2, 0, -1], '.'), '12.34.56.78'); + equal(g("12345678", [3,3,3,3], '.'), '12.345.678'); + equal(g("12345678", [3,0], '.'), '12.345.678'); }); test('format_integer', function () { openerp.web._t.database.parameters.grouping = [3, 3, 3, 3]; diff --git a/addons/web/static/test/test.html b/addons/web/static/test/test.html index 9bbfff168fd..b1018bc00ca 100644 --- a/addons/web/static/test/test.html +++ b/addons/web/static/test/test.html @@ -5,14 +5,14 @@ OpenERP - - + + - + diff --git a/addons/web_calendar/__openerp__.py b/addons/web_calendar/__openerp__.py index fcdbd3746c7..877e96d918f 100644 --- a/addons/web_calendar/__openerp__.py +++ b/addons/web_calendar/__openerp__.py @@ -1,6 +1,10 @@ { "name": "web calendar", - "category" : "Hidden", + "category": "Hidden", + "description": + """ + OpenERP Web calendar view. + """, "version": "2.0", "depends": ['web'], "js": [ diff --git a/addons/web_calendar/po/bn.po b/addons/web_calendar/po/bn.po new file mode 100644 index 00000000000..13d5b1333c2 --- /dev/null +++ b/addons/web_calendar/po/bn.po @@ -0,0 +1,22 @@ +# Bengali translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:38+0200\n" +"PO-Revision-Date: 2011-11-24 12:51+0000\n" +"Last-Translator: nasir khan saikat \n" +"Language-Team: Bengali \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2011-11-25 05:35+0000\n" +"X-Generator: Launchpad (build 14376)\n" + +#: addons/web_calendar/static/src/xml/web_calendar.xml:0 +msgid " " +msgstr " " diff --git a/addons/web_calendar/po/hr.po b/addons/web_calendar/po/hr.po new file mode 100644 index 00000000000..d5573b297c3 --- /dev/null +++ b/addons/web_calendar/po/hr.po @@ -0,0 +1,22 @@ +# Croatian translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:38+0200\n" +"PO-Revision-Date: 2011-11-28 12:04+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: 2011-11-29 05:49+0000\n" +"X-Generator: Launchpad (build 14399)\n" + +#: addons/web_calendar/static/src/xml/web_calendar.xml:0 +msgid " " +msgstr " " diff --git a/addons/web_calendar/po/nl.po b/addons/web_calendar/po/nl.po new file mode 100644 index 00000000000..b3ee13bf096 --- /dev/null +++ b/addons/web_calendar/po/nl.po @@ -0,0 +1,22 @@ +# Dutch translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:38+0200\n" +"PO-Revision-Date: 2011-12-01 13:57+0000\n" +"Last-Translator: Douwe Wullink (Dypalio) \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: 2011-12-02 05:28+0000\n" +"X-Generator: Launchpad (build 14414)\n" + +#: addons/web_calendar/static/src/xml/web_calendar.xml:0 +msgid " " +msgstr " " diff --git a/addons/web_calendar/po/ru.po b/addons/web_calendar/po/ru.po new file mode 100644 index 00000000000..e83a1e66d47 --- /dev/null +++ b/addons/web_calendar/po/ru.po @@ -0,0 +1,22 @@ +# Russian translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:38+0200\n" +"PO-Revision-Date: 2011-12-02 07:07+0000\n" +"Last-Translator: FULL NAME \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: 2011-12-03 05:46+0000\n" +"X-Generator: Launchpad (build 14418)\n" + +#: addons/web_calendar/static/src/xml/web_calendar.xml:0 +msgid " " +msgstr "" diff --git a/addons/web_calendar/static/src/js/calendar.js b/addons/web_calendar/static/src/js/calendar.js index 93e798ba804..75b168ccf5a 100644 --- a/addons/web_calendar/static/src/js/calendar.js +++ b/addons/web_calendar/static/src/js/calendar.js @@ -246,44 +246,75 @@ openerp.web_calendar.CalendarView = openerp.web.View.extend({ var self = this, data = this.get_event_data(event_obj); this.dataset.create(data, function(r) { - var id = parseInt(r.result, 10); + var id = r.result; self.dataset.ids.push(id); scheduler.changeEventId(event_id, id); self.refresh_minical(); }, function(r, event) { - self.creating_event_id = event_id; - self.form_dialog.form.on_record_loaded(data); - self.form_dialog.open(); event.preventDefault(); + self.do_create_event_with_formdialog(event_id, event_obj); + }); + }, + do_create_event_with_formdialog: function(event_id, event_obj) { + if (!event_obj) { + event_obj = scheduler.getEvent(event_id); + } + var self = this, + data = this.get_event_data(event_obj), + form = self.form_dialog.form, + fields_to_fetch = _(form.fields_view.fields).keys(); + this.dataset.index = null; + self.creating_event_id = event_id; + this.form_dialog.form.do_show().then(function() { + form.show_invalid = false; + _.each(['date_start', 'date_stop', 'date_delay'], function(field) { + var field_name = self[field]; + if (field_name) { + field = form.fields[field_name]; + field.set_value(data[field_name]); + field.dirty = true; + form.do_onchange(field); + } + }); + form.show_invalid = true; + self.form_dialog.open(); }); }, do_save_event: function(event_id, event_obj) { var self = this, - data = this.get_event_data(event_obj); - this.dataset.write(parseInt(event_id, 10), data, {}, function() { - self.refresh_minical(); - }); + data = this.get_event_data(event_obj), + index = this.dataset.get_id_index(event_id); + if (index != null) { + this.dataset.write(event_id, data, {}, function() { + self.refresh_minical(); + }); + } }, do_delete_event: function(event_id, event_obj) { - var self = this; // dhtmlx sends this event even when it does not exist in openerp. // Eg: use cancel in dhtmlx new event dialog - if (_.indexOf(this.dataset.ids, parseInt(event_id, 10)) > -1) { - this.dataset.unlink(parseInt(event_id, 10), function() { + var self = this, + index = this.dataset.get_id_index(event_id); + if (index !== null) { + this.dataset.unlink(event_id, function() { self.refresh_minical(); }); } }, do_edit_event: function(event_id) { var self = this; - event_id = parseInt(event_id, 10); - var index = _.indexOf(this.dataset.ids, event_id); - if (index > -1) { + var index = this.dataset.get_id_index(event_id); + if (index !== null) { this.dataset.index = index; this.form_dialog.form.do_show().then(function() { self.form_dialog.open(); }); return false; + } else if (scheduler.getState().mode === 'month') { + this.do_create_event_with_formdialog(event_id); + // TODO: check dhtmlxscheduler problem here. At this line, scheduler + // event 'onEventChanged' bound to this.do_save_event() won't be fired !; + return false; } return true; }, diff --git a/addons/web_chat/__openerp__.py b/addons/web_chat/__openerp__.py index f0525bcadad..109fe54f345 100644 --- a/addons/web_chat/__openerp__.py +++ b/addons/web_chat/__openerp__.py @@ -1,6 +1,10 @@ { "name": "Web Chat", - "category" : "Hidden", + "category": "Hidden", + "description": + """ + OpenERP Web chat module. + """, "version": "2.0", "depends": ['web'], "js": [ diff --git a/addons/web_dashboard/__openerp__.py b/addons/web_dashboard/__openerp__.py index 68c73731c71..5f8be2b4e51 100644 --- a/addons/web_dashboard/__openerp__.py +++ b/addons/web_dashboard/__openerp__.py @@ -1,6 +1,10 @@ { "name": "web Dashboard", - "category" : "Hidden", + "category": "Hidden", + "description": + """ + OpenERP Web dashboard view. + """, "version": "2.0", "depends": ['web'], "js": [ diff --git a/addons/web_dashboard/po/bn.po b/addons/web_dashboard/po/bn.po new file mode 100644 index 00000000000..bb05c54ae23 --- /dev/null +++ b/addons/web_dashboard/po/bn.po @@ -0,0 +1,46 @@ +# Bengali translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:39+0200\n" +"PO-Revision-Date: 2011-11-24 12:53+0000\n" +"Last-Translator: nasir khan saikat \n" +"Language-Team: Bengali \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2011-11-25 05:35+0000\n" +"X-Generator: Launchpad (build 14376)\n" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Reset" +msgstr "" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Undo" +msgstr "" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Add Widget" +msgstr "" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Change layout" +msgstr "" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Choose dashboard layout" +msgstr "" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "progress:" +msgstr "" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "%" +msgstr "%" diff --git a/addons/web_dashboard/po/hr.po b/addons/web_dashboard/po/hr.po new file mode 100644 index 00000000000..033c88801f3 --- /dev/null +++ b/addons/web_dashboard/po/hr.po @@ -0,0 +1,46 @@ +# Croatian translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:39+0200\n" +"PO-Revision-Date: 2011-11-28 12:07+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: 2011-11-29 05:49+0000\n" +"X-Generator: Launchpad (build 14399)\n" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Reset" +msgstr "Vrati izvorno" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Undo" +msgstr "Vrati" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Add Widget" +msgstr "Dodaj widget" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Change layout" +msgstr "Promijeni raspored" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Choose dashboard layout" +msgstr "Odaberi raspored" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "progress:" +msgstr "napredak:" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "%" +msgstr "%" diff --git a/addons/web_dashboard/po/nl.po b/addons/web_dashboard/po/nl.po new file mode 100644 index 00000000000..909cb924de4 --- /dev/null +++ b/addons/web_dashboard/po/nl.po @@ -0,0 +1,46 @@ +# Dutch translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:39+0200\n" +"PO-Revision-Date: 2011-12-01 13:58+0000\n" +"Last-Translator: Douwe Wullink (Dypalio) \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: 2011-12-02 05:28+0000\n" +"X-Generator: Launchpad (build 14414)\n" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Reset" +msgstr "Reset" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Undo" +msgstr "Ongedaan maken" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Add Widget" +msgstr "Widget toevoegen" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Change layout" +msgstr "Layout wijzigen" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Choose dashboard layout" +msgstr "Kies dashboard layout" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "progress:" +msgstr "voortgang:" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "%" +msgstr "%" diff --git a/addons/web_dashboard/po/ru.po b/addons/web_dashboard/po/ru.po new file mode 100644 index 00000000000..018ada93a30 --- /dev/null +++ b/addons/web_dashboard/po/ru.po @@ -0,0 +1,46 @@ +# Russian translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:39+0200\n" +"PO-Revision-Date: 2011-12-02 07:09+0000\n" +"Last-Translator: FULL NAME \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: 2011-12-03 05:46+0000\n" +"X-Generator: Launchpad (build 14418)\n" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Reset" +msgstr "" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Undo" +msgstr "" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Add Widget" +msgstr "" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Change layout" +msgstr "" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "Choose dashboard layout" +msgstr "" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "progress:" +msgstr "" + +#: addons/web_dashboard/static/src/xml/web_dashboard.xml:0 +msgid "%" +msgstr "" diff --git a/addons/web_dashboard/static/src/css/dashboard.css b/addons/web_dashboard/static/src/css/dashboard.css index 54b1cc7d2b5..572340a3e13 100644 --- a/addons/web_dashboard/static/src/css/dashboard.css +++ b/addons/web_dashboard/static/src/css/dashboard.css @@ -169,6 +169,11 @@ text-transform: uppercase; margin: 0 0 0.5em 0; } +.openerp .oe-dashboard-config-overview .oe-config-tip { + color: #222; + text-shadow: #eee 0 1px 0; + text-align: center; +} .openerp .oe-dashboard-config-overview dt { font-weight: bold; text-transform: uppercase; diff --git a/addons/web_dashboard/static/src/img/installer_account_accountant.png b/addons/web_dashboard/static/src/img/installer_account_accountant.png new file mode 100644 index 00000000000..5cae206d4e5 Binary files /dev/null and b/addons/web_dashboard/static/src/img/installer_account_accountant.png differ diff --git a/addons/web_dashboard/static/src/js/dashboard.js b/addons/web_dashboard/static/src/js/dashboard.js index deba1529aa3..5d9c82af027 100644 --- a/addons/web_dashboard/static/src/js/dashboard.js +++ b/addons/web_dashboard/static/src/js/dashboard.js @@ -26,7 +26,6 @@ openerp.web.form.DashBoard = openerp.web.form.Widget.extend({ // Events this.$element.find('.oe-dashboard-link-undo').click(this.on_undo); this.$element.find('.oe-dashboard-link-reset').click(this.on_reset); - this.$element.find('.oe-dashboard-link-add_widget').click(this.on_add_widget); this.$element.find('.oe-dashboard-link-change_layout').click(this.on_change_layout); this.$element.delegate('.oe-dashboard-column .oe-dashboard-fold', 'click', this.on_fold_action); @@ -34,19 +33,19 @@ openerp.web.form.DashBoard = openerp.web.form.Widget.extend({ this.actions_attrs = {}; // Init actions - _.each(this.node.children, function(column) { - _.each(column.children, function(action) { + _.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) - }, self.on_load_action); + }, function(result) { + self.on_load_action(result, column_index + '_' + action_index); + }); }); }); - - //this.$element.find('a.oe-dashboard-action-rename').live('click', this.on_rename); }, on_undo: function() { this.rpc('/web/view/undo_custom', { @@ -59,85 +58,6 @@ openerp.web.form.DashBoard = openerp.web.form.Widget.extend({ reset: true }, this.do_reload); }, - on_add_widget: function() { - var self = this; - var action_manager = new openerp.web.ActionManager(this); - var dialog = new openerp.web.Dialog(this, { - title : 'Actions', - width: 800, - height: 600, - buttons : { - Cancel : function() { - $(this).dialog('destroy'); - }, - Add : function() { - self.do_add_widget(action_manager.inner_viewmanager.views.list.controller); - $(this).dialog('destroy'); - } - } - }).start().open(); - action_manager.appendTo(dialog.$element); - action_manager.do_action({ - res_model : 'ir.actions.actions', - views : [[false, 'list']], - type : 'ir.actions.act_window', - limit : 80, - auto_search : true, - flags : { - sidebar : false, - views_switcher : false, - action_buttons : false - } - }); - // TODO: should bind ListView#select_record in order to catch record clicking - }, - do_add_widget : function(listview) { - var self = this, - actions = listview.groups.get_selection().ids, - results = [], - qdict = { view : this.view }; - // TODO: should load multiple actions at once - _.each(actions, function(aid) { - self.rpc('/web/action/load', { - action_id: aid - }, function(result) { - self.actions_attrs[aid] = { - name: aid, - string: _.str.trim(result.result.name) - }; - qdict.action = { - attrs : self.actions_attrs[aid] - }; - self.$element.find('.oe-dashboard-column:first').prepend(QWeb.render('DashBoard.action', qdict)); - self.do_save_dashboard(); - self.on_load_action(result) - }); - }); - }, - on_rename : function(e) { - var self = this, - id = parseInt($(e.currentTarget).parents('.oe-dashboard-action:first').attr('data-id'), 10), - $header = $(e.currentTarget).parents('.oe-dashboard-action-header:first'), - $rename = $header.find('a.oe-dashboard-action-rename').hide(), - $title = $header.find('span.oe-dashboard-action-title').hide(), - $input = $header.find('input[name=title]'); - $input.val($title.text()).show().focus().bind('keydown', function(e) { - if (e.which == 13 || e.which == 27) { - if (e.which == 13) { //enter - var val = $input.val(); - if (!val) { - return false; - } - $title.text(val); - self.actions_attrs[id].string = val; - self.do_save_dashboard(); - } - $input.unbind('keydown').hide(); - $rename.show(); - $title.show(); - } - }); - }, on_change_layout: function() { var self = this; var qdict = { @@ -191,8 +111,10 @@ openerp.web.form.DashBoard = openerp.web.form.Widget.extend({ this.do_save_dashboard(); }, on_close_action: function(e) { - $(e.currentTarget).parents('.oe-dashboard-action:first').remove(); - this.do_save_dashboard(); + if (confirm("Are you sure you want to remove this item ?")) { + $(e.currentTarget).parents('.oe-dashboard-action:first').remove(); + this.do_save_dashboard(); + } }, do_save_dashboard: function() { var self = this; @@ -204,8 +126,17 @@ openerp.web.form.DashBoard = openerp.web.form.Widget.extend({ this.$element.find('.oe-dashboard-column').each(function() { var actions = []; $(this).find('.oe-dashboard-action').each(function() { - var action_id = $(this).attr('data-id'); - actions.push(self.actions_attrs[action_id]); + var action_id = $(this).attr('data-id'), + new_attrs = _.clone(self.actions_attrs[action_id]); + if (new_attrs.domain) { + new_attrs.domain = new_attrs.domain_string; + delete(new_attrs.domain_string); + } + if (new_attrs.context) { + new_attrs.context = new_attrs.context_string; + delete(new_attrs.context_string); + } + actions.push(new_attrs); }); board.columns.push(actions); }); @@ -217,7 +148,7 @@ openerp.web.form.DashBoard = openerp.web.form.Widget.extend({ self.$element.find('.oe-dashboard-link-undo, .oe-dashboard-link-reset').show(); }); }, - on_load_action: function(result) { + on_load_action: function(result, index) { var self = this, action = result.result, action_attrs = this.actions_attrs[action.id], @@ -261,7 +192,7 @@ openerp.web.form.DashBoard = openerp.web.form.Widget.extend({ }; var am = new openerp.web.ActionManager(this); this.action_managers.push(am); - am.appendTo($("#"+this.view.element_id + '_action_' + action.id)); + am.appendTo($('#' + this.view.element_id + '_action_' + index)); am.do_action(action); am.do_action = function(action) { self.do_action(action); diff --git a/addons/web_dashboard/static/src/xml/web_dashboard.xml b/addons/web_dashboard/static/src/xml/web_dashboard.xml index 72f418ebbad..085c331b4fc 100644 --- a/addons/web_dashboard/static/src/xml/web_dashboard.xml +++ b/addons/web_dashboard/static/src/xml/web_dashboard.xml @@ -9,10 +9,6 @@ Undo -
    - + -
    -
    -
    - +
    +
    +
    +
    + +
    +
      +
    • + : +
    • +
    -
      -
    • - : -
    • -
    +

    -

    @@ -46,7 +48,9 @@ - + + + </tr><tr> diff --git a/addons/web_mobile/__openerp__.py b/addons/web_mobile/__openerp__.py index ce219df3138..03526288cf6 100644 --- a/addons/web_mobile/__openerp__.py +++ b/addons/web_mobile/__openerp__.py @@ -1,6 +1,10 @@ { "name" : "OpenERP Web mobile", - "category" : "Hidden", + "category": "Hidden", + "description": + """ + OpenERP Web mobile. + """, "version" : "2.0", "depends" : [], 'active': True, diff --git a/addons/web_mobile/po/bn.po b/addons/web_mobile/po/bn.po new file mode 100644 index 00000000000..8b58155b7cd --- /dev/null +++ b/addons/web_mobile/po/bn.po @@ -0,0 +1,66 @@ +# Bengali translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:39+0200\n" +"PO-Revision-Date: 2011-11-24 12:56+0000\n" +"Last-Translator: nasir khan saikat \n" +"Language-Team: Bengali \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2011-11-25 05:35+0000\n" +"X-Generator: Launchpad (build 14376)\n" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "OpenERP" +msgstr "" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Database:" +msgstr "ডেটাবেস:" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Login:" +msgstr "লগইন:" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Password:" +msgstr "পাসওয়ার্ড:" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Login" +msgstr "লগইন" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Bad username or password" +msgstr "" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Favourite" +msgstr "" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Preference" +msgstr "পছন্দসমূহ" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Applications" +msgstr "অ্যাপ্লিকেশন" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Options" +msgstr "" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Logout" +msgstr "লগআউট" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid ":" +msgstr ":" diff --git a/addons/web_mobile/po/nl.po b/addons/web_mobile/po/nl.po new file mode 100644 index 00000000000..5b9799ab09c --- /dev/null +++ b/addons/web_mobile/po/nl.po @@ -0,0 +1,66 @@ +# Dutch translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:39+0200\n" +"PO-Revision-Date: 2011-12-01 14:02+0000\n" +"Last-Translator: Douwe Wullink (Dypalio) \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: 2011-12-02 05:28+0000\n" +"X-Generator: Launchpad (build 14414)\n" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "OpenERP" +msgstr "OpenERP" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Database:" +msgstr "Database:" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Login:" +msgstr "Inlognaam:" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Password:" +msgstr "Wachtwoord:" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Login" +msgstr "Aanmelden" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Bad username or password" +msgstr "Verkeerde gebruikersnaam of wachtwoord" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Favourite" +msgstr "Favoriet" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Preference" +msgstr "Voorkeur" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Applications" +msgstr "Toepassingen" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Options" +msgstr "Opties" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Logout" +msgstr "Afmelden" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid ":" +msgstr ":" diff --git a/addons/web_mobile/po/ru.po b/addons/web_mobile/po/ru.po new file mode 100644 index 00000000000..a7235fe09e2 --- /dev/null +++ b/addons/web_mobile/po/ru.po @@ -0,0 +1,66 @@ +# Russian translation for openerp-web +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openerp-web package. +# FIRST AUTHOR , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openerp-web\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2011-10-07 10:39+0200\n" +"PO-Revision-Date: 2011-12-02 07:20+0000\n" +"Last-Translator: FULL NAME \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: 2011-12-03 05:46+0000\n" +"X-Generator: Launchpad (build 14418)\n" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "OpenERP" +msgstr "" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Database:" +msgstr "" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Login:" +msgstr "" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Password:" +msgstr "" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Login" +msgstr "" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Bad username or password" +msgstr "" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Favourite" +msgstr "" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Preference" +msgstr "" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Applications" +msgstr "" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Options" +msgstr "" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Logout" +msgstr "" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid ":" +msgstr "" diff --git a/addons/web_mobile/static/src/web_mobile.html b/addons/web_mobile/static/src/web_mobile.html index 2afa79dcb5e..3d91fb405c2 100755 --- a/addons/web_mobile/static/src/web_mobile.html +++ b/addons/web_mobile/static/src/web_mobile.html @@ -3,24 +3,24 @@ OpenERP Web Mobile - - + + - + - - - - - - - - + + + + + + + + @@ -28,7 +28,7 @@ - + diff --git a/addons/web_process/__openerp__.py b/addons/web_process/__openerp__.py index 1ef47573d55..903cc060a60 100644 --- a/addons/web_process/__openerp__.py +++ b/addons/web_process/__openerp__.py @@ -1,6 +1,10 @@ { "name" : "Process", - "version" : "2.0", + "version": "2.0", + "description": + """ + OpenERP Web process view. + """, "depends" : ["web"], "js": [ "static/src/js/process.js" @@ -9,7 +13,7 @@ "static/src/css/process.css" ], 'qweb': [ - "static/src/xml/web_process.css" + "static/src/xml/*.xml" ], 'active': True } diff --git a/addons/web_process/static/src/css/process.css b/addons/web_process/static/src/css/process.css index 364c3788b11..cebc6b1e91f 100644 --- a/addons/web_process/static/src/css/process.css +++ b/addons/web_process/static/src/css/process.css @@ -50,6 +50,17 @@ a.cta-a strong { display: table-cell; } +.oe-process-view { + height: 20px; + margin-top:4px; + padding: 0; + width: 24px; + cursor: pointer; + display: block; + background: url(/web/static/src/img/icons/gtk-help.png) no-repeat center center; + float: left; +} + .process-help-text { float: left; padding:5px 10px; @@ -59,4 +70,4 @@ a.cta-a strong { td.process_fields,button.toggle_fields span:last-child { display: none; -} \ No newline at end of file +} diff --git a/addons/web_process/static/src/js/process.js b/addons/web_process/static/src/js/process.js index 52f6ab1a674..d33ed6bcd35 100644 --- a/addons/web_process/static/src/js/process.js +++ b/addons/web_process/static/src/js/process.js @@ -44,6 +44,7 @@ openerp.web_process = function (openerp) { if(self.process_id) { self.graph_get().done(function(res) { self.process_notes = res.notes; + self.process_title = res.name; self.process_subflows = _.filter(res.nodes, function(x) { return x.subflow != false; }); @@ -245,9 +246,10 @@ openerp.web_process = function (openerp) { transitions['active'] = src.active && !dst.gray; process_graph.addEdge(src['name'], dst['name'], {directed : true}); }); - + var width = $(document).width(); + var height = $(document).height(); var layouter = new Graph.Layout.Ordered(process_graph); - var render_process_graph = new Graph.Renderer.Raphael('process_canvas', process_graph, $('#process_canvas').width(), $('#process_canvas').height()); + var render_process_graph = new Graph.Renderer.Raphael('process_canvas', process_graph, width, height); }, jump_to_view: function(model, id) { var self = this; diff --git a/addons/web_process/static/src/xml/web_process.xml b/addons/web_process/static/src/xml/web_process.xml index 63e207a4f96..727bdad9d25 100644 --- a/addons/web_process/static/src/xml/web_process.xml +++ b/addons/web_process/static/src/xml/web_process.xml @@ -1,7 +1,7 @@