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/controllers/main.py b/addons/web/controllers/main.py index 6af0268b3bf..7dbd696cfb4 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -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/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/pt.po b/addons/web/po/pt.po new file mode 100644 index 00000000000..ca98e18bce9 --- /dev/null +++ b/addons/web/po/pt.po @@ -0,0 +1,688 @@ +# Portuguese 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-21 22:22+0000\n" +"Last-Translator: Daniel Reis \n" +"Language-Team: Portuguese \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-22 05:13+0000\n" +"X-Generator: Launchpad (build 14299)\n" + +#: addons/web/static/src/js/view_form.js:355 +msgid "" +"Warning, the record has been modified, your changes will be discarded." +msgstr "" +"Atenção, o o registo foi modificado, as suas alterações serão descartadas." + +#: 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 "Escolha pelo menos um registo." + +#: addons/web/static/src/js/views.js:569 +msgid "Warning" +msgstr "Aviso" + +#: addons/web/static/src/js/views.js:609 +msgid "Translations" +msgstr "Traduções" + +#: addons/web/static/src/js/views.js:614 addons/web/static/src/xml/base.xml:0 +msgid "Save" +msgstr "Guardar" + +#: addons/web/static/src/js/views.js:615 +msgid "Close" +msgstr "Fechar" + +#: 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 "A carregar ..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create" +msgstr "Criar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Drop" +msgstr "Excluir" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Backup" +msgstr "Cópia de segurança" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Restore" +msgstr "Restaurar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Password" +msgstr "Senha" + +#: 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 "Nome da nova base de dados" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Load Demonstration data:" +msgstr "Carregar dados de demonstração" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Default language:" +msgstr "Idioma predefinido:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Admin password:" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm password:" +msgstr "Confirmar senha:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "DROP DATABASE" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Database:" +msgstr "Base de dados:" + +#: 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 "Ficheiro:" + +#: 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 "Utilizador:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Password:" +msgstr "Senha:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Database" +msgstr "Base de dados" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Login" +msgstr "Iniciar sessão" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Bad username or password" +msgstr "Nome de utilizador ou senha incorrectos" + +#: 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 "" +"Pensamos que as atividades do trabalho diário pode ser mais intuitivas, " +"eficientes, automatizadas, ... e até mesmo divertidas." + +#: addons/web/static/src/xml/base.xml:0 +msgid "OpenERP's vision to be:" +msgstr "A visão do OpenERP é:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Full featured" +msgstr "Pleno de funcionalidade" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"Today's enterprise challenges are multiple. We provide one module for each " +"need." +msgstr "" +"Os desafios atuais das empresas são múltiplos. Nós fornecemos um módulo para " +"cada necessidade." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Open Source" +msgstr "Código aberto" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"To Build a great product, we rely on the knowledge of thousands of " +"contributors." +msgstr "" +"Para construir um grande produto, nós contamos com o conhecimento de " +"milhares de contribuidores." + +#: addons/web/static/src/xml/base.xml:0 +msgid "User Friendly" +msgstr "Amigável para o utilizador" + +#: addons/web/static/src/xml/base.xml:0 +msgid "" +"In order to be productive, people need clean and easy to use interface." +msgstr "" +"Para serem produtivas, as pessoas precisam de uma interface simples e fácil " +"de usar." + +#: 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 "SAIR" + +#: 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 "Ocultar esta dica" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Disable all tips" +msgstr "Desativar todas as dicas" + +#: addons/web/static/src/xml/base.xml:0 +msgid "View#" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Fields" +msgstr "Campos" + +#: addons/web/static/src/xml/base.xml:0 +msgid "View labels" +msgstr "Ver etiquetas" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Sidebar Relates" +msgstr "" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Field" +msgstr "Campo" + +#: addons/web/static/src/xml/base.xml:0 +msgid ":" +msgstr ":" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Translate view" +msgstr "Traduzir vista" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Translate sidebar" +msgstr "Traduzir barra lateral" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delete" +msgstr "Apagar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "First" +msgstr "Primeiro" + +#: 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 "Último" + +#: addons/web/static/src/xml/base.xml:0 +msgid "♻" +msgstr "♻" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & Edit" +msgstr "Gravar & Editar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create & Edit" +msgstr "Criar & Editar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New" +msgstr "Novo" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Duplicate" +msgstr "Duplicar" + +#: 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 "Acrescentar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Unhandled widget" +msgstr "Widget não tratado" + +#: 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 "Concluído" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Open..." +msgstr "Abrir..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Create..." +msgstr "Criar..." + +#: addons/web/static/src/xml/base.xml:0 +msgid "Search..." +msgstr "Procurar..." + +#: 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 "Selecionar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save As" +msgstr "Guardar como" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Clear" +msgstr "Limpar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Advanced Filter" +msgstr "Filtro avançados" + +#: addons/web/static/src/xml/base.xml:0 +msgid "-- Filters --" +msgstr "-- Filtros --" + +#: addons/web/static/src/xml/base.xml:0 +msgid "-- Actions --" +msgstr "-- Ações --" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save Filter" +msgstr "Guardar filtro" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Manage Filters" +msgstr "Gerir filtros" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Filter Name:" +msgstr "Nome do filtro:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "(Any existing filter with the same name will be replaced)" +msgstr "(filtros existentes com esse nome serão substituídos)" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Any of the following conditions must match" +msgstr "Deve satisfazer alguma das seguintes condições" + +#: addons/web/static/src/xml/base.xml:0 +msgid "All the following conditions must match" +msgstr "Deve satisfazer toas as seguintes condições" + +#: addons/web/static/src/xml/base.xml:0 +msgid "None of the following conditions must match" +msgstr "Não deve satisfazernenhuma das seguintes condições" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Add condition" +msgstr "Acrescentar condição" + +#: addons/web/static/src/xml/base.xml:0 +msgid "and" +msgstr "e" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Cancel" +msgstr "Cancelar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & New" +msgstr "Guardar & Novo" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save & Close" +msgstr "Guardar & Fechar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export" +msgstr "Exportar" + +#: 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 "Tipo de exportação:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Compatible Export" +msgstr "Exportação compatível com importação" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export all Data" +msgstr "Exportar todos os dados" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Export Formats" +msgstr "Formatos de exportação" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Available fields" +msgstr "Campos disponíveis" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Fields to export" +msgstr "Campos a exportar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save fields list" +msgstr "Gravar lista de campos" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Remove" +msgstr "Remover" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Remove All" +msgstr "Remover tudo" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Name" +msgstr "Nome" + +#: addons/web/static/src/xml/base.xml:0 +msgid " " +msgstr " " + +#: addons/web/static/src/xml/base.xml:0 +msgid "Save as:" +msgstr "Guardar como:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Ok" +msgstr "Ok" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Saved exports:" +msgstr "Exportações guardadas:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Old Password:" +msgstr "Senha antiga:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "New Password:" +msgstr "Nova senha:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Confirm Password:" +msgstr "Confirme a senha:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import" +msgstr "Importar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "1. Import a .CSV file" +msgstr "1. Importar um ficheiro .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 "Ficheiro CSV:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "2. Check your file format" +msgstr "2. Verifique o formato do ficheiro" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Import Options" +msgstr "Opções de importação" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Does your file have titles?" +msgstr "O ficheiro tem títulos?" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Separator:" +msgstr "Separador:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Delimiter:" +msgstr "Delimitador:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Encoding:" +msgstr "Codificação:" + +#: 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 "Linhas a ignorar" + +#: addons/web/static/src/xml/base.xml:0 +msgid "The import failed due to:" +msgstr "Importação falhou devido a:" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Here is a preview of the file we could not import:" +msgstr "Previsão do ficheiro que não conseguiu ser importado:" + +#: 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 "Versão" + +#: addons/web/static/src/xml/base.xml:0 +msgid "Copyright © 2011-TODAY OpenERP SA. All Rights Reserved." +msgstr "Copyright © 2011-HOJE OpenERP SA. Todos os direitos reservados." + +#: 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 "Acerca do 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 "" +"Dependendo de suas necessidades, o OpenERP está disponível através da web ou " +"de uma aplicação cliente." 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/src/css/base.css b/addons/web/static/src/css/base.css index d8f31af1d35..cad536c0f1f 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -1310,6 +1310,14 @@ 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; } 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/js/chrome.js b/addons/web/static/src/js/chrome.js index 2b838ee3743..f10ee9376f6 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -1114,7 +1114,7 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie this.action_manager.do_action(action); }, do_about: function() { - }, + } }); diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js index a9731ef5b16..8eeca33934f 100644 --- a/addons/web/static/src/js/core.js +++ b/addons/web/static/src/js/core.js @@ -509,16 +509,24 @@ openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp. var self = this; this.session_id = this.get_cookie('session_id'); return this.rpc("/web/session/get_session_info", {}).then(function(result) { + // If immediately follows a login (triggered by trying to restore + // an invalid session or no session at all), refresh session data + // (should not change, but just in case...) but should not call + // on_session_valid again as it triggers reloading the menu + var already_logged = self.uid; _.extend(self, { uid: result.uid, user_context: result.context, db: result.db, username: result.login }); - if (self.uid) - self.on_session_valid(); - else - self.on_session_invalid(); + if (!already_logged) { + if (self.uid) { + self.on_session_valid(); + } else { + self.on_session_invalid(); + } + } }, function() { self.on_session_invalid(); }); @@ -809,7 +817,7 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W */ tag_name: 'div', /** - * Construct the widget and set its parent if a parent is given. + * Constructs the widget and sets its parent if a parent is given. * * @constructs openerp.web.Widget * @extends openerp.web.CallbackEnabled @@ -841,7 +849,7 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W this.widget_is_stopped = false; }, /** - * Render the current widget and appends it to the given jQuery object or Widget. + * Renders the current widget and appends it to the given jQuery object or Widget. * * @param target A jQuery object or a Widget instance. */ @@ -852,7 +860,7 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W }, target); }, /** - * Render the current widget and prepends it to the given jQuery object or Widget. + * Renders the current widget and prepends it to the given jQuery object or Widget. * * @param target A jQuery object or a Widget instance. */ @@ -863,7 +871,7 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W }, target); }, /** - * Render the current widget and inserts it after to the given jQuery object or Widget. + * Renders the current widget and inserts it after to the given jQuery object or Widget. * * @param target A jQuery object or a Widget instance. */ @@ -874,7 +882,7 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W }, target); }, /** - * Render the current widget and inserts it before to the given jQuery object or Widget. + * Renders the current widget and inserts it before to the given jQuery object or Widget. * * @param target A jQuery object or a Widget instance. */ @@ -884,6 +892,16 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W self.$element.insertBefore(t); }, target); }, + /** + * Renders the current widget and replaces the given jQuery object. + * + * @param target A jQuery object or a Widget instance. + */ + replace: function(target) { + return this._render_and_insert(_.bind(function(t) { + this.$element.replaceAll(t); + }, this), target); + }, _render_and_insert: function(insertion, target) { this.render_element(); if (target instanceof openerp.web.Widget) @@ -929,7 +947,7 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W return $.Deferred().done().promise(); }, /** - * Destroys the current widget, also destroy all its children before destroying itself. + * Destroys the current widget, also destroys all its children before destroying itself. */ stop: function() { _.each(_.clone(this.widget_children), function(el) { @@ -945,7 +963,7 @@ openerp.web.Widget = openerp.web.CallbackEnabled.extend(/** @lends openerp.web.W this.widget_is_stopped = true; }, /** - * Inform the action manager to do an action. Of course, this suppose that + * Informs the action manager to do an action. This supposes that * the action manager can be found amongst the ancestors of the current widget. * If that's not the case this method will simply return `false`. */ @@ -1058,7 +1076,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 @@ -1076,6 +1095,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 69d8fd9ddfd..1f2520ee774 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -730,6 +730,19 @@ openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({ return_records(); } return completion.promise(); + }, + call_button: function (method, args, callback, error_callback) { + var id = args[0][0], index; + for(var i=0, len=this.cache.length; i'); + this.create_view_widget = []; + _.each(view_widget, function(widget) { + var type_widget = new (self.property.get_any([widget.type])) (self.create_view_dialog, widget); + self.create_view_dialog.$element.find('table[id=create_view]').append('' + widget.string + ':' + type_widget.render()+''); + var value = null; + if (widget.value) { + value = widget.value; + type_widget.dirty = true; + } + type_widget.start(); + type_widget.set_value(value) + self.create_view_widget.push(type_widget); + }); + }, + do_save_view: function(values) { + def = $.Deferred(); + var field_dataset = new openerp.web.DataSetSearch(this, this.model, null, null); + var model_dataset = new openerp.web.DataSetSearch(this, 'ir.model', null, null); + var view_string = "", field_name = false, self = this; + field_dataset.call( 'fields_get', [], function(fields) { + _.each(['name', 'x_name'], function(value) { + if (_.include(_.keys(fields), value)) { + field_name = value; + return false; + } }); - } else { - val.child_id = child_obj_list; + if (field_name) { + model_dataset.read_slice(['name','field_id'], {"domain": [['model','=',self.model]]}, function(records) { + if (records) {view_string = records[0].name;} + var arch = _.str.sprintf("\n<%s string='%s'>\n\t\n", values.view_type, view_string, field_name, values.view_type); + var vals = {'model': self.model, 'name': values.view_name, 'priority': values.priority, 'type': values.view_type, 'arch': arch}; + self.dataset.create(vals, function(suc) { + def.resolve(); + }); + }); + } + }); + return def.promise(); + }, + on_valid_create_view: function(widgets) { + var msg = "
    "; + _.each(widgets, function(widget) { + if (widget.is_invalid) { + msg += "
  • " + widget.name + "
  • "; + } + }); + msg += "
"; + this.do_warn("The following fields are invalid :", msg); + }, + add_node_name : function(node) { + if(node.tagName.toLowerCase() == "button" || node.tagName.toLowerCase() == "field"){ + return (node.getAttribute('name'))? + _.str.sprintf( "<%s name='%s'>",node.tagName.toLowerCase(), node.getAttribute('name')): + _.str.sprintf( "<%s>",node.tagName.toLowerCase()); + }else if(node.tagName.toLowerCase() == "group"){ + return (node.getAttribute('string'))? + _.str.sprintf( "<%s>",node.getAttribute('string')): + _.str.sprintf( "<%s>",node.tagName.toLowerCase()); + }else{ + return (node.getAttribute('string'))? + _.str.sprintf( "<%s string='%s'>",node.tagName.toLowerCase(), node.getAttribute('string')): + _.str.sprintf( "<%s>",node.tagName.toLowerCase()); } }, - xml_node_create: function(xml, root, parent_list, parent_id, main_object){ + do_delete_view: function() { + if (confirm(_t("Do you really want to remove this view?"))) { + var controller = this.action_manager.inner_viewmanager.views[this.action_manager.inner_viewmanager.active_view].controller; + this.dataset.unlink([this.main_view_id]).then(function() { + controller.reload_content(); + this.main_view_id = self.parent.fields_view.view_id; + }); + } + }, + create_View_Node: function(node){ + ViewNode = { + 'level': ($(node).parents()).length + 1, + 'id': this.xml_element_id += 1, + 'att_list': [], + 'name': this.add_node_name(node), + 'child_id': [] + } + ViewNode.att_list.push(node.tagName.toLowerCase()); + _.each(node.attributes, function(att) { + ViewNode.att_list.push([att.nodeName, att.nodeValue]); + }); + return ViewNode; + }, + append_child_object: function(main_object, parent_id, child_obj_list) { + var self = this; + if (main_object.id == parent_id) { + main_object.child_id = child_obj_list; + return main_object; + } else { + _.each(main_object.child_id, function(child_object) { + self.append_child_object(child_object, parent_id, child_obj_list); + }); + } + }, + convert_arch_to_obj: function(xml_Node, main_object, parent_id) { var self = this; var child_obj_list = []; - var children_list = $(xml).filter(root).children(); - var parents = $(children_list[0]).parents().get(); - _.each(children_list, function (child_node) { - child_obj_list.push(self.check_attr(child_node,child_node.tagName.toLowerCase(),parents.length)); + _.each(xml_Node, function(element) { + child_obj_list.push(self.create_View_Node(element)); }); - if (children_list.length != 0) { - if (parents.length <= parent_list.length) { - parent_list.splice(parents.length - 1); + this.append_child_object(main_object, parent_id, child_obj_list); + var obj_xml_list = _.zip(xml_Node, child_obj_list); + _.each(obj_xml_list, function(node) { + var children = _.filter(node[0].childNodes, function(child) { + return child.nodeType == 1; + }); + if (children) { + self.convert_arch_to_obj(children, main_object, node[1].id); } - parent_list.push(parent_id); - self.save_object(main_object[0], parent_list.slice(1), child_obj_list); - } - for (var i = 0; i < children_list.length; i++) { - self.xml_node_create - (children_list[i], children_list[i].tagName.toLowerCase(), - parent_list, child_obj_list[i].id, main_object); - } + }); return main_object; }, parse_xml: function(arch, view_id) { - var root = $(arch).filter(":first")[0]; - var tag = root.tagName.toLowerCase(); - var obj ={'child_id':[],'id':this.xml_id++,'level':0,'att_list':[],'name':""}; - var root_object = this.check_attr(root,tag,0); - obj.child_id = this.xml_node_create(arch, tag, [], this.xml_id-1, [root_object], []) - return [obj]; + main_object = { + 'level': 0, + 'id': this.xml_element_id +=1, + 'att_list': [], + 'name': _.str.sprintf("", view_id), + 'child_id': [] + }; + var xml_arch = QWeb.load_xml(arch); + return [this.convert_arch_to_obj(xml_arch.childNodes, main_object, this.xml_element_id)]; }, - get_data: function() { + get_arch: function() { var self = this; var view_arch_list = []; - self.main_view_id =((this.view_edit_dialog.$element.find("input[name='radiogroup']:checked").parent()).parent()).attr('data-id'); - var ve_dataset = new openerp.web.DataSet(this, 'ir.ui.view'); - ve_dataset.read_ids([parseInt(self.main_view_id)], ['arch', 'type'], function (arch) { - one_object = self.parse_xml(arch[0].arch,self.main_view_id); - self.main_view_type = arch[0].type - view_arch_list.push({"view_id" : self.main_view_id, "arch" : arch[0].arch}); - dataset = new openerp.web.DataSetSearch(self, 'ir.ui.view', null, null); - dataset.read_slice([], {domain : [['inherit_id','=', parseInt(self.main_view_id)]]}, function (result) { - _.each(result, function(res) { - view_arch_list.push({"view_id":res.id,"arch":res.arch}); - self.inherit_view(one_object, res); - }); - return self.edit_view({"main_object": one_object, - "parent_child_id": self.parent_child_list(one_object, []), - "arch": view_arch_list}); - }); - }); - }, - parent_child_list : function(one_object, p_list) { - var self = this; - _.each(one_object , function(element){ - if(element.child_id.length != 0){ - p_list.push({"key":element.id,"value":_.pluck(element.child_id, 'id')}); - self.parent_child_list(element.child_id, p_list); - } - }); - return p_list; - }, - inherit_view : function(one_object, result) { - var self = this; - var root = $(result.arch).filter('*'); - var xml_list = []; - if (root[0].tagName.toLowerCase() == "data") { - xml_list = $(root[0]).children(); - } else { - xml_list.push(root[0]); - } - _.each(xml_list , function(xml){ - var parent_id; - var check_list = []; - var xpath_object = self.parse_xml(xml,result.id); - if (xml.tagName.toLowerCase() == "xpath" ) { - var part_expr = _.without($(xml).attr('expr').split("/"),""); - _.each(part_expr,function(part){ - check_list.push(_.without($.trim(part.replace(/[^a-zA-Z 0-9 _]+/g,'!')).split("!"),"")); + this.dataset.read_ids([parseInt(self.main_view_id)], ['arch', 'type'], function(arch) { + if (arch.length) { + var arch_object = self.parse_xml(arch[0].arch, self.main_view_id); + self.main_view_type = arch[0].type == 'tree'? 'list': arch[0].type; + view_arch_list.push({"view_id": self.main_view_id, "arch": arch[0].arch}); + self.dataset.read_slice([], {domain: [['inherit_id','=', parseInt(self.main_view_id)]]}, function(result) { + _.each(result, function(res) { + view_arch_list.push({"view_id": res.id, "arch": res.arch}); + self.inherit_view(arch_object, res); + }); + return self.edit_view({"main_object": arch_object, + "parent_child_id": self.parent_child_list(arch_object, []), + "arch": view_arch_list}); }); } else { - var temp = []; - _.each(xpath_object[0].child_id[0].att_list, function(list){ - if(!_.include(list, "position")){ - temp.push(list); - } - }); - check_list = [_.flatten(temp)]; + self.do_warn("Please select view in list :"); } - self.full_path_search(check_list ,one_object ,xpath_object); }); }, - full_path_search: function(check_list ,val ,xpath_object) { + parent_child_list : function(one_object, parent_list) { var self = this; - if(xpath_object.length!=0){ - var check = check_list[0]; - var obj; + _.each(one_object , function(element) { + if (element.child_id.length != 0) { + parent_list.push({"key": element.id, "value": _.pluck(element.child_id, 'id')}); + self.parent_child_list(element.child_id, parent_list); + } + }); + return parent_list; + }, + inherit_view : function(arch_object, result) { + var self = this, xml_list = [], xml_arch = QWeb.load_xml(result.arch); + if (xml_arch.childNodes[0].tagName == "data") { + xml_list = _.filter(xml_arch.childNodes[0].childNodes, function(child) { + return child.nodeType == 1; + }); + } else { + xml_list.push( xml_arch.childNodes[0]); + } + _.each(xml_list, function(xml) { + var expr_to_list = [], xpath_arch_object = self.parse_xml(QWeb.tools.xml_node_to_string(xml), result.id); + if (xml.tagName == "xpath") { + var part_expr = _.without(xml.getAttribute('expr').split("/"), ""); + _.each(part_expr, function(part) { + expr_to_list.push(_.without($.trim(part.replace(/[^a-zA-Z 0-9 _]+/g,'!')).split("!"), "")); + }); + } else { + var temp = _.reject(xpath_arch_object[0].child_id[0].att_list, function(list) { + return list instanceof Array? _.include(list, "position"): false; + }); + expr_to_list = [_.flatten(temp)]; + } + self.inherit_apply(expr_to_list, arch_object ,xpath_arch_object); + }); + }, + inherit_apply: function(expr_list ,arch_object ,xpath_arch_object) { + var self = this; + if (xpath_arch_object.length) { + var check = expr_list[0], obj = false; switch (check.length) { case 2: - if(parseInt(check[1])){ - var list_1 = _.select(val,function(element){ - var main_list = _.flatten(element.att_list); - return _.include(main_list, check[0]); + if (parseInt(check[1])) { + //for field[3] + var temp_list = _.select(arch_object, function(element) { + return _.include(_.flatten(element.att_list), check[0]); }); - obj = val[_.indexOf(val,list_1[parseInt(check[1])-1])]; + obj = arch_object[_.indexOf(arch_object, temp_list[parseInt(check[1]) - 1])]; } else { - obj = _.detect(val, function(element){ - var main_list = _.flatten(element.att_list); - return _.include(main_list, check[0]); + //for notebook[last()] + obj = _.detect(arch_object, function(element) { + return _.include(_.flatten(element.att_list), check[0]); }); } break; case 3: - obj = _.detect(val,function(element){ - var main_list = _.flatten(element.att_list); - check = _.uniq(check); - var insert = _.intersection(main_list,check); - if(insert.length == check.length ){return element;} + //for field[@name='type'] + obj = _.detect(arch_object, function(element){ + if ((_.intersection(_.flatten(element.att_list), _.uniq(check))).length == check.length) { + return element; + } }); break; case 1: - var list_1 = _.select(val,function(element){ - var main_list = _.flatten(element.att_list); - return _.include(main_list, check[0]); + //for /form/notebook + var temp_list = _.select(arch_object, function(element) { + return _.include(_.flatten(element.att_list), check[0]); }); - if(list_1.length != 0){ - (check_list.length == 1)? obj = list_1[0] : check_list.shift(); + if (temp_list.length != 0) { + expr_list.length == 1 ? obj = temp_list[0] : expr_list.shift(); } break; } - if(obj) { - check_list.shift(); - if (check_list.length !=0){ - self.full_path_search(check_list ,obj.child_id ,xpath_object); + if (obj) { + expr_list.shift(); + if (expr_list.length) { + self.inherit_apply(expr_list, obj.child_id, xpath_arch_object); } else { - var level = obj.level+1; - self.increase_level(xpath_object[0], level) - obj.child_id.push(xpath_object[0]); - xpath_object.pop(); - return; + self.increase_level(xpath_arch_object[0], obj.level + 1); + obj.child_id.push(xpath_arch_object[0]); + xpath_arch_object.pop(); } - } - else { - _.each(val,function(element){ - self.full_path_search(check_list ,element.child_id ,xpath_object); + } else { + _.each(arch_object, function(element) { + self.inherit_apply(expr_list, element.child_id, xpath_arch_object); }); } } @@ -253,30 +358,39 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({ self.increase_level(val, level + 1); }); }, + do_select_row: function(row_id) { + this.edit_xml_dialog.$element.find("tr[id^='viewedit-']").removeClass('ui-selected'); + this.edit_xml_dialog.$element.find("tr[id=viewedit-" + row_id + "]").addClass('ui-selected'); + }, + do_parent_img_hide_show: function(img) { + if ($(img).attr('src') == '/web/static/src/img/collapse.gif') { + $(img).attr('src', '/web/static/src/img/expand.gif'); + this.on_expand(img); + } else { + $(img).attr('src', '/web/static/src/img/collapse.gif'); + this.on_collapse(img); + } + }, edit_view: function(one_object) { var self = this; - this.edit_xml_dialog = new openerp.web.Dialog(this,{ + this.one_object = one_object; + this.edit_xml_dialog = new openerp.web.Dialog(this, { modal: true, - title: 'View Editor', + title: _.str.sprintf("View Editor %d - %s", self.main_view_id, self.model), width: 750, height: 500, buttons: { - "Inherited View": function(){ - //todo - }, - "Preview": function(){ + "Preview": function() { var action = { - context:self.session.user_context, - res_model : self.model, - views : [[self.main_view_id, self.main_view_type]], + context: self.session.user_context, + res_model: self.model, + views: [[self.main_view_id, self.main_view_type]], type: 'ir.actions.act_window', target: "new", flags: { sidebar: false, views_switcher: false, - action_buttons:false, - search_view:false, - pager:false, + action_buttons: false, }, }; var action_manager = new openerp.web.ActionManager(self); @@ -286,231 +400,765 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({ self.edit_xml_dialog.close(); } } + }).start().open(); + var no_property_att = []; + _.each(_PROPERTIES, function(val, key) { + if (! val.length) no_property_att.push(key); }); - this.edit_xml_dialog.start().open(); - this.edit_xml_dialog.$element.html(QWeb.render('view_editor', { - 'data': one_object['main_object'], - })); + this.edit_xml_dialog.$element.html(QWeb.render('view_editor', {'data': one_object['main_object'], 'no_properties': no_property_att})); this.edit_xml_dialog.$element.find("tr[id^='viewedit-']").click(function() { - self.edit_xml_dialog.$element.find("tr[id^='viewedit-']").removeClass('ui-selected'); - $(this).addClass('ui-selected'); + self.do_select_row(this.id.split('-')[1]); }); this.edit_xml_dialog.$element.find("img[id^='parentimg-']").click(function() { - if ($(this).attr('src') == '/web/static/src/img/collapse.gif') { - $(this).attr('src', '/web/static/src/img/expand.gif'); - self.on_expand(this); - } else { - $(this).attr('src', '/web/static/src/img/collapse.gif'); - var id = this.id.split('-')[1]; - self.on_collapse(this,one_object['parent_child_id'], one_object['main_object']); - } + self.do_parent_img_hide_show(this); }); this.edit_xml_dialog.$element.find("img[id^='side-']").click(function() { - var side = $(this).closest("tr[id^='viewedit-']") - var id_tr = (side.attr('id')).split('-')[1]; - var img = side.find("img[id='parentimg-"+id_tr+"']").attr('src'); ; - var level = parseInt(side.attr('level')); - var list_shift =[]; - var last_tr; - var cur_tr = side; - list_shift.push(side); - var next_tr; - var ls = side; - var view_id; - var view_xml_id; - while(1){ - ls = ls.prev(); - if((self.edit_xml_dialog.$element.find(ls).find('a').text()).search("view_id") != -1 - && parseInt(ls.attr('level')) < level){ - view_id = parseInt(($(ls).find('a').text()).replace(/[^0-9]+/g,'')); - view_xml_id = (ls.attr('id')).split('-')[1]; + self.on_select_img(this); + }); + }, + on_select_img: function(element_img) { + var self = this; + var side = $(element_img).closest("tr[id^='viewedit-']"); + this.one_object.clicked_tr_id = parseInt((side.attr('id')).split('-')[1]); + this.one_object.clicked_tr_level = parseInt(side.attr('level')); + var img = side.find("img[id='parentimg-" + this.one_object.clicked_tr_id + "']").attr('src'); + var view_id = 0, view_xml_id = 0, view_find = side; + //for view id finding + var min_level = this.one_object.clicked_tr_id; + if (($(side).find('a').text()).search("view_id") != -1) { + view_id = parseInt(($(view_find).find('a').text()).replace(/[^0-9]+/g, '')); + view_xml_id = (view_find.attr('id')).split('-')[1]; + this.one_object.clicked_tr_id += 1; + this.one_object.clicked_tr_level += 1; + }else{ + while (1) { + view_find = view_find.prev(); + if (view_find.length == 0 || + (self.edit_xml_dialog.$element.find(view_find).find('a').text()).search("view_id") != -1 + && parseInt(view_find.attr('level')) < min_level ) { + view_id = parseInt(($(view_find).find('a').text()).replace(/[^0-9]+/g, '')); + view_xml_id = parseInt((view_find.attr('id')).split('-')[1]); break; } + if (view_find.attr('level') < min_level) { + min_level = parseInt(view_find.attr('level')); + } } - switch (this.id) { - case "side-add": - break; - case "side-remove": - break; - case "side-edit": - break; - case "side-up": - while (1) { - var prev_tr = cur_tr.prev(); - if(level >= parseInt(prev_tr.attr('level')) || prev_tr.length == 0) { - last_tr = prev_tr; - break; - } - cur_tr = prev_tr; - } - if (img) { - while (1) { - next_tr = side.next(); - if ( parseInt(next_tr.attr('level')) <= level || next_tr.length == 0) { - break; - } else { - list_shift.push(next_tr); - side = next_tr; - } - } - } - if (last_tr.length != 0 && parseInt(last_tr.attr('level')) == level && - (self.edit_xml_dialog.$element.find(last_tr).find('a').text()).search("view_id") == -1) { - _.each(list_shift, function(rec) { - $(last_tr).before(rec); - }); - self.save_move_arch(one_object, view_id, view_xml_id, id_tr, level, "up"); - } + } + this.one_object.clicked_tr_view = [view_id, view_xml_id]; + switch (element_img.id) { + case "side-add": + self.do_node_add(side); + break; + case "side-remove": + if (confirm(_t("Do you really want to remove this node?"))) { + self.do_save_update_arch("remove_node"); + } + break; + case "side-edit": + self.do_node_edit(side); + break; + case "side-up": + self.do_node_up(side, img); break; case "side-down": - if (img) { - while (1) { - next_tr = cur_tr.next(); - if ( parseInt(next_tr.attr('level')) <= level || next_tr.length == 0) { - last_tr = next_tr; - break; - } else { - list_shift.push(next_tr); - cur_tr = next_tr; - } - } - } - else { - last_tr = cur_tr.next(); - } - if((self.edit_xml_dialog.$element.find(last_tr).find('a').text()).search("view_id") != -1){ - return; - } - if (last_tr.length != 0 && parseInt(last_tr.attr('level')) == level) { - var last_tr_id = (last_tr.attr('id')).split('-')[1]; - img = last_tr.find("img[id='parentimg-" + last_tr_id + "']").attr('src'); - if (img) { - self.edit_xml_dialog.$element.find("img[id='parentimg-" + last_tr_id + "']"). - attr('src', '/web/static/src/img/expand.gif'); - while (1) { - var next_tr = last_tr.next(); - if (next_tr.attr('level') <= level || next_tr.length == 0) break; - next_tr.hide(); - last_tr = next_tr; - } - } - list_shift.reverse(); - _.each(list_shift, function(rec) { - $(last_tr).after(rec); - }); - self.save_move_arch(one_object, view_id, view_xml_id, id_tr, level, "down"); - } + self.do_node_down(side, img); break; - } + } + }, + do_node_add: function(side){ + var self = this; + var tr = $(side).find('a').text(); + var parent_tr = ($(side).prevAll("tr[level=" + String(this.one_object.clicked_tr_level - 1) + "]"))[0]; + var field_dataset = new openerp.web.DataSetSearch(this, this.model, null, null); + parent_tr = $(parent_tr).find('a').text(); + field_dataset.call( 'fields_get', [], function(result) { + var fields = _.keys(result); + fields.push(" "),fields.sort(); + var property_to_check = []; + _.each([tr, parent_tr],function(element) { + property_to_check.push( + _.detect(_.keys(_CHILDREN),function(res){ + return _.str.include(element, res); + })); + }); + self.on_add_node(property_to_check, fields); }); }, - save_move_arch: function(one_object, view_id, view_xml_id, id_tr, level, move_direct){ + do_node_edit: function(side) { var self = this; - var arch = _.detect(one_object['arch'],function(element){ - return element.view_id == view_id; - }); - var obj = self.get_view_object(view_xml_id, one_object['main_object'], []); - if(($(arch.arch).filter("data")).length != 0 && view_xml_id != 0){ + var result = self.get_object_by_id(this.one_object.clicked_tr_id, this.one_object['main_object'], []); + if (result.length && result[0] && result[0].att_list) { + var properties = _PROPERTIES[result[0].att_list[0]]; + self.on_edit_node(properties); + } + }, + do_node_down: function(cur_tr, img) { + var self = this, next_tr, last_tr, tr_to_move = []; + tr_to_move.push(cur_tr); + if (img) { + while (1) { + next_tr = cur_tr.next(); + if ( parseInt(next_tr.attr('level')) <= this.one_object.clicked_tr_level || next_tr.length == 0) { + last_tr = next_tr; + break; + } else { + tr_to_move.push(next_tr); + cur_tr = next_tr; + } + } + } else { + last_tr = cur_tr.next(); + } + if ((self.edit_xml_dialog.$element.find(last_tr).find('a').text()).search("view_id") != -1) { + return false; + } + if (last_tr.length != 0 && parseInt(last_tr.attr('level')) == this.one_object.clicked_tr_level) { + var last_tr_id = (last_tr.attr('id')).split('-')[1]; + img = last_tr.find("img[id='parentimg-" + last_tr_id + "']").attr('src'); + if (img) { + self.edit_xml_dialog.$element.find("img[id='parentimg-" + last_tr_id + "']"). + attr('src', '/web/static/src/img/expand.gif'); + while (1) { + var next_tr = last_tr.next(); + if (next_tr.attr('level') <= this.one_object.clicked_tr_level || next_tr.length == 0) break; + next_tr.hide(); + last_tr = next_tr; + } + } + tr_to_move.reverse(); + _.each(tr_to_move, function(rec) { + $(last_tr).after(rec); + }); + self.do_save_update_arch("down"); + } + }, + do_node_up: function(cur_tr, img) { + var self = this, side = cur_tr, tr_to_move = []; + tr_to_move.push(side); + while (1) { + var prev_tr = cur_tr.prev(); + if (this.one_object.clicked_tr_level >= parseInt(prev_tr.attr('level')) || prev_tr.length == 0) { + last_tr = prev_tr; + break; + } + cur_tr = prev_tr; + } + if (img) { + self.edit_xml_dialog.$element.find("img[id='parentimg-" + this.one_object.clicked_tr_id + "']"). + attr('src', '/web/static/src/img/expand.gif'); + while (1) { + next_tr = side.next(); + if (parseInt(next_tr.attr('level')) <= this.one_object.clicked_tr_level || next_tr.length == 0) { + break; + } else { + next_tr.hide(); + tr_to_move.push(next_tr); + side = next_tr; + } + } + } + if (last_tr.length != 0 && parseInt(last_tr.attr('level')) == this.one_object.clicked_tr_level && + (self.edit_xml_dialog.$element.find(last_tr).find('a').text()).search("view_id") == -1) { + _.each(tr_to_move, function(rec) { + $(last_tr).before(rec); + }); + self.do_save_update_arch("up"); + } + }, + do_save_update_arch: function(move_direct, update_values) { + var self = this; + var arch = _.detect(self.one_object['arch'], function(element) + {return element.view_id == self.one_object.clicked_tr_view[0]}); + var obj = self.get_object_by_id(this.one_object.clicked_tr_view[1],this.one_object['main_object'], []); + //for finding xpath tag from inherit view + var xml_arch = QWeb.load_xml(arch.arch); + if (xml_arch.childNodes[0].tagName == "data") { var check_list = _.flatten(obj[0].child_id[0].att_list); - arch.arch = _.detect($(arch.arch).children(), function(xml_child){ - var temp_obj = self.check_attr(xml_child, xml_child.tagName.toLowerCase()); - var main_list = _.flatten(temp_obj.att_list); - check_list = _.uniq(check_list); - var insert = _.intersection(main_list,check_list); - if(insert.length == check_list.length ){return xml_child;} + var children = _.filter(xml_arch.childNodes[0].childNodes, function (child) { + return child.nodeType == 1; + }); + arch.arch = _.detect(children, function(xml_child) { + var temp_obj = self.create_View_Node(xml_child), + insert = _.intersection(_.flatten(temp_obj.att_list),_.uniq(check_list)); + if (insert.length == check_list.length ) {return xml_child;} }); } - return self.get_node(arch.arch, obj[0].child_id[0], parseInt(id_tr), [], parseInt(level), - parseInt(view_id), arch, move_direct); + arch_to_pass = _.filter($(arch.arch), function (child) { + return child.nodeType == 1; + }); + return self.do_save_xml(arch_to_pass[0], obj[0].child_id[0],[], move_direct, update_values,arch); }, - - get_view_object: function(view_xml_id, one_object,result){ + get_object_by_id: function(id, one_object, result) { var self = this; - if(result.length==0){ - var check = _.detect(one_object , function(obj){ - return view_xml_id==obj.id; + if (result.length == 0 ) { + var check = _.detect(one_object , function(obj) { + return id == obj.id; }); - if(check){result.push(check);}; - _.each(one_object, function(obj){ - self.get_view_object(view_xml_id, obj.child_id, result); + if (check) {result.push(check);}; + _.each(one_object, function(obj) { + self.get_object_by_id(id,obj.child_id, result); }); } return result; }, - get_node: function(arch1, obj, id, child_list, level, view_id, arch, move_direct){ + create_clone: function(clone, new_node_obj, position){ var self = this; - var children_list = $(arch1).children(); - var list_obj_xml = _.zip(children_list,obj.child_id); - if (id) { - if (obj.id == id) { - var id; - var parent = $(arch1).parents(); - var index = _.indexOf(child_list, obj) - var re_insert_obj = child_list.splice(index, 1); + clone.find('a').text(new_node_obj.name); + ($(clone.find('a').parent()).siblings('td')).css( "padding-left", 20 * new_node_obj.level); + clone.attr("id", "viewedit-" + new_node_obj.id); + clone.attr("level", new_node_obj.level); + clone.find("img[id^='parentimg-']").remove(); + clone.bind("click",function(){ + self.do_select_row(this.id.split('-')[1]); + }); + clone.find("img[id^='side-']").click(function() { + self.on_select_img(this); + }); + return clone; + }, + do_save_xml: function(arch1, obj, child_list, move_direct, update_values, arch){ + var self = this, children_list = $(arch1).children(), list_obj_xml = _.zip(children_list, obj.child_id); + if (this.one_object.clicked_tr_id) { + if (obj.id == this.one_object.clicked_tr_id) { + var parent = false, index = _.indexOf(child_list, obj); if (move_direct == "down") { var next = $(arch1).next(); $(next).after(arch1); + var re_insert_obj = child_list.splice(index, 1); child_list.splice(index+1, 0, re_insert_obj[0]); - } else { + parent = $(arch1).parents(); + } else if (move_direct == "up") { var prev = $(arch1).prev(); $(prev).before(arch1); + var re_insert_obj = child_list.splice(index, 1); child_list.splice(index-1, 0, re_insert_obj[0]); + parent = $(arch1).parents(); + } else if (move_direct == "update_node") { + _.each(update_values, function(val){ + if (val[1]) $(arch1)[0].setAttribute(val[0], val[1]); + else $(arch1)[0].removeAttribute(val[0]); + }); + var new_obj = self.create_View_Node(arch1); + new_obj.id = obj.id,new_obj.child_id = obj.child_id; + self.edit_xml_dialog.$element. + find("tr[id='viewedit-"+this.one_object.clicked_tr_id+"']"). + find('a').text(new_obj.name); + child_list.splice(index, 1, new_obj); + parent = $(arch1).parents(); + } else if(move_direct == "add_node") { + var tr_click = self.edit_xml_dialog.$element.find("tr[id='viewedit-"+self.one_object.clicked_tr_id+"']"), + temp_xml = QWeb.load_xml(update_values[0]), + object_xml = self.create_View_Node(temp_xml.childNodes[0]); + (update_values[1] == "Inside")? object_xml.level = obj.level + 1:object_xml.level = obj.level; + var clone = self.create_clone(tr_click.clone(),object_xml), + after_append = _.detect(self.one_object['parent_child_id'],function(ele){ + return self.one_object.clicked_tr_id == ele.key; + }); + after_append = (after_append)?_.last(after_append.value):self.one_object.clicked_tr_id; + switch (update_values[1]) { + case "After": + self.edit_xml_dialog.$element. + find("tr[id='viewedit-"+after_append+"']").after(clone); + $(arch1).after(update_values[0]); + child_list.splice(index + 1, 0, object_xml); + break; + case "Before": + tr_click.before(clone); + $(arch1).before(update_values[0]); + child_list.splice(index - 1, 0, object_xml); + break; + case "Inside": + if (tr_click.find("img[id^='parentimg-']").length == 0) { + ($(tr_click.find('a').parent()).siblings('td')) + .append($('').attr('src', '/web/static/src/img/collapse.gif'). + attr('id','parentimg-'+ self.one_object.clicked_tr_id).click(function(){ + self.do_parent_img_hide_show(this); + })); + } + $(arch1).append(update_values[0]); + self.edit_xml_dialog.$element. + find("tr[id='viewedit-"+after_append+"']").after(clone); + obj.child_id.push(object_xml); + break; + } + self.edit_xml_dialog.$element. + find("tr[id='viewedit-" + object_xml.id + "']").removeClass('ui-selected'); + parent = $(arch1).parents(); + } else if (move_direct == "remove_node") { + parent = $(arch1).parents(); + if (parent.length == 0 || (parent[0].tagName.toLowerCase() == "data")) { + self.one_object.clicked_tr_id = self.one_object.clicked_tr_id -1; + self.one_object.clicked_tr_level = self.one_object.clicked_tr_level - 1; + (parent.length == 0)?parent.push("remove_view"):false; + } + $(arch1).remove(); + child_list.splice(index,1); + var cur_tr = self.edit_xml_dialog.$element. + find("tr[id='viewedit-" + self.one_object.clicked_tr_id + "']"); + _.each(self.get_list_tr(cur_tr,self.one_object.clicked_tr_level), function(tr_element){ + tr_element.remove(); + }); + cur_tr.remove(); + var parent_img = _.detect(self.one_object['parent_child_id'],function(element){ + return _.include(element.value, self.one_object.clicked_tr_id); + }); + if(parent_img.value.length == 1){ + self.edit_xml_dialog.$element. + find("tr[id='viewedit-"+parent_img.key+"']"). + find("img[id^='parentimg-']").remove(); + } + self.one_object['parent_child_id'] = self.parent_child_list(self.one_object['main_object'],[]); } - parent = parent[parent.length-1]; - var convert_to_utf = self.xml2Str(parent); - if (convert_to_utf) { + var convert_to_utf = (parent.length != 0)? parent[parent.length-1]: arch1; + if (convert_to_utf != "remove_view") { + convert_to_utf = QWeb.tools.xml_node_to_string(convert_to_utf); convert_to_utf = convert_to_utf.replace('xmlns="http://www.w3.org/1999/xhtml"', ""); convert_to_utf = '' + convert_to_utf; arch.arch = convert_to_utf; - dataset = new openerp.web.DataSet(this, 'ir.ui.view'); - dataset.write(parseInt(view_id),{"arch":convert_to_utf}, function(r) { - }); + this.dataset.write(this.one_object.clicked_tr_view[0] ,{"arch":convert_to_utf}, function(r) {}); + } else { + this.dataset.unlink([this.one_object.clicked_tr_view[0]],function(res) {}); + } + if(move_direct == "add_node"){ + self.add_node_dialog.close(); + self.on_select_img(clone.find("img[id='side-edit']")[0]); + self.one_object['parent_child_id'] = self.parent_child_list(self.one_object['main_object'],[]); } } - if (obj.level <= level) { + if (obj.level <= this.one_object.clicked_tr_level) { _.each(list_obj_xml, function(child_node) { - self.get_node(child_node[0], child_node[1], id, obj.child_id, level, view_id, arch, move_direct); + self.do_save_xml(child_node[0], child_node[1], obj.child_id, move_direct, update_values, arch); }); } } }, - xml2Str: function(xmlNode) { - try { - return (new XMLSerializer()).serializeToString(xmlNode); - } - catch (e) { - try { - return xmlNode.xml; - } - catch (e) { - return false; - } - } - - }, on_expand: function(expand_img){ var level = parseInt($(expand_img).closest("tr[id^='viewedit-']").attr('level')); var cur_tr = $(expand_img).closest("tr[id^='viewedit-']"); + _.each(this.get_list_tr(cur_tr,level), function(tr_element){ + tr_element.hide(); + }); + }, + get_list_tr: function(cur_tr,level){ + tr_list = []; while (1) { var nxt_tr = cur_tr.next(); - if (parseInt(nxt_tr.attr('level')) > level){ + if (parseInt(nxt_tr.attr('level')) > level) { cur_tr = nxt_tr; - nxt_tr.hide(); - } else return nxt_tr; + tr_list.push(nxt_tr); + } else return tr_list; } }, - on_collapse: function(collapse_img, parent_child_id, id, main_object) { - var self = this; - var id = collapse_img.id.split('-')[1]; - var datas = _.detect(parent_child_id,function(res) { + on_collapse: function(collapse_img) { + var self = this, id = collapse_img.id.split('-')[1]; + var datas = _.detect(self.one_object['parent_child_id'] , function(res) { return res.key == id; }); - _.each(datas.value, function(rec) { - var tr = self.edit_xml_dialog.$element.find("tr[id='viewedit-"+rec+"']"); - tr.find("img[id='parentimg-"+rec+"']").attr('src','/web/static/src/img/expand.gif'); + _.each(datas.value, function (rec) { + var tr = self.edit_xml_dialog.$element.find("tr[id='viewedit-" + rec + "']"); + tr.find("img[id='parentimg-" + rec + "']").attr('src', '/web/static/src/img/expand.gif'); tr.show(); }); + }, + on_edit_node: function(properties){ + var self = this; + this.edit_node_dialog = new openerp.web.Dialog(this,{ + modal: true, + title: 'Properties', + width: 500, + height: 400, + buttons: { + "Update": function(){ + var warn = false, update_values = []; + _.each(self.edit_widget, function(widget) { + if (widget.is_invalid) { + warn = true; + return false; + }; + if (widget.dirty && !widget.is_invalid) { + update_values.push([widget.name, widget.get_value()]); + } + }); + if (warn) { + self.on_valid_create_view(self.edit_widget); + } else { + self.do_save_update_arch("update_node", update_values); + self.edit_node_dialog.close(); + } + }, + "Cancel": function(){ + self.edit_node_dialog.close(); + } + } + }); + this.edit_node_dialog.start().open(); + var _PROPERTIES_ATTRIBUTES = { + 'name' : {'name':'name', 'string': 'Name', 'type': 'char'}, + 'string' : {'name':'string', 'string': 'String', 'type': 'char'}, + 'required' : {'name':'required', 'string': 'Required', 'type': 'boolean'}, + 'readonly' : {'name':'readonly', 'string': 'Readonly', 'type': 'boolean'}, + 'domain' : {'name':'domain', 'string': 'Domain', 'type': 'char'}, + 'context' : {'name':'context', 'string': 'Context', 'type': 'char'}, + 'limit' : {'name':'limit', 'string': 'Limit', 'type': 'float'}, + 'min_rows' : {'name':'min_rows', 'string': 'Minimum rows', 'type': 'float'}, + 'date_start' : {'name':'date_start', 'string': 'Start date', 'type': 'char'}, + 'date_delay' : {'name':'date_delay', 'string': 'Delay date', 'type': 'char'}, + 'day_length' : {'name':'day_length', 'string': 'Day length', 'type': 'char'}, + 'mode' : {'name':'mode', 'string': 'Mode', 'type': 'char'}, + 'align' : {'name':'align', 'string': 'Alignment ', 'type': 'selection', 'selection': [['', ''], ['0.0', 'Left'], ['0.5', 'Center'], ['1.0', 'Right']]}, + 'icon' : {'name':'icon', 'string': 'Icon', 'type': 'selection', 'selection': _ICONS}, + 'type' : {'name':'type', 'string': 'Type', 'type': 'selection', 'selection': [['', ''], ['action', 'Action'], ['object', 'Object'], ['workflow', 'Workflow'], ['server_action', 'Server Action']]}, + 'special' : {'name':'special', 'string': 'Special', 'type': 'selection', 'selection': [['',''],['save', 'Save Button'], ['cancel', 'Cancel Button'], ['open', 'Open Button']]}, + 'target' : {'name':'target', 'string': 'Target', 'type': 'selection', 'selection': [['', ''], ['new', 'New Window']]}, + 'confirm' : {'name':'confirm', 'string': 'Confirm', 'type': 'char'}, + 'style' : {'name':'style', 'string': 'Style', 'type': 'selection', 'selection':[["",""],["1", "1"],["1-1", "1-1"],["1-2", "1-2"],["2-1", "2-1"],["1-1-1", "1-1-1"]]}, + 'filename' : {'name':'filename', 'string': 'File Name', 'type': 'char'}, + 'width' : {'name':'width', 'string': 'Width', 'type': 'float'}, + 'height' : {'name':'height', 'string': 'Height', 'type': 'float'}, + 'attrs' : {'name':'attrs', 'string': 'Attrs', 'type': 'char'}, + 'col' : {'name':'col', 'string': 'col', 'type': 'float'}, + 'link' : {'name':'link', 'string': 'Link', 'type': 'char'}, + 'position' : {'name':'position', 'string': 'Position', 'type': 'selection', 'selection': [['',''],['after', 'After'],['before', 'Before'],['inside', 'Inside'],['replace', 'Replace']]}, + 'states' : {'name':'states', 'string': 'states', 'type': 'char'}, + 'eval' : {'name':'eval', 'string': 'Eval', 'type': 'char'}, + 'ref' : {'name':'ref', 'string': 'Ref', 'type': 'char'}, + 'on_change' : {'name':'on_change', 'string': 'On change', 'type': 'char'}, + 'nolabel' : {'name':'nolabel', 'string': 'No label', 'type': 'boolean'}, + 'completion' : {'name':'completion', 'string': 'Completion', 'type': 'boolean'}, + 'colspan' : {'name':'colspan', 'string': 'Colspan', 'type': 'float'}, + 'widget' : {'name':'widget', 'string': 'widget', 'type': 'selection'}, + 'colors' : {'name':'colors', 'string': 'Colors', 'type': 'char'}, + 'editable' : {'name':'editable', 'string': 'Editable', 'type': 'selection', 'selection': [["",""],["top","Top"],["bottom", "Bottom"]]}, + 'groups' : {'name':'groups', 'string': 'Groups', 'type': 'seleciton_multi'}, + }; + var arch_val = self.get_object_by_id(this.one_object.clicked_tr_id,this.one_object['main_object'], []); + this.edit_node_dialog.$element.append('
'); + this.edit_widget = []; + self.ready = $.when(self.on_groups(properties)).then(function () { + _PROPERTIES_ATTRIBUTES['groups']['selection'] = self.groups; + var values = _.keys( openerp.web.form.widgets.map); + values.push(''); + values.sort(); + _PROPERTIES_ATTRIBUTES['widget']['selection'] = values; + var widgets = _.filter(_PROPERTIES_ATTRIBUTES, function(property){ return _.include(properties, property.name)}) + _.each(widgets, function(widget) { + var type_widget = new (self.property.get_any([widget.type])) (self.edit_node_dialog, widget); + var value = _.detect(arch_val[0]['att_list'],function(res) { + return res instanceof Array? _.include(res, widget.name): false; + }); + value = value instanceof Array ? value[1] : value; + self.edit_node_dialog.$element.find('table[id=rec_table]').append('' + widget.string + ':' + type_widget.render() + ''); + type_widget.start(); + type_widget.set_value(value); + self.edit_widget.push(type_widget); + }); + }); + }, + //for getting groups + on_groups: function(properties){ + var self = this, + def = $.Deferred(); + if (!_.include(properties, 'groups')) { + self.groups = false; + def.resolve(); + } + var group_ids = [], group_names = {}, groups = []; + var res_groups = new openerp.web.DataSetSearch(this,'res.groups', null, null), + model_data = new openerp.web.DataSetSearch(self,'ir.model.data', null, null); + res_groups + .read_slice([], {}) + .done(function(res_grp) { + _.each(res_grp,function(res){ + var key = res.id; + group_names[key]=res.name; + group_ids.push(res.id); + }); + model_data + .read_slice([],{domain:[['res_id', 'in', group_ids],['model','=','res.groups']]}) + .done(function(model_grp) { + _.each(model_grp, function(res_group) { + groups.push([res_group.module + "." + res_group.name,group_names[res_group.res_id]]); + }); + self.groups = groups; + def.resolve(); + }); + }) + return def.promise(); + }, + on_add_node: function(properties, fields){ + var self = this; + var render_list = [{'name': 'node_type','selection': _.keys(_CHILDREN).sort(), 'value': 'field', 'string': 'Node Type','type': 'selection'}, + {'name': 'field_value','selection': fields, 'value': false, 'string': '','type': 'selection'}, + {'name': 'position','selection': ['After','Before','Inside'], 'value': false, 'string': 'Position','type': 'selection'}]; + this.add_widget = []; + this.add_node_dialog = new openerp.web.Dialog(this,{ + modal: true, + title: 'Properties', + width: 450, + height: 190, + buttons: { + "Update": function(){ + var check_add_node = true, values = {}; + _.each(self.add_widget, function(widget) { + values[widget.name] = widget.get_value() || false; + }); + (values.position == "Inside")? + check_add_node =(_.include(_CHILDREN[properties[0]],values.node_type))?true:false: + check_add_node =(_.include(_CHILDREN[properties[1]],values.node_type))?true:false; + if(values.node_type == "field" && check_add_node ) + {check_add_node = (values.field_value != " ")?true:false; + } + if(check_add_node){ + var tag = (values.node_type == "field")? + _.str.sprintf("<%s name='%s'> ",values.node_type,values.field_value,values.node_type): + _.str.sprintf("<%s> ",values.node_type,values.node_type); + self.do_save_update_arch("add_node", [tag, values.position]); + }else{alert("Can't Update View");} + }, + "Cancel": function(){ + self.add_node_dialog.close(); + } + } + }).start().open(); + this.add_node_dialog.$element.append('
'); + var table_selector = self.add_node_dialog.$element.find('table[id=rec_table] tbody'); + _.each(render_list, function(node) { + type_widget = new (self.property.get_any([node.type])) (self.add_node_dialog, node); + if (node.name == "position") { + table_selector.append('' + node.string + '' + type_widget.render() + ''); + } else { + table_selector.append('' + node.string + '' + type_widget.render() ); + if (node.name == "field_value") { + table_selector.append(' '); + } + } + type_widget.start(); + type_widget.set_value(node.value); + self.add_widget.push(type_widget); + }); + table_selector.find("td[id^=]").attr("width","100px"); + self.add_node_dialog.$element.find('#new_field').click(function() { + model_data = new openerp.web.DataSetSearch(self,'ir.model', null, null); + model_data.read_slice([], {domain: [['model','=', self.model]]}, function(result) { + self.render_new_field(result[0].id); + }); + }); + }, + render_new_field :function(id){ + var self = this; + var action = { + context: {'default_model_id': id, 'manual':true}, + res_model: "ir.model.fields", + views: [[false, 'form']], + type: 'ir.actions.act_window', + target: "new", + flags: { + action_buttons: true, + } + } + var action_manager = new openerp.web.ActionManager(self); + $.when(action_manager.do_action(action)).then(function() { + var controller = action_manager.dialog_viewmanager.views['form'].controller; + controller.do_set_readonly.add_last(function(){ + action_manager.stop(); + new_fields_name = new openerp.web.DataSetSearch(self,'ir.model.fields', null, null); + new_fields_name.read_ids([controller.datarecord.id], ['name'], function(result) { + self.add_node_dialog.$element.find('select[id=field_value]').append($("").attr("value", result[0].name).text(result[0].name)); + _.detect(self.add_widget,function(widget){ + widget.name == "field_value"? widget.selection.push(result[0].name): false; + }); + }); + }); + }); } +}); +openerp.web.ViewEditor.Field = openerp.web.Class.extend({ + init: function(view, widget) { + this.$element = view.$element; + this.dirty = false; + this.name = widget.name; + this.selection = widget.selection || []; + this.required = widget.required || false; + this.string = widget.string || ""; + this.type = widget.type; + this.is_invalid = false; + }, + start: function () { + this.update_dom(); + }, + update_dom: function() { + this.$element.find("td[id=" + this.name + "]").toggleClass('invalid', this.is_invalid); + this.$element.find("td[id=" + this.name + "]").toggleClass('required', this.required); + }, + on_ui_change: function() { + this.validate(); + this.dirty = true; + this.update_dom(); + }, + validate: function() { + this.is_invalid = false; + try { + var value = openerp.web.parse_value(this.get_value(), this, ''); + this.is_invalid = this.required && value === ''; + } catch(e) { + this.is_invalid = true; + } + }, + render: function() { + return _.str.sprintf("%s", this.name, QWeb.render(this.template, {widget: this})) + }, +}); +openerp.web.ViewEditor.FieldBoolean = openerp.web.ViewEditor.Field.extend({ + template : "vieweditor_boolean", + start: function() { + var self = this; + this._super(); + this.$element.find("input[id="+ self.name+"]").change(function() { + self.on_ui_change(); + }); + }, + set_value: function(value) { + if (value) { + this.$element.find("input[id=" + this.name+ "]").attr('checked', true); + } + }, + get_value: function() { + return this.$element.find("input[id=" + this.name + "]").is(':checked')? "1" : null; + } +}); +openerp.web.ViewEditor.FieldChar = openerp.web.ViewEditor.Field.extend({ + template : "vieweditor_char", + start: function () { + var self = this; + this._super(); + this.$element.find("input[id="+ this.name+"]").css('width','100%').change(function() { + self.on_ui_change(); + }); + }, + set_value: function(value) { + this.$element.find("input[id=" + this.name + "]").val(value); + }, + get_value: function() { + return this.$element.find("input[id=" + this.name + "]").val(); + } +}); +openerp.web.ViewEditor.FieldSelect = openerp.web.ViewEditor.Field.extend({ + template : "vieweditor_selection", + start: function () { + var self = this; + this._super(); + this.$element.find("select[id=" + this.name + "]").css('width', '100%').change(function() { + self.on_ui_change(); + if (self.name == "node_type") { + if (self.get_value() == "field") { + self.$element.find('#new_field').show(); + self.$element.find("select[id=field_value]").show(); + } else { + self.$element.find('#new_field').hide(); + self.$element.find("select[id=field_value]").hide(); + } + } + }); + }, + set_value: function(value) { + var index = 0; + value = value === null? false: value; + for (var i = 0, ii = this.selection.length; i < ii; i++) { + if ((this.selection[i] instanceof Array && this.selection[i][1] === value) || this.selection[i] === value) index = i; + } + this.$element.find("select[id=" + this.name + "]")[0].selectedIndex = index; + }, + get_value: function() { + return this.$element.find("select[id=" + this.name + "]").val(); + } +}); +openerp.web.ViewEditor.FieldSelectMulti = openerp.web.ViewEditor.FieldSelect.extend({ + start: function () { + this._super(); + this.$element.find("select[id=" + this.name + "]").css('height', '100px').attr("multiple", true); + }, + set_value: function(value) { + var self = this; + self.$element.find("#groups option").attr("selected",false); + if (!value) return false; + _.each(this.selection, function(item) { + if (_.include(value.split(','), item[0])) { + self.$element.find("select[id="+self.name+"] option[value='" + item[0] +"']").attr("selected",1) + } + }); + } +}); +openerp.web.ViewEditor.FieldFloat = openerp.web.ViewEditor.FieldChar.extend({ +}); +var _PROPERTIES = { + 'field' : ['name', 'string', 'required', 'readonly', 'domain', 'context', 'nolabel', 'completion', + 'colspan', 'widget', 'eval', 'ref', 'on_change', 'attrs', 'groups'], + 'form' : ['string', 'col', 'link'], + 'notebook' : ['colspan', 'position', 'groups'], + 'page' : ['string', 'states', 'attrs', 'groups'], + 'group' : ['string', 'col', 'colspan', 'states', 'attrs', 'groups'], + 'image' : ['filename', 'width', 'height', 'groups'], + 'separator' : ['string', 'colspan', 'groups'], + 'label': ['string', 'align', 'colspan', 'groups'], + 'button': ['name', 'string', 'icon', 'type', 'states', 'readonly', 'special', 'target', 'confirm', 'context', 'attrs', 'colspan', 'groups'], + 'newline' : [], + 'board': ['style'], + 'column' : [], + 'action' : ['name', 'string', 'colspan', 'groups'], + 'tree' : ['string', 'colors', 'editable', 'link', 'limit', 'min_rows'], + 'graph' : ['string', 'type'], + 'calendar' : ['string', 'date_start', 'date_stop', 'date_delay', 'day_length', 'color', 'mode'], +}; +var _CHILDREN = { + 'form': ['notebook', 'group', 'field', 'label', 'button','board', 'newline', 'separator'], + 'tree': ['field'], + 'graph': ['field'], + 'calendar': ['field'], + 'notebook': ['page'], + 'page': ['notebook', 'group', 'field', 'label', 'button', 'newline', 'separator'], + 'group': ['field', 'label', 'button', 'separator', 'newline'], + 'board': ['column'], + 'action': [], + 'field': ['form', 'tree', 'graph'], + 'label': [], + 'button' : [], + 'newline': [], + 'separator': [], +}; +var _ICONS = ['','STOCK_ABOUT', 'STOCK_ADD', 'STOCK_APPLY', 'STOCK_BOLD', + 'STOCK_CANCEL', 'STOCK_CDROM', 'STOCK_CLEAR', 'STOCK_CLOSE', 'STOCK_COLOR_PICKER', + 'STOCK_CONNECT', 'STOCK_CONVERT', 'STOCK_COPY', 'STOCK_CUT', 'STOCK_DELETE', + 'STOCK_DIALOG_AUTHENTICATION', 'STOCK_DIALOG_ERROR', 'STOCK_DIALOG_INFO', + 'STOCK_DIALOG_QUESTION', 'STOCK_DIALOG_WARNING', 'STOCK_DIRECTORY', 'STOCK_DISCONNECT', + 'STOCK_DND', 'STOCK_DND_MULTIPLE', 'STOCK_EDIT', 'STOCK_EXECUTE', 'STOCK_FILE', + 'STOCK_FIND', 'STOCK_FIND_AND_REPLACE', 'STOCK_FLOPPY', 'STOCK_GOTO_BOTTOM', + 'STOCK_GOTO_FIRST', 'STOCK_GOTO_LAST', 'STOCK_GOTO_TOP', 'STOCK_GO_BACK', + 'STOCK_GO_DOWN', 'STOCK_GO_FORWARD', 'STOCK_GO_UP', 'STOCK_HARDDISK', + 'STOCK_HELP', 'STOCK_HOME', 'STOCK_INDENT', 'STOCK_INDEX', 'STOCK_ITALIC', + 'STOCK_JUMP_TO', 'STOCK_JUSTIFY_CENTER', 'STOCK_JUSTIFY_FILL', + 'STOCK_JUSTIFY_LEFT', 'STOCK_JUSTIFY_RIGHT', 'STOCK_MEDIA_FORWARD', + 'STOCK_MEDIA_NEXT', 'STOCK_MEDIA_PAUSE', 'STOCK_MEDIA_PLAY', + 'STOCK_MEDIA_PREVIOUS', 'STOCK_MEDIA_RECORD', 'STOCK_MEDIA_REWIND', + 'STOCK_MEDIA_STOP', 'STOCK_MISSING_IMAGE', 'STOCK_NETWORK', 'STOCK_NEW', + 'STOCK_NO', 'STOCK_OK', 'STOCK_OPEN', 'STOCK_PASTE', 'STOCK_PREFERENCES', + 'STOCK_PRINT', 'STOCK_PRINT_PREVIEW', 'STOCK_PROPERTIES', 'STOCK_QUIT', + 'STOCK_REDO', 'STOCK_REFRESH', 'STOCK_REMOVE', 'STOCK_REVERT_TO_SAVED', + 'STOCK_SAVE', 'STOCK_SAVE_AS', 'STOCK_SELECT_COLOR', 'STOCK_SELECT_FONT', + 'STOCK_SORT_ASCENDING', 'STOCK_SORT_DESCENDING', 'STOCK_SPELL_CHECK', + 'STOCK_STOP', 'STOCK_STRIKETHROUGH', 'STOCK_UNDELETE', 'STOCK_UNDERLINE', + 'STOCK_UNDO', 'STOCK_UNINDENT', 'STOCK_YES', 'STOCK_ZOOM_100', + 'STOCK_ZOOM_FIT', 'STOCK_ZOOM_IN', 'STOCK_ZOOM_OUT', + 'terp-account', 'terp-crm', 'terp-mrp', 'terp-product', 'terp-purchase', + 'terp-sale', 'terp-tools', 'terp-administration', 'terp-hr', 'terp-partner', + 'terp-project', 'terp-report', 'terp-stock', 'terp-calendar', 'terp-graph' +]; +openerp.web.ViewEditor.property_widget = new openerp.web.Registry({ + 'boolean' : 'openerp.web.ViewEditor.FieldBoolean', + 'seleciton_multi' : 'openerp.web.ViewEditor.FieldSelectMulti', + 'selection' : 'openerp.web.ViewEditor.FieldSelect', + 'char' : 'openerp.web.ViewEditor.FieldChar', + 'float' : 'openerp.web.ViewEditor.FieldFloat', }); }; diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 8b84404f87a..8b3f4737658 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -107,7 +107,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# this.$form_header.find('button.oe_form_button_delete').click(this.on_button_delete); this.$form_header.find('button.oe_form_button_toggle').click(this.on_toggle_readonly); - if (this.options.sidebar && this.options.sidebar_id) { + if (!this.sidebar && this.options.sidebar && this.options.sidebar_id) { this.sidebar = new openerp.web.Sidebar(this, this.options.sidebar_id); this.sidebar.start(); this.sidebar.do_unfold(); @@ -242,69 +242,99 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# $pager.find('span.oe_pager_index').html(index); $pager.find('span.oe_pager_count').html(this.dataset.ids.length); }, + parse_on_change: function (on_change, widget) { + var self = this; + var onchange = _.str.trim(on_change); + var call = onchange.match(/^\s?(.*?)\((.*?)\)\s?$/); + if (!call) { + return null; + } + + var method = call[1]; + if (!_.str.trim(call[2])) { + return {method: method, args: [], context_index: null} + } + + var argument_replacement = { + 'False': function () {return false;}, + 'True': function () {return true;}, + 'None': function () {return null;}, + 'context': function (i) { + context_index = i; + var ctx = widget.build_context ? widget.build_context() : {}; + return ctx; + } + }; + var parent_fields = null, context_index = null; + var args = _.map(call[2].split(','), function (a, i) { + var field = _.str.trim(a); + + // literal constant or context + if (field in argument_replacement) { + return argument_replacement[field](i); + } + // literal number + if (/^-?\d+(\.\d+)?$/.test(field)) { + return Number(field); + } + // form field + if (self.fields[field]) { + var value = self.fields[field].get_on_change_value(); + return value == null ? false : value; + } + // parent field + var splitted = field.split('.'); + if (splitted.length > 1 && _.str.trim(splitted[0]) === "parent" && self.dataset.parent_view) { + if (parent_fields === null) { + parent_fields = self.dataset.parent_view.get_fields_values(); + } + var p_val = parent_fields[_.str.trim(splitted[1])]; + if (p_val !== undefined) { + return p_val == null ? false : p_val; + } + } + // string literal + var first_char = field[0], last_char = field[field.length-1]; + if ((first_char === '"' && last_char === '"') + || (first_char === "'" && last_char === "'")) { + return field.slice(1, -1); + } + + throw new Error("Could not get field with name '" + field + + "' for onchange '" + onchange + "'"); + }); + + return { + method: method, + args: args, + context_index: context_index + }; + }, do_onchange: function(widget, processed) { var self = this; var act = function() { try { - processed = processed || []; - if (widget.node.attrs.on_change) { - var onchange = _.str.trim(widget.node.attrs.on_change); - var call = onchange.match(/^\s?(.*?)\((.*?)\)\s?$/); - if (call) { - var method = call[1], args = []; - var context_index = null; - var argument_replacement = { - 'False' : function() {return false;}, - 'True' : function() {return true;}, - 'None' : function() {return null;}, - 'context': function(i) { - context_index = i; - var ctx = widget.build_context ? widget.build_context() : {}; - return ctx; - } - }; - var parent_fields = null; - _.each(call[2].split(','), function(a, i) { - var field = _.str.trim(a); - if (field in argument_replacement) { - args.push(argument_replacement[field](i)); - return; - } else if (self.fields[field]) { - var value = self.fields[field].get_on_change_value(); - args.push(value == null ? false : value); - return; - } else { - var splitted = field.split('.'); - if (splitted.length > 1 && _.str.trim(splitted[0]) === "parent" && self.dataset.parent_view) { - if (parent_fields === null) { - parent_fields = self.dataset.parent_view.get_fields_values(); - } - var p_val = parent_fields[_.str.trim(splitted[1])]; - if (p_val !== undefined) { - args.push(p_val == null ? false : p_val); - return; - } - } - } - throw "Could not get field with name '" + field + - "' for onchange '" + onchange + "'"; - }); - var ajax = { - url: '/web/dataset/call', - async: false - }; - return self.rpc(ajax, { - model: self.dataset.model, - method: method, - args: [(self.datarecord.id == null ? [] : [self.datarecord.id])].concat(args), - context_id: context_index === null ? null : context_index + 1 - }).pipe(function(response) { - return self.on_processed_onchange(response, processed); - }); - } else { - console.warn("Wrong on_change format", on_change); + processed = processed || []; + var on_change = widget.node.attrs.on_change; + if (on_change) { + var change_spec = self.parse_on_change(on_change, widget); + if (change_spec) { + var ajax = { + url: '/web/dataset/call', + async: false + }; + return self.rpc(ajax, { + model: self.dataset.model, + method: change_spec.method, + args: [(self.datarecord.id == null ? [] : [self.datarecord.id])].concat(change_spec.args), + context_id: change_spec.context_index == undefined ? null : change_spec.context_index + 1 + }).pipe(function(response) { + return self.on_processed_onchange(response, processed); + }); + } else { + console.warn("Wrong on_change format", on_change); + } } - } } catch(e) { console.error(e); return $.Deferred().reject(); @@ -578,6 +608,9 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# return false; } return true; + }, + sidebar_context: function () { + return this.do_save().pipe($.proxy(this, 'get_fields_values')); } }); openerp.web.FormDialog = openerp.web.Dialog.extend({ @@ -922,8 +955,9 @@ openerp.web.form.WidgetFrame = openerp.web.form.Widget.extend({ var type = {}; if (node.tag == 'field') { type = this.view.fields_view.fields[node.attrs.name] || {}; - if (node.attrs.widget == 'statusbar') { + if (node.attrs.widget == 'statusbar' && node.attrs.nolabel !== '1') { // This way we can retain backward compatibility between addons and old clients + node.attrs.colspan = (parseInt(node.attrs.colspan, 10) || 1) + 1; node.attrs.nolabel = '1'; } } @@ -956,7 +990,7 @@ openerp.web.form.WidgetFrame = openerp.web.form.Widget.extend({ }); openerp.web.form.WidgetGroup = openerp.web.form.WidgetFrame.extend({ - template: 'WidgetGroup', + template: 'WidgetGroup' }), openerp.web.form.WidgetNotebook = openerp.web.form.Widget.extend({ @@ -1571,7 +1605,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); @@ -2519,18 +2553,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]), @@ -3075,7 +3121,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); diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index 728b090d679..53c8d634ad1 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -661,8 +661,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/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js index dba0a1abba4..f6b7f85dee1 100644 --- a/addons/web/static/src/js/view_list_editable.js +++ b/addons/web/static/src/js/view_list_editable.js @@ -5,6 +5,7 @@ openerp.web.list_editable = function (openerp) { var KEY_RETURN = 13, KEY_ESCAPE = 27; + var QWeb = openerp.web.qweb; // editability status of list rows openerp.web.ListView.prototype.defaults.editable = null; @@ -350,6 +351,19 @@ openerp.web.list_editable = function (openerp) { new_record: function () { this.dataset.index = null; this.render_row_as_form(); + }, + render_record: function (record) { + var index = this.records.indexOf(record); + // FIXME: context dict should probably be extracted cleanly + return QWeb.render('ListView.row', { + columns: this.columns, + options: this.options, + record: record, + row_parity: (index % 2 === 0) ? 'even' : 'odd', + view: this.view, + render_cell: $.proxy(this, 'render_cell'), + edited: !!this.edition_form + }); } }); if (!openerp.web.list) { diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 90060f47fc1..582a526e57a 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) { @@ -679,13 +681,7 @@ session.web.Sidebar = session.web.Widget.extend({ item.callback.apply(self, [item]); } if (item.action) { - if (self.widget_parent instanceof session.web.FormView) { - self.widget_parent.do_save(function() { - self.on_item_action_clicked(item); - }); - } else { - self.on_item_action_clicked(item); - } + self.on_item_action_clicked(item); } return false; }); @@ -699,29 +695,31 @@ session.web.Sidebar = session.web.Widget.extend({ }, on_item_action_clicked: function(item) { var self = this; - var ids = self.widget_parent.get_selected_ids(); - if (ids.length == 0) { - //TODO: make prettier warning? - $("
").text(_t("You must choose at least one record.")).dialog({ - title: _t("Warning"), - modal: true + self.widget_parent.sidebar_context().then(function (context) { + var ids = self.widget_parent.get_selected_ids(); + if (ids.length == 0) { + //TODO: make prettier warning? + $("
").text(_t("You must choose at least one record.")).dialog({ + title: _t("Warning"), + modal: true + }); + return false; + } + var additional_context = _.extend({ + active_id: ids[0], + active_ids: ids, + active_model: self.widget_parent.dataset.model + }, context); + self.rpc("/web/action/load", { + action_id: item.action.id, + context: additional_context + }, function(result) { + result.result.context = _.extend(result.result.context || {}, + additional_context); + result.result.flags = result.result.flags || {}; + result.result.flags.new_window = true; + self.do_action(result.result); }); - return false; - } - var additional_context = { - active_id: ids[0], - active_ids: ids, - active_model: self.widget_parent.dataset.model - }; - self.rpc("/web/action/load", { - action_id: item.action.id, - context: additional_context - }, function(result) { - result.result.context = _.extend(result.result.context || {}, - additional_context); - result.result.flags = result.result.flags || {}; - result.result.flags.new_window = true; - self.do_action(result.result); }); }, do_fold: function() { @@ -979,6 +977,9 @@ session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{ }); }, on_sidebar_view_log: function() { + }, + sidebar_context: function () { + return $.Deferred().resolve({}).promise(); } }); diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index fb7ccdf7d8e..1fe4d028db4 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -360,6 +360,10 @@
  • +
  • + + +
  • LOGOUT @@ -530,16 +534,17 @@ t-att-id="'treerow_' + record.id" t-att-data-id="record.id" t-att-data-level="level + 1"> - + + t-att-class="class"> + @@ -625,18 +630,9 @@ - - - - - - - - - - - - + + + + @@ -1148,6 +1145,16 @@

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

    + +
    +

    Select Dashboard to add this filter to:

    + +

    Title of new Dashboard item:

    + +
    +
    @@ -1369,6 +1376,18 @@ + + + +
    + + + + + $(document.createElement('t')) @@ -1392,51 +1411,70 @@
    - - - - - - - -
    - - - -
    - - - - - - - - - - -
    - - - - - - - - - -
    - - - - - - - + + + + + + + + +
    + + + + + +
    + + + + + + + + + + +
    + + + + + + + + + +
    + + + + + + + + + + + + + + + + Export diff --git a/addons/web/static/test/onchange.js b/addons/web/static/test/onchange.js new file mode 100644 index 00000000000..8074c755bd3 --- /dev/null +++ b/addons/web/static/test/onchange.js @@ -0,0 +1,74 @@ +$(document).ready(function () { + var openerp, + make_form = function (default_values) { + var fields = {}; + _(default_values).each(function (value, name) { + fields[name] = value instanceof Function ? value : { + get_on_change_value: function () { return value; } + }; + }); + return _.extend(new openerp.web.FormView(null, {}), + {fields: fields}); + }; + module("form.onchange", { + setup: function () { + openerp = window.openerp.init(true); + window.openerp.web.core(openerp); + window.openerp.web.chrome(openerp); + // views loader stuff + window.openerp.web.data(openerp); + window.openerp.web.views(openerp); + window.openerp.web.list(openerp); + window.openerp.web.form(openerp); + } + }); + test('Parse args-less onchange', function () { + var f = new openerp.web.FormView(null, {}); + var result = f.parse_on_change('on_change_foo()', {}); + equal(result.method, 'on_change_foo'); + deepEqual(result.args, []); + }); + test('Parse 1-arg onchange', function () { + var f = make_form({foo: 3}); + var result = f.parse_on_change('on_change_foo(foo)', {}); + equal(result.method, 'on_change_foo'); + deepEqual(result.args, [3]); + }); + test('Parse 2-args onchange', function () { + var f = make_form({foo: 3, bar: 'qux'}); + var result = f.parse_on_change('on_change_foo(bar, foo)', {}); + equal(result.method, 'on_change_foo'); + deepEqual(result.args, ['qux', 3]); + }); + test('Literal null', function () { + var f = make_form(); + var result = f.parse_on_change('on_null(None)', {}); + deepEqual(result.args, [null]); + }); + test('Literal true', function () { + var f = make_form(); + var result = f.parse_on_change('on_null(True)', {}); + deepEqual(result.args, [true]); + }); + test('Literal false', function () { + var f = make_form(); + var result = f.parse_on_change('on_null(False)', {}); + deepEqual(result.args, [false]); + }); + test('Literal string', function () { + var f = make_form(); + var result = f.parse_on_change('on_str("foo")', {}); + deepEqual(result.args, ['foo']); + var result2 = f.parse_on_change("on_str('foo')", {}); + deepEqual(result2.args, ['foo']); + }); + test('Literal number', function () { + var f = make_form(); + var result = f.parse_on_change('on_str(42)', {}); + deepEqual(result.args, [42]); + var result2 = f.parse_on_change("on_str(-25)", {}); + deepEqual(result2.args, [-25]); + var result3 = f.parse_on_change("on_str(25.02)", {}); + deepEqual(result3.args, [25.02]); + }); +}); diff --git a/addons/web/static/test/test.html b/addons/web/static/test/test.html index d182ce18707..b1018bc00ca 100644 --- a/addons/web/static/test/test.html +++ b/addons/web/static/test/test.html @@ -5,14 +5,14 @@ OpenERP - - + + - + @@ -49,4 +49,5 @@ + diff --git a/addons/web_calendar/__openerp__.py b/addons/web_calendar/__openerp__.py index 5b09e70cba8..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": [ @@ -8,8 +12,9 @@ 'static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_minical.js', 'static/src/js/calendar.js' ], - "css": ['static/lib/dhtmlxScheduler/codebase/dhtmlxscheduler.css', - 'static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_ext.css' + "css": [ + 'static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_ext.css', + 'static/src/css/web_calendar.css' ], 'qweb' : [ "static/src/xml/*.xml", 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/pt.po b/addons/web_calendar/po/pt.po new file mode 100644 index 00000000000..a2ba6e02a2a --- /dev/null +++ b/addons/web_calendar/po/pt.po @@ -0,0 +1,22 @@ +# Portuguese 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-21 21:57+0000\n" +"Last-Translator: Daniel Reis \n" +"Language-Team: Portuguese \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-22 05:13+0000\n" +"X-Generator: Launchpad (build 14299)\n" + +#: addons/web_calendar/static/src/xml/web_calendar.xml:0 +msgid " " +msgstr " " diff --git a/addons/web_calendar/static/src/css/web_calendar.css b/addons/web_calendar/static/src/css/web_calendar.css new file mode 100644 index 00000000000..cdad3ae794f --- /dev/null +++ b/addons/web_calendar/static/src/css/web_calendar.css @@ -0,0 +1,1062 @@ +#openerp_scheduler { + background-color:white; +} +.openerp .dhx_mini_calendar { + -moz-box-shadow: none; + -khtml-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} +.openerp .dhx_cal_container, .openerp .dhx_cal_event { + background-position:0 24px; + background-repeat:repeat-x; + font-family: Ubuntu, Helvetica, sans-serif; + position:relative; + overflow:hidden; +} +.openerp .dhx_cal_container.dhx_mini_calendar { + background-color:#eee; +} +.openerp .dhx_cal_container div{ + -moz-user-select:none; + -moz-user-select:-moz-none; +} + +.openerp .dhx_cal_navline{ + height:20px; position:absolute;z-index:3;width:750px;color:#2F3A48; +} +.openerp .dhx_cal_navline div{ + top:2px; + white-space:nowrap; +} + +.openerp .dhx_cal_navline .dhx_cal_date{ + font-weight:bold; + float:left; + font-size:1em; + margin:2px 0px 0px 10px; +} + +.openerp .dhx_cal_button .dhx_left_bg{width:1px;overflow:hidden;height:17px;z-index:20;top:0;} + +.openerp .dhx_cal_today_button, .openerp .dhx_cal_prev_button, .openerp .dhx_cal_next_button { + color:white; + height:17px; + line-height:17px; + font-weight:bold; + cursor:pointer; + font-size:90%; + text-decoration:none; + float:left; + margin:0px 3px; + padding:2px 2px; + border:1px solid black; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + vertical-align:0px; +} + +.openerp .dhx_cal_today_button { + background: #ccc; /* Old browsers */ + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#c9c9c9', endColorstr='#999999'); /* IE6-9 */ + background: -webkit-gradient(linear, left top, left bottom, from(#c9c9c9), to(#999999)); /* Chrome,Safari4+ */ + background: -moz-linear-gradient(top, #c9c9c9, #999999); /* FF3.6+ */ + background: -webkit-linear-gradient(top, #c9c9c9 0%,#999999 60%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(top, #c9c9c9 0%,#999999 60%); /* Opera11.10+ */ + background: -ms-linear-gradient(top, #c9c9c9 0%,#999999 60%); /* IE10+ */ + background: linear-gradient(top, #c9c9c9 0%,#999999 60%); /* W3C */ + padding-left:5px; + padding-right:5px; +} + +.openerp .dhx_cal_prev_button{ + background: #bbb; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#c9c9c9', endColorstr='#999999'); + background: url("/web_calendar/static/src/img/cal_left.png") 5px 3px, -webkit-gradient(linear, left top, left bottom, from(#c9c9c9), to(#999999)); + background: url("/web_calendar/static/src/img/cal_left.png") 5px 3px, -moz-linear-gradient(top, #c9c9c9, #999999); + background: url("/web_calendar/static/src/img/cal_left.png") 5px 3px, -webkit-linear-gradient(top, #c9c9c9 0%,#999999 60%); + background: url("/web_calendar/static/src/img/cal_left.png") 5px 3px, -o-linear-gradient(top, #c9c9c9 0%,#999999 60%); + background: url("/web_calendar/static/src/img/cal_left.png") 5px 3px, -ms-linear-gradient(top, #c9c9c9 0%,#999999 60%); + background: url("/web_calendar/static/src/img/cal_left.png") 5px 3px, linear-gradient(top, #c9c9c9 0%,#999999 60%); + background-repeat:no-repeat; + width:20px; +} + +.openerp .dhx_cal_next_button { + background: #ccc; /* Old browsers */ + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#888', endColorstr='#888'); /* IE6-9 */ + background: url("/web_calendar/src/img/cal_right.png") 5px 3px, -webkit-gradient(linear, left top, left bottom, from(#c9c9c9), to(#999999)); /* Chrome,Safari4+ */ + background: url("/web_calendar/static/src/img/cal_right.png") 5px 3px, -moz-linear-gradient(top, #c9c9c9, #999999); /* FF3.6+ */ + background: url("/web_calendar/static/src/img/cal_right.png") 5px 3px, -webkit-linear-gradient(top, #c9c9c9 0%,#999999 60%); /* Chrome10+,Safari5.1+ */ + background: url("/web_calendar/static/src/img/cal_right.png") 5px 3px, -o-linear-gradient(top, #c9c9c9 0%,#999999 60%); /* Opera11.10+ */ + background: url("/web_calendar/static/src/img/cal_right.png") 5px 3px, -ms-linear-gradient(top, #c9c9c9 0%,#999999 60%); /* IE10+ */ + background: url("/web_calendar/static/src/img/cal_right.png") 5px 3px, linear-gradient(top, #c9c9c9 0%,#999999 60%); /* W3C */ + background-repeat:no-repeat; + width:20px; +} + +.openerp .dhx_cal_prev_button:hover, .openerp .dhx_cal_prev_button:active { + background: #bbb; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#888', endColorstr='#888'); + background: url("/web_calendar/static/src/img/cal_left.png") 5px 3px, -webkit-gradient(linear, left top, left bottom, from(#888), to(#888)); + background: url("/web_calendar/static/src/img/cal_left.png") 5px 3px, -moz-linear-gradient(top, #888, #888); + background: url("/web_calendar/static/src/img/cal_left.png") 5px 3px, -webkit-linear-gradient(top, #888 0%,#888 60%); + background: url("/web_calendar/static/src/img/cal_left.png") 5px 3px, -o-linear-gradient(top, #888 0%,#888 60%); + background: url("/web_calendar/static/src/img/cal_left.png") 5px 3px, -ms-linear-gradient(top, #888 0%,#888 60%); + background: url("/web_calendar/static/src/img/cal_left.png") 5px 3px, linear-gradient(top, #888 0%,#888 60%); + background-repeat:no-repeat; +} + +.openerp .dhx_cal_next_button:hover, .openerp .dhx_cal_next_button:active { + background: #bbb; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#888', endColorstr='#888'); + background:-webkit-gradient(linear, left top, left bottom, from(#888), to(#888)); + background: url("/web_calendar/static/src/img/cal_right.png") 5px 3px, -moz-linear-gradient(top, #888, #888); + background: url("/web_calendar/static/src/img/cal_right.png") 5px 3px, -webkit-linear-gradient(top, #888 0%,#888 60%); + background: url("/web_calendar/static/src/img/cal_right.png") 5px 3px, -o-linear-gradient(top, #888 0%,#888 60%); + background: url("/web_calendar/static/src/img/cal_right.png") 5px 3px, -ms-linear-gradient(top, #888 0%,#888 60%); + background: url("/web_calendar/static/src/img/cal_right.png") 5px 3px, linear-gradient(top, #888 0%,#888 60%); + background-repeat:no-repeat; +} + +.openerp .dhx_cal_today_button:hover, .openerp .dhx_cal_today_button:active { + background: #bbb; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#bbb', endColorstr='#bbb'); + background: -webkit-gradient(linear, left top, left bottom, from(#888), to(#888)); + background: -moz-linear-gradient(top, #888, #888); + background: -webkit-linear-gradient(top, #888 0%,#888 60%); + background: -o-linear-gradient(top, #888 0%,#888 60%); + background: -ms-linear-gradient(top, #888 0%,#888 60%); + background: linear-gradient(top, #888 0%,#888 60%); + background-repeat:no-repeat; +} + +.openerp .dhx_mini_calendar .dhx_cal_prev_button, .openerp .dhx_mini_calendar .dhx_cal_next_button, .openerp .dhx_mini_calendar .dhx_cal_today_button { + background:none; + border:0px; +} +.openerp .dhx_mini_calendar .dhx_cal_prev_button, .openerp .dhx_mini_calendar .dhx_cal_next_button { + width:16px; + height:18px; +} +.openerp .dhx_mini_calendar .dhx_cal_prev_button { + background:url("/web_calendar/static/src/img/minical_left.png") no-repeat 5px 6px; +} + +.openerp .dhx_mini_calendar .dhx_cal_next_button { + background:url("/web_calendar/static/src/img/minical_right.png") no-repeat 8px 6px; +} + +.openerp .dhx_mini_calendar .dhx_month_head { + font-size:0.9em; + color:#888 +} +.openerp .dhx_mini_calendar .dhx_month_head:hover { + background-color:#bbb; + color:white; + text-shadow:none; +} +.openerp .dhx_mini_calendar .dhx_scale_bar { + border-width:0px; + padding:2px 0px; +} + +.openerp .dhx_cal_tab { + width:59px; + height:16px; + line-height:16px; + text-align:center; + text-transform:uppercase; + text-decoration:none; + font-weight:bold; + font-size:80%; + color:#555; + margin:6px 1px 0px 1px; + padding-top:2px; + cursor:pointer; + float:right; + background-color:#bbb; + -webkit-border-top-left-radius:4px; + -webkit-border-top-right-radius:4px; + -moz-border-radius-topleft:4px; + -moz-border-radius-topright:4px; + border-top-left-radius:4px; + border-top-right-radius:4px; +} +.openerp .dhx_cal_tab[name="month_tab"] { right:16px; } +.openerp .dhx_cal_tab[name="week_tab"] { right:78px; } +.openerp .dhx_cal_tab[name="day_tab"] { right:123px; } + +.openerp .dhx_cal_tab:hover { + background-color:#ddd; +} + +.openerp .dhx_cal_tab.active{ + height:17px; + line-height:17px; + text-decoration:none; + cursor:default; + border:1px dotted #8894A3; + border-bottom:0px; + background-color:white /*#F4F4F4;*/ +} + +.openerp .dhx_cal_tab[name="day_tab"] { + margin-right:18px; +} + +.openerp .dhx_cal_header{ + position:absolute; + left:10px; + top:23px; + width:750px; + text-transform:uppercase; + font-size:0.8em; + font-weight:bold; + color:#3F3F3F; + border-bottom:1px dotted #8894A3; + border-top:1px dotted #8894A3; + /*border-right:1px dotted #8894A3;z-index:2;*/ + overflow:hidden; + background-color: white; /*#F4F4F4;*/ + text-shadow: 0 1px 0 white; +} + +.openerp .dhx_cal_data{ + position:absolute; + top:44px; + width:600px; + overflow-y:auto; + overflow-x:hidden; +} + +.openerp .dhx_cal_data tr td { + border-width:0px; +} + +.openerp .dhx_scale_bar{ + position:absolute; + text-align:center; + text-shadow: 0 1px 0 white; + background-color:#C2D5FC; + padding-top:3px; + border-left:1px dotted #586A7E; +} + +.openerp .dhx_scale_holder{ + position:absolute; + border-right:1px solid #ccc; + background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/databg.png"); +} +.openerp .dhx_scale_holder_now{ + position:absolute; + border-right:1px solid #ccc; + background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/databg_now.png"); +} + +.openerp .dhx_scale_hour{ + height:41px; + width:50px; + border-bottom:1px dotted #8894A3; + border-right:1px dotted #8894A3; + background-color:#ddd; + text-align:center; + line-height:40px; + color:#586A7E; + overflow:hidden; +} + +.openerp .dhx_month_head{ + background-color:#F4F4F4; + color:#2F3A48; + text-shadow: 0 1px 0 white; + font-weight:bold; + text-align:center; + border-left:1px solid #E9E9E9; + height:18px; + padding-right:4px; + padding-top:4px; + text-align:right; + font-size:0.9em; +} +.openerp .dhx_mini_calendar .dhx_month_head{ + padding-right:6px; +} + +.openerp .dhx_cal_data table tbody tr td:nth-child(7) { + color:red; +} + + +.openerp .dhx_now .openerp .dhx_month_body{ + background-color:#cccccc; +} + +.openerp .dhx_after .dhx_month_body,.openerp .dhx_before .dhx_month_body{background-color:#ECECEC;} + +.openerp .dhx_after .dhx_month_head,.openerp .dhx_before .dhx_month_head{background-color:#F4F4F4;color:#94A6BB;} + +.openerp .dhx_now .dhx_month_head{ + background-color:#ddd; +} + +.openerp .dhx_cal_drag{position:absolute;z-index:9999;background-color:#FFE763;border:1px solid #B7A543;opacity:.5;filter:alpha(opacity=50);} + +.openerp .dhx_loading{position:absolute;width:128px;height:15px;background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/loading.gif);z-index:9999;} + +.openerp .dhx_multi_day_icon, .openerp .dhx_multi_day{ + background-color:#ddd; + background-repeat:no-repeat; + /*border-right:1px dotted #8894A3;*/ +} +.openerp .dhx_multi_day{ + position:absolute; +/*border-top:1px dotted #8894A3;*/ +} + +.openerp .dhx_multi_day_icon{ + background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/clock_big.gif); +} + +.openerp .dhx_multi_day_icon_small { + background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/clock_small.gif); +} + +.openerp .dhx_multi_day_icon, .openerp .dhx_multi_day_icon_small{ + background-position:center center; + background-repeat:no-repeat; + border:1px dotted #8894A3; + border-left:0px; +} + +.openerp .dhtmlxLayoutPolyContainer_dhx_skyblue .dhx_cal_container{background-color:none;} + +.openerp .dhx_cal_event div{ + font-family: Ubuntu, Helvetica, sans-serif; + background-color:#FFE763; + border:1px solid #a73636; + color:#887A2E; + overflow:hidden; + font-size:100%; +} + +.openerp .dhx_move_denied .dhx_cal_event .dhx_header, .openerp .dhx_move_denied .dhx_cal_event .dhx_title{cursor:default;} + +.openerp .dhx_cal_event .dhx_header{ + height:0px; + margin-left:1px; + /*border-width:1px 1px 0 1px;*/ + cursor:pointer; +} + +.openerp .dhx_cal_event .dhx_title{ + height:18px; + border-bottom-style:solid; + border-top-style:solid; + font-weight:bold; + text-align:center; + background-position:right; + background-repeat:no-repeat; + cursor:pointer; + vertical-align:middle; + padding-top:2px; + font-size: 90%; + -moz-border-radius-topleft: 3px; -webkit-border-top-left-radius: 3px; border-top-left-radius: 3px; -moz-border-radius-topright: 3px; -webkit-border-top-right-radius: 3px; border-top-right-radius: 3px; +} + +.openerp .dhx_cal_event .dhx_body{ + border-width:0 1px 1px 1px; + padding:0px 5px; + -moz-border-radius-bottomleft: 3px; -webkit-border-bottom-left-radius: 3px; border-bottom-left-radius: 3px; -moz-border-radius-bottomright: 3px; -webkit-border-bottom-right-radius: 3px; border-bottom-right-radius: 3px; + font-size:90%; + line-height:9px; +} + +.openerp .dhx_resize_denied .dhx_cal_event .dhx_footer{ + cursor:default; +} + +.openerp .dhx_cal_event .dhx_footer{ + height:2px; + margin-left:2px; + border-width:0 1px 1px 1px; + cursor:s-resize; + overflow:auto; +} + +/* +The old one + +.openerp .dhx_cal_event_line{ + background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/event-bg.png); + background-color:#FFE763; + border:1px solid #FFBD51; + border-radius:3px; + height:13px; + padding-left:10px; + color:#000; + cursor:pointer; + overflow:hidden; +}*/ + +.openerp .dhx_cal_event_clear, .openerp .dhx_cal_event_line{ + font-family:Ubuntu, Helvetica, sans-serif; + font-size:95%; + height:15px; + line-height:15px; + padding:0px 2px; + color:white; + white-space:nowrap; + overflow:hidden; + cursor:pointer; + vertical-align:middle; +} +.openerp .dhx_cal_event_clear:hover, .openerp .dhx_cal_event_line:hover{ + background-color:#ccc; +} + +.openerp .dhx_in_move{background-color:#FFFF80;} + +.openerp div .dhx_cal_editor{ + background-color:white; + border:1px solid #B7A543; + width:100%; + /*min-height:40px;*/ + height:100%; + z-index:999; + position:absolute; + overflow:hidden; +} + +.openerp textarea .dhx_cal_editor{ + background-color:white; + width:100%; +/*min-height:40px;*/ + height:100%; + border:0 solid black; + margin:none; + padding:none; + overflow:auto; +} + +.openerp div .dhx_menu_head{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/controls.gif);background-position:0 -43px;width:10px;height:10px;margin-left:5px;margin-top:1px;border:none;cursor:default;} + +.openerp div .dhx_menu_icon{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/controls.gif);width:20px;height:20px;margin-left:-5px;margin-top:0;border:none;cursor:pointer;} +.openerp div .icon_details{background-position:0 0;} + +.openerp div .icon_edit{background-position:-22px 0;} +.openerp div .icon_save{background-position:-84px -1px;} +.openerp div .icon_cancel{background-position:-62px 0;}div.icon_delete{background-position:-42px 0;} +.openerp div .dhx_now_time{position:absolute;width:100%;border-bottom:2px dotted red;z-index:1;} +.openerp div .dhx_time_block{position:absolute;width:100%;background:silver;opacity:.4;filter:alpha(opacity=40);z-index:1;} + +.openerp .dhx_unselectable, .dhx_unselectable div{-webkit-user-select:none;-moz-user-select:none;-moz-user-select:-moz-none;} + +.openerp .dhx_cal_light{background-color:#FFE763;border-radius:5px; + font-size:8pt;border:1px solid #B7A64B;color:#887A2E;position:absolute;z-index:10001;width:580px;height:300px;box-shadow:5px 5px 5px #888;} + +.openerp .dhx_cal_light_wide{width:650px;} +.openerp .dhx_mark{position:relative;top:3px;background-image:url('/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/controls.gif');background-position:0 -43px;padding-left:10px;} + +.openerp .dhx_ie6 .dhx_mark{background-position:6px -41px;} + +.openerp .dhx_cal_light select{font-size:8pt;color:#887A2E;padding:2px;margin:0;}.openerp .dhx_cal_ltitle{padding:2px 0 2px 5px;overflow:hidden;white-space:nowrap;} + +.openerp .dhx_cal_ltitle span{white-space:nowrap;} + +.openerp .dhx_cal_lsection{background-color:#DBCF8C;color:#FFF4B5;font-weight:bold;padding:5px 0 3px 10px;}.openerp .dhx_section_time{background-color:#DBCF8C;} + +.openerp .dhx_cal_lsection .dhx_fullday{float:right;margin-right:5px;color:#887A2E;font-size:12px;font-weight:normal;line-height:20px;vertical-align:top;cursor:pointer;} + +.openerp .dhx_cal_lsection{font-size:18px;} + +.openerp .dhx_cal_ltext{padding:2px 0 2px 10px;overflow:hidden;} +.openerp .dhx_cal_ltext textarea{background-color:#FFF4B5;overflow:auto;border:none;color:#887A2E;height:100%;width:100%;outline:none!important;} +.openerp .dhx_time{font-weight:bold;} + +.openerp .dhx_cal_light .openerp .dhx_title{padding-left:10px;} + +.openerp .dhx_cal_larea{border:1px solid #DCC43E;background-color:#FFF4B5;overflow:hidden;margin-left:3px;width:572px;height:1px;} +.openerp .dhx_btn_set{padding:5px 10px 0 10px;float:left;}.openerp .dhx_btn_set div{float:left;height:21px;line-height:21px;vertical-align:middle;cursor:pointer;} +.openerp .dhx_save_btn{background-image:url('/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/controls.gif');background-position:-84px 0;width:21px;} +.openerp .dhx_cancel_btn{background-image:url('/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/controls.gif');background-position:-63px 0;width:20px;} +.openerp .dhx_delete_btn{background-image:url('/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/controls.gif');background-position:-42px 0;width:20px;} +.openerp .dhx_cal_cover{width:100%;height:100%;position:absolute;z-index:10000;top:0;left:0;background-color:black;opacity:.1;filter:alpha(opacity=10);} +.openerp .dhx_custom_button{padding:0 3px 0 3px;color:#887A2E;font-size:8pt;background-color:#FFE763;font-weight:normal;margin-right:5px;margin-top:0;cursor:pointer;} +.openerp .dhx_custom_button div{cursor:pointer;float:left;height:21px;line-height:21px;vertical-align:middle;} + +.openerp .dhx_cal_light_wide .dhx_cal_larea{border-top-width:0;} +.openerp .dhx_cal_light_wide .dhx_cal_lsection{border:0;float:left;text-align:right;width:100px;height:20px;font-size:16px;padding:5px 0 0 10px;} +.openerp .dhx_cal_light_wide .dhx_wrap_section{border-top:1px solid #DBCF8C;position:relative;background-color:#DBCF8C;overflow:hidden;} +.openerp .dhx_cal_light_wide .dhx_section_time{padding-top:2px!important;height:20px!important;} +.openerp .dhx_section_time{text-align:center;} +.openerp .dhx_cal_light_wide .dhx_cal_larea{width:730px;} +.openerp .dhx_cal_light_wide{width:738px;} +.openerp .dhx_cal_light_wide .dhx_section_time{background:transparent;} +.openerp .dhx_cal_light_wide .dhx_cal_checkbox label{padding-left:0;} +.openerp .dhx_cal_wide_checkbox input{margin-top:8px;margin-left:14px;} +.openerp .dhx_cal_light input{;font-size:8pt;color:#887A2E;} + +.openerp .dhx_cal_light_wide .dhx_cal_lsection .dhx_fullday{float:none;margin-right:0;color:#FFF4B5;font-weight:bold;font-size:16px;cursor:pointer;} + +.openerp .dhx_custom_button{float:right;height:21px;width:90px;-webkit-border-radius:4px;-moz-border-radius:4px;-ms-border-radius:4px;-o-border-radius:4px;border-radius:4px;} +.openerp .dhx_cal_light_wide .dhx_custom_button{position:absolute;top:0;right:0;margin-top:2px;} +.openerp .dhx_cal_light_wide .dhx_repeat_right{margin-right:55px;} +.openerp .dhx_cal_light_wide .dhx_repeat_divider{border-color:#FFE763;} + +.openerp .dhx_scale_bar_header{position:absolute;border-bottom:1px dotted #8894A3;width:100%;} + +.openerp .dhx_expand_icon{position:absolute;top:0;right:0;background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/colapce-expand-icon.gif);width:18px;height:18px;cursor:pointer;background-position:0 18px;z-index:16;} +.openerp .dhx_agenda_area{width:100%;height:100%;overflow-y:auto;background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/databg.png);} +.openerp .dhx_agenda_line{height:21px;clear:both;overflow:hidden;} +.openerp .dhx_agenda_line div{float:left;width:188px;border-right:1px dotted #8894A3;text-align:center;line-height:21px;overflow:hidden;} +.openerp .dhx_agenda_area .dhx_agenda_line div{border-right:0 dotted #8894A3;} +.openerp .dhx_v_border{position:absolute;left:186px;top:0;border-right:1px dotted #8894A3;width:1px;height:100%;} +.openerp .dhx_agenda_line .dhx_event_icon{width:20px;border-width:0;background:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/icon.png) no-repeat;background-position:5px 4px;cursor:pointer;} +.openerp .dhx_agenda_line span{padding-left:5px;line-height:21px;} + + +.openerp .dhx_year_week{ + position:relative; + font-weight:bold; + font-size:1em; + color:#aaa; + vertical-align:middle; + border-top:1px solid #ccc; + border-bottom:1px solid #ccc; +} + +.openerp .dhx_scale_bar_last{border-right:1px dotted #586A7E;} + +.openerp .dhx_year_month{ + height:18px; + line-height:18px; + padding-top:2px; + text-align:center; + vertical-align:middle; + text-transform:uppercase; + font-weight:bold; + font-size:0.9em; + text-shadow: 0 1px 0 white; + border:0px; + color:#444; +} +/*.openerp .dhx_mini_calendar .openerp .dhx_year_month{ + padding-top:0px; +} */ + +.openerp .dhx_mini_calendar + .dhx_year_body { + border:0px; +} + +.openerp .dhx_year_body .dhx_before .dhx_month_head,.openerp .dhx_year_body .dhx_after .dhx_month_head, .openerp .dhx_year_body .dhx_before .dhx_month_head a,.openerp .dhx_year_body .dhx_after .dhx_month_head a {color:#bbb;} + +.openerp .dhx_year_body .dhx_month_body{height:0;overflow:hidden;} + +.openerp .dhx_year_body .dhx_before .dhx_month_head, .dhx_year_body .dhx_after .dhx_month_head{cursor:default;} + +.openerp .dhx_tooltip{border:1px solid #BBB;background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/databg.png);position:absolute;z-index:9998;width:300px;height:auto; +font-size:8pt;overflow:hidden;} +.openerp .dhx_tooltip_line{line-height:20px;height:20px;overflow:hidden;} +.openerp .dhx_tooltip_line .dhx_event_icon{width:20px;height:20px;padding-right:10px;float:left;border-width:0;position:relative;background:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/icon.png) no-repeat;background-position:5px 4px;cursor:pointer;} +.openerp .dhx_tooltip_date{float:left;width:auto;padding-left:5px;text-align:center;} + +.openerp .dhx_text_disabled{color:#887A2E;font-size:8pt;} + +.openerp .dhx_cal_navline div .dhx_minical_icon{width:18px;height:18px;left:190px;top:1px;cursor:pointer;background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/calendar.gif);} + +.openerp .dhx_matrix_scell{height:100%;} +.openerp .dhx_matrix_cell, +.openerp .dhx_matrix_scell{overflow:hidden;text-align:center;vertical-align:middle;border-bottom:1px dotted #8894A3;border-right:1px dotted #8894A3;} +.openerp .dhx_matrix_cell{background-color:white;} +.openerp .dhx_matrix_line{overflow:hidden;} +.openerp .dhx_matrix_cell div, .openerp .dhx_matrix_scell div{overflow:hidden;text-align:center;height:auto;} +.openerp .dhx_cal_lsection .dhx_readonly{font-size:9pt;font-size:8pt;padding:2px;color:#887A2E;} + +.openerp .dhx_matrix_scell.folder,.openerp .dhx_data_table.folder .dhx_matrix_cell{background-color:#969394;cursor:pointer;} +.openerp .dhx_matrix_scell .dhx_scell_level0{padding-left:5px;} +.openerp .dhx_matrix_scell .dhx_scell_level1{padding-left:20px;} +.openerp .dhx_matrix_scell .dhx_scell_level2{padding-left:35px;} +.openerp .dhx_matrix_scell .dhx_scell_level3{padding-left:50px;} +.openerp .dhx_matrix_scell .dhx_scell_level4{padding-left:65px;} +.openerp .dhx_matrix_scell.folder{font-weight:bold;text-align:left;} +.openerp .dhx_matrix_scell.folder .dhx_scell_expand{float:left;width:10px;padding-right:3px;} +.openerp .dhx_matrix_scell.folder .dhx_scell_name{float:left;width:auto;} +.openerp .dhx_matrix_scell.item .dhx_scell_name{padding-left:15px;text-align:left;} + +.openerp .dhx_data_table.folder .dhx_matrix_cell{border-right:0;} +.openerp .dhx_section_timeline{overflow:hidden;padding:4px 0 2px 10px;} +.openerp .dhx_section_timeline select{width:552px;} +.openerp .dhx_map_area{width:100%;height:100%;overflow-y:auto;overflow-x:hidden;background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/databg.png);} +.openerp .dhx_map_line .dhx_event_icon{width:20px;border-width:0;background:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/icon.png) no-repeat;background-position:5px 4px;cursor:pointer;} +.openerp .dhx_map_line{height:21px;clear:both;overflow:hidden;} +.openerp .dhx_map{position:absolute;} +.openerp .dhx_map_line div{float:left;border-right:1px dotted #8894A3;text-align:center;line-height:21px;overflow:hidden;} +.openerp .dhx_map_line .headline_description{float:left;border-right:1px dotted #8894A3;text-align:center;line-height:21px;overflow:hidden;} +.openerp .dhx_map_line .dhx_map_description{float:left;border-right:0 dotted #8894A3;text-align:center;line-height:21px;overflow:hidden;} + +.openerp .dhx_map_line .line_description{float:left;border-right:1px dotted #8894A3;text-align:left;padding-left:5px;line-height:21px;overflow:hidden;} +.openerp .dhx_map_line.highlight{background-color:#C4C5CC;} +.openerp .dhx_map_area .dhx_map_line div{border-right:0 dotted #8894A3;}.dhtmlXTooltip.tooltip{-moz-box-shadow:3px 3px 3px #888;-webkit-box-shadow:3px 3px 3px #888;-o-box-shadow:3px 3px 3px #888;box-shadow:3px 3px 3px #888;filter:progid:DXImageTransform.Microsoft.Shadow(color='#888888',Direction=135,Strength=5);background-color:white;border-left:1px dotted #887A2E;border-top:1px dotted #887A2E;color:#887A2E;cursor:default;padding:10px;position:absolute;z-index:500;} +.openerp .dhx_cal_checkbox label{padding-left:5px;} +.openerp .dhx_cal_light .radio{padding:2px 0 2px 10px;} +.openerp .dhx_cal_light .radio input,.openerp .dhx_cal_light .radio label{line-height:15px;} +.openerp .dhx_cal_light .radio input{vertical-align:middle;margin:0;padding:0;} +.openerp .dhx_cal_light .radio label{vertical-align:middle;padding-right:10px;} +.openerp .dhx_cal_light .combo{padding:4px;} +.openerp .dhx_wa_column{float:left;} +.openerp .dhx_wa_column_last .dhx_wa_day_cont{border-left:1px dotted #8894A3;} + +.openerp .dhx_wa_scale_bar{padding-left:10px;font-size:11px;border-top:1px dotted #8894A3;border-bottom:1px dotted #8894A3;} +.openerp .dhx_wa_day_data{background-color:#FCFEFC;overflow-y:auto;} +.openerp .dhx_wa_ev_body{border-bottom:1px dotted #789;font-size:12px;padding:5px 0 5px 7px;} + +.openerp .dhx_wa_dnd{position:absolute;padding-right:7px;color:#887AE2!important;background-color:#FFE763!important;border:1px solid #B7A543;} +.openerp .dhx_cal_event_selected{background-color:#9cc1db;color:white;} +.openerp .dhx_second_scale_bar{border-bottom:1px dotted #586A7E;padding-top:2px;} +.openerp div .dhx_form_repeat input.radio{margin:-4px 0 0 -4px!ie;} +.openerp div .dhx_form_repeat input.checkbox{margin:0 0 0 -4px!ie;} + +.openerp .dhx_form_repeat,.openerp .dhx_form_repeat input{padding:0;margin:0;padding-left:5px; +font-size:11px;line-height:24px;} +.openerp .dhx_form_repeat{overflow:hidden;height:0;background-color:#FFF4B5;} +.openerp .dhx_cal_light_wide .dhx_form_repeat{background-color:transparent;} +.openerp .dhx_repeat_center,.openerp .dhx_repeat_left{height:115px;padding:10px 0 10px 10px;float:left;} +.openerp .dhx_repeat_left{width:95px;} +.openerp .dhx_repeat_center{width:335px;margin-top:12px;} +.openerp .dhx_repeat_divider{float:left;height:115px;border-left:1px dotted #DCC43E;width:1px;} +.openerp .dhx_repeat_right{float:right;height:115px;width:160px;padding:10px 3px 10px 10px;margin-top:7px;} +.openerp input .dhx_repeat_text{height:16px;width:27px;margin:0 4px 0 4px;line-height:18px;padding:0 0 0 2px;} +.openerp .dhx_form_repeat select{height:20px;width:87px;padding:0 0 0 2px;margin:0 4px 0 4px;} +.openerp input .dhx_repeat_date{height:18px;width:80px;padding:0 0 0 2px;margin:0 4px 0 4px;background-repeat:no-repeat;background-position:64px 0;border:1px #7f9db9 solid;line-height:18px;}input.openerp .dhx_repeat_radio{margin-right:4px;} +.openerp input .dhx_repeat_checkbox{margin:4px 4px 0 0;} +.openerp .dhx_repeat_days td{padding-right:5px;} +.openerp .dhx_repeat_days label{font-size:10px;} +.openerp .dhx_custom_button{width:90px;-webkit-border-radius:4px;-moz-border-radius:4px;-ms-border-radius:4px;-o-border-radius:4px;border-radius:4px;} +.openerp .dhx_custom_button_recurring{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/but_repeat.gif);background-position:-5px 20px;width:20px;margin-right:10px;} +.openerp .dhx_cal_light_rec{width:640px;} +.openerp .dhx_cal_light_rec .dhx_cal_larea{width:632px;} +.openerp .dhx_cal_light_rec .dhx_cal_light_wide{width:816px;} +.openerp .dhx_cal_light_rec .dhx_cal_light_wide .dhx_cal_larea{width:808px;} + +.openerp .dhx_cal_navline{background-color:none;height:23px!important;} + + + + +.openerp .dhx_scale_bar{/*background-image:url(imgs/top-separator.gif);background-position:0 0;background-repeat:no-repeat; */background-color:transparent;padding-top:3px;border-left:0;} + +.openerp .dhx_multi_day{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/multi-days-bg.png);background-repeat:repeat;} + +.openerp .dhx_month_head{background-color:#F4F4F4;} + +.openerp .dhx_after .dhx_month_head,.openerp .dhx_before .dhx_month_head{background-color:#F4F4F4;} + +.openerp .dhx_after .dhx_month_body,.openerp .dhx_before .dhx_month_body{background-color:#EFEDE2;} + +.openerp .dhx_cal_event div{border:1px solid #FFBD51;background-color:#FFE4AB;color:#000;} + +.openerp .dhx_in_move{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/move.png);} + +.openerp .dhx_cal_event .dhx_title{background-color:#FFE4AB;} + +.openerp .dhx_cal_light{-moz-box-shadow:5px 5px 5px #888;-khtml-box-shadow:5px 5px 5px #888;background-color:#EBEBEB;border:2px solid #A4BED4;color:#000;} +.openerp .dhx_cal_larea{border:1px solid #A4BED4;border-width:0 1px 1px;background-color:#FFF;} + +.openerp .dhx_cal_lsection{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/lightbox.png);font-size:14px;padding:5px 0 5px 10px;color:#000;} + +.openerp .dhx_cal_light_wide .dhx_cal_lsection{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/multi-days-bg.png);}.openerp .dhx_cal_ltext textarea{background-color:#fff;color:#000;} + +.openerp .dhx_cal_light select,.openerp .dhx_cal_light input{color:#000;} +.openerp .dhx_save_btn{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/controlls5.png);} + +.openerp .dhx_cancel_btn{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/controlls5.png);} +.openerp .dhx_delete_btn{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/controlls5.png);} + +.openerp .div .dhx_menu_head{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/controlls5.png);border:1px solid #FFE4AB;} + +.openerp .div .dhx_menu_icon{background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/controlls5.png);border:medium none;} + +.openerp .dhx_section_time{height:20px!important;padding:7px 0!important;text-align:center;background:white;} + +.openerp .div .dhx_cal_editor{background-color:#FFE4AB;} + +.openerp .dhx_month_body{ + border-left:1px solid #E9E9E9; + border-bottom:1px solid #E9E9E9; +} + +.openerp .dhx_scale_bar_last{border-right:none;} + +.openerp .dhx_month_head .dhx_year_event{background-color:#ddd;} + +.openerp .dhx_year_body .dhx_before .dhx_month_head,.openerp .dhx_year_body .dhx_after .dhx_month_head, .dhx_year_body .dhx_before .dhx_month_head a,.openerp .dhx_year_body .dhx_after .dhx_month_head a{color:#EFEDE2 ;} + +.openerp .dhx_cal_lsection .dhx_readonly{color:#000;} +.openerp .dhx_tooltip{-moz-box-shadow:2px 2px 2px #888;-khtml-box-shadow:2px 2px 2px #888;} +.openerp .dhx_custom_button{margin-top:-2px;} +.openerp .dhx_cal_lsection .dhx_fullday{color:#000;} +.openerp .dhx_cal_lsection .dhx_cal_checkbox{height:16px;line-height:18px;} +.openerp .dhx_cal_light_wide +.openerp .dhx_cal_lsection .dhx_cal_checkbox{height:20px;} +.openerp .dhx_cal_checkbox label{vertical-align:top;} +.openerp .dhx_cal_light_wide .dhx_cal_lsection{color:black;} +.openerp .dhx_cal_light_wide .dhx_wrap_section{border-top:1px solid #A4BED4;background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/multi-days-bg.png);} +.openerp .dhx_cal_light_wide .dhx_cal_ltext{border-left:1px solid #A4BED4;} +.openerp .dhx_cal_light_wide .dhx_cal_ltext{background-color:white;} +.openerp .dhx_custom_button{background:white;color:black;} +.openerp .dhx_form_repeat{background:white;} +.openerp .dhx_repeat_divider{border-left:1px solid #A4BED4;} +.openerp .dhx_cal_header .dhx_second_cal_header{background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/second-top-days-bg.png");padding-right:20px;} +.openerp .dhx_scale_bar{padding-top:4px;} + +.openerp .dhx_second_scale_bar{border-bottom:0;padding-top:4px;} +.openerp .dhx_cal_light_wide .dhx_cal_lsection .dhx_fullday,.openerp .dhx_cal_lsection .dhx_fullday{color:#000;font-size:14px;} +.openerp .dhx_cal_light_wide .dhx_cal_lsection{font-size:14px;padding-right:10px;} + + +.openerp .dhx_scale_bar { +/*background-color:#bac6cf; + border-left:1px dotted #7e7e7e; */ + } + + +.openerp .dhx_cal_drag { + background-color:#ff8d8d; + border:1px solid #a73636; +} + + + +.openerp .dhx_in_move{ + background-color:#f7ffb1; +} + + +.openerp .dhx_cal_event div .dhx_menu_icon { + border: medium none; +} + +.openerp .dhx_after .dhx_month_body, .openerp .dhx_before .dhx_month_body { + background-color:#e9e9e9; +} + + +.openerp .dhx_cal_light { + background-color:#ff8d8d; + color: #000102; + border:1px solid #b7a543; +} + +.openerp .dhx_cal_light select { + color: #000102; +} + +.openerp .dhx_cal_lsection { + background-color:#dbcf8c; + color: #fff4b5; +} + +.openerp .dhx_cal_larea { + background-color:#fff4b5; + border:1px solid #b7a543; +} + + +.openerp .dhx_agenda_area{ + background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/databg.png"); +} + +.openerp .dhx_agenda_line div { + border-right:1px dotted #7e7e7e; +} + +.openerp .dhx_agenda_area .dhx_agenda_line div { + border-right:0px dotted #7e7e7e; +} + + +.openerp .dhx_scale_bar_last { + border-right: none; +} + +.openerp .dhx_year_body .dhx_before .dhx_month_head, .openerp .dhx_year_body .dhx_after .dhx_month_head, .openerp .dhx_year_body .dhx_before .dhx_month_head a, .openerp .dhx_year_body .dhx_after .dhx_month_head a { + color:#bbb; +} +.openerp .dhx_year_body .dhx_before .dhx_month_head:hover, .openerp .dhx_year_body .dhx_after .dhx_month_head:hover, .openerp .dhx_year_body .dhx_before .dhx_month_head a:hover, .openerp .dhx_year_body .dhx_after .dhx_month_head a:hover { + color:white; + text-shadow:none; +} + +.openerp .dhx_tooltip { + background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/databg.png"); +} + +.openerp .dhx_cal_event div .dhx_menu_head { + border:none; +} + +div.openerp .dhx_menu_head{ + border:1px solid #ff8d8d; +} + +.openerp .dhx_after .dhx_month_head, .openerp .dhx_before .dhx_month_head { + color:#8c9299; +} + +.openerp .dhx_cal_data .dhx_agenda_line { + color:#000102; +} + +.openerp .dhx_cal_header .dhx_agenda_line { + color: #020202; +} + +.openerp .dhx_tooltip_line { + color:#000102; +} + +.openerp .dhx_cal_light select { + background-color: #ffffff; +} + +.openerp .dhx_custom_button { + color: #000102; + background-color: #bac6cf; +} + +div.openerp .dhx_form_repeat { + background-color: #ffffff; +} + +div.openerp .dhx_repeat_divider { + border-left:1px dotted #dbcf8c; +} + + +.openerp .dhx_v_border { + border-right:1px dotted #8c9299; +} + + +.openerp .dhx_scale_bar_last { + border-right: none; +} + +.openerp .dhx_tooltip { + background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/databg.png"); +} + +.openerp .dhx_text_disabled { + color:#000102; +} + +.openerp .dhx_mini_calendar .dhx_calendar_click { + background-color:#bac6cf; +} + +.openerp .dhx_matrix_cell, .openerp .dhx_matrix_scell { + border-bottom:1px dotted #757575; + border-right:1px dotted #757575; +} + +.openerp .dhx_matrix_cell { + background-color: #ffffff; +} + + +/*=================================================================*/ +/* pro */ +/*=================================================================*/ + + +.openerp .dhx_cal_navline{ + background-color:none; +} + +.openerp .dhx_in_move{ + background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/move.png"); +} +.openerp .dhx_cal_light{ + background-color:#bac6cf; + border:2px solid #757575; + color:#000102; +} + +.openerp .dhx_cal_larea{ + border:1px solid #757575; + background-color:#FFFFFF; +} + +.openerp .dhx_cal_lsection{ + background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/lightbox.png"); + color:#000102; +} + +.openerp .dhx_cal_ltext{ + background-color:#ffffff; +} + +.openerp .dhx_cal_ltext textarea{ + color:#000102; + background-color:#ffffff; +} + +.openerp .dhx_form_repeat input, .openerp .dhx_form_repeat select{ + background-color:white; + color:black; +} + +.openerp .dhx_cal_light select{ + color:#000102; + background-color:#ffffff; +} + +.openerp .dhx_section_time{ + background-image:none; + background-color:#ffffff; +} + +div.openerp .dhx_cal_editor{ + background-color:#ff8d8d; +} + +div.openerp .dhx_cal_editor textarea { + color: #000102; +} + + +/* .openerp .dhx_year_week{ + background-image:url("./imgs/top-days-bg.png"); +} + +.openerp .dhx_month_head.openerp .dhx_year_event{ + background-color:#ff8d8d; +} */ + +.openerp .dhx_cal_lsection .dhx_readonly{ + color:#000102; +} + +.openerp .dhx_after .dhx_month_head, .openerp .dhx_before .dhx_month_head { + background-color:#F4F4F4; +} + +/* Tree view */ +.openerp .dhx_matrix_scell.folder, .dhx_data_table.folder .dhx_matrix_cell{ + background-color: #7e7e7e; +} +.dhtmlXTooltip.tooltip{ + border-left:1px dotted #7e7e7e; + border-top:1px dotted #7e7e7e; +} +.openerp .dhx_map_area{ + background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/databg_now.png"); +} +.openerp .dhx_map_line div{ + border-right:1px dotted #7e7e7e; +} +.openerp .dhx_map_line .headline_description{ + border-right:1px dotted #7e7e7e; +} +.openerp .dhx_map_line .dhx_map_description{ + border-right: 0px dotted #7e7e7e; +} +.openerp .dhx_map_line .line_description{ + border-right:1px dotted #7e7e7e; +} +.openerp .dhx_map_line.highlight{ + background-color: #bac6cf; +} +.openerp .dhx_map_area .dhx_map_line div{ + border-right:0px dotted #7e7e7e; +} +/* Map view */ +.openerp .dhx_map_area{ + background-image:url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/databg.png"); +} +/* Map view end */ + + +/* Agenda week start */ +.openerp .dhx_wa_column_last .dhx_wa_day_cont{ + border-left: 1px dotted #757575; +} +.openerp .dhx_wa_scale_bar { + border-top: 1px dotted #757575; + border-bottom: 1px dotted #757575; + color: #020202; +} +.openerp .dhx_wa_day_data { + background-color: #ffffff; +} +.openerp .dhx_wa_ev_body { + border-bottom: 1px dotted #757575; + color: #000102; +} +.openerp .dhx_wa_dnd { + color: #525253 !important; + background-color: #f7ffb1 !important; + border: 1px solid #757575; +} +.openerp .dhx_cal_event_selected{ + background-color: #757575; + color: ffffff; +} +/* Agenda week end */ +.openerp .dhx_scale_bar_header { + border-bottom: 1px dotted #8894A3; +} + +/*All*/ +/* increase width of lightbox */ +.openerp .dhx_cal_light_wide .dhx_cal_lsection{ + background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/multi-days-bg.png); +} +/*2.3*/ +.openerp .dhx_cal_lsection .dhx_fullday{ + color:#000000; +} +.openerp .dhx_cal_light_wide .dhx_cal_lsection{ + color:#000000; +} +.openerp .dhx_cal_light_wide .dhx_wrap_section{ + border-top:1px solid #757575; + background-image:url(/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/multi-days-bg.png); +} +.openerp .dhx_cal_light_wide .dhx_cal_ltext{ + border-left:1px solid #757575; +} +.openerp .dhx_cal_light_wide .dhx_cal_ltext { + background-color:#ffffff; +} +.openerp .dhx_custom_button{ + background:#ffffff; + color:#000000; +} +/* timeline second scale start */ +.openerp .dhx_cal_header.openerp .dhx_second_cal_header { + background-image: url("/web_calendar/static/lib/dhtmlxScheduler/codebase/imgs/second-top-days-bg.png"); +} +/* timeline second scale end */ +.openerp .dhx_cal_light_wide .dhx_cal_lsection .dhx_fullday, .openerp .dhx_cal_lsection .dhx_fullday{ + color:#000000; + font-size: 14px; +} +.openerp .dhx_cal_light_wide .dhx_cal_lsection { + font-size: 14px; +} +.dhtmlxLayoutPolyContainer_dhx_skyblue .dhx_cal_container { + background-color: #d0e5ff; +} +.openerp div .dhx_cal_editor{ + border:1px solid #B7A543; +} +.openerp .dhx_cal_light_wide .dhx_repeat_divider { + border-color: #757575; +} +.openerp .dhx_cal_event .dhx_header, .openerp .dhx_cal_event .dhx_header { + display:none; +} diff --git a/addons/web_calendar/static/src/img/cal_left.png b/addons/web_calendar/static/src/img/cal_left.png new file mode 100644 index 00000000000..b9b66aaeb63 Binary files /dev/null and b/addons/web_calendar/static/src/img/cal_left.png differ diff --git a/addons/web_calendar/static/src/img/cal_right.png b/addons/web_calendar/static/src/img/cal_right.png new file mode 100644 index 00000000000..3c48e521be4 Binary files /dev/null and b/addons/web_calendar/static/src/img/cal_right.png differ diff --git a/addons/web_calendar/static/src/img/minical_left.png b/addons/web_calendar/static/src/img/minical_left.png new file mode 100644 index 00000000000..b17118fcc67 Binary files /dev/null and b/addons/web_calendar/static/src/img/minical_left.png differ diff --git a/addons/web_calendar/static/src/img/minical_right.png b/addons/web_calendar/static/src/img/minical_right.png new file mode 100644 index 00000000000..ab660de81f0 Binary files /dev/null and b/addons/web_calendar/static/src/img/minical_right.png differ diff --git a/addons/web_calendar/static/src/js/calendar.js b/addons/web_calendar/static/src/js/calendar.js index 0c814811766..93e798ba804 100644 --- a/addons/web_calendar/static/src/js/calendar.js +++ b/addons/web_calendar/static/src/js/calendar.js @@ -112,6 +112,9 @@ openerp.web_calendar.CalendarView = openerp.web.View.extend({ scheduler.init('openerp_scheduler', null, this.mode || 'month'); + // Remove hard coded style attributes from dhtmlx scheduler + this.$element.find(".dhx_cal_navline div").removeAttr('style'); + scheduler.detachAllEvents(); scheduler.attachEvent('onEventAdded', this.do_create_event); scheduler.attachEvent('onEventDeleted', this.do_delete_event); 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/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 6d0a9e1c747..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,13 +192,22 @@ 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); } if (am.inner_viewmanager) { am.inner_viewmanager.on_mode_switch.add(function(mode) { + var new_views = []; + _.each(action_orig.views, function(view) { + new_views[view[1] === mode ? 'unshift' : 'push'](view); + }); + if (!new_views.length || new_views[0][1] !== mode) { + new_views.unshift([false, mode]); + } + action_orig.views = new_views; + action_orig.res_id = am.inner_viewmanager.dataset.ids[am.inner_viewmanager.dataset.index]; self.do_action(action_orig); }); } @@ -512,10 +452,13 @@ openerp.web_dashboard.ApplicationTiles = openerp.web.View.extend({ run_configuration_wizards: function () { var self = this; new openerp.web.DataSet(this, 'res.config').call('start', [[]], function (action) { - $.unblockUI(); self.widget_parent.widget_parent.do_action(action, function () { openerp.webclient.do_reload(); }); + self.$element.empty(); + self.do_display_root_menu().then(function () { + $.unblockUI(); + }); }); } }); 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/pt.po b/addons/web_mobile/po/pt.po new file mode 100644 index 00000000000..8054ab4ceac --- /dev/null +++ b/addons/web_mobile/po/pt.po @@ -0,0 +1,66 @@ +# Portuguese 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-21 22:23+0000\n" +"Last-Translator: Daniel Reis \n" +"Language-Team: Portuguese \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-22 05:13+0000\n" +"X-Generator: Launchpad (build 14299)\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 "Base de dados:" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Login:" +msgstr "Utilizador (login):" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Password:" +msgstr "Senha:" + +#: 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 "Nome de utilizador ou senha incorrectos" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Favourite" +msgstr "Favorito" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Preference" +msgstr "Preferência" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Applications" +msgstr "Aplicações" + +#: addons/web_mobile/static/src/xml/web_mobile.xml:0 +msgid "Options" +msgstr "Opções" + +#: 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..ebb2267714c 100644 --- a/addons/web_process/static/src/css/process.css +++ b/addons/web_process/static/src/css/process.css @@ -50,6 +50,16 @@ a.cta-a strong { display: table-cell; } +.oe-process-view { + height: 20px; + padding: 0; + width: 24px; + cursor: pointer; + display: block; + background: url(/web/static/src/img/icons/gtk-help.png) no-repeat bottom; + float: left; +} + .process-help-text { float: left; padding:5px 10px; diff --git a/addons/web_process/static/src/js/process.js b/addons/web_process/static/src/js/process.js index f7497773645..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; @@ -303,7 +305,7 @@ openerp.web_process = function (openerp) { pager: false } }); - }, + } }); }; // vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: 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 @@