diff options
| author | Antony Lesuisse <al@openerp.com> | 2012-07-23 19:34:50 +0200 |
|---|---|---|
| committer | Antony Lesuisse <al@openerp.com> | 2012-07-23 19:34:50 +0200 |
| commit | 07fb6d88b9c0ca87545735c83afc8f271db090dd (patch) | |
| tree | 62f48db8d70ddacffe868f05cb19590776b2203a /addons/web | |
| parent | ac5dc58367d9bed5a576baaa7b803a67b5d00d07 (diff) | |
| parent | 8df25dc6830c1878931b7848dbf8a9be6a2d0515 (diff) | |
[MERGE] trunk
bzr revid: al@openerp.com-20120723173450-2yxayvyoiiiw9tcw
Diffstat (limited to 'addons/web')
21 files changed, 2561 insertions, 1001 deletions
diff --git a/addons/web/__openerp__.py b/addons/web/__openerp__.py index 6863779e41f..9e8e258dedc 100644 --- a/addons/web/__openerp__.py +++ b/addons/web/__openerp__.py @@ -1,10 +1,10 @@ { - "name" : "web", + "name" : "Web", "category": "Hidden", "description": """ OpenERP Web core module. - This module provides the core of the OpenERP web client. + This module provides the core of the OpenERP Web Client. """, "depends" : [], 'auto_install': True, @@ -33,6 +33,7 @@ "static/lib/underscore/underscore.js", "static/lib/underscore/underscore.string.js", "static/lib/backbone/backbone.js", + "static/lib/cleditor/jquery.cleditor.js", "static/lib/py.js/lib/py.js", "static/src/js/boot.js", "static/src/js/corelib.js", @@ -60,6 +61,7 @@ "static/src/css/base.css", "static/src/css/data_export.css", "static/src/css/data_import.css", + "static/lib/cleditor/jquery.cleditor.css", ], 'qweb' : [ "static/src/xml/*.xml", diff --git a/addons/web/common/http.py b/addons/web/common/http.py index cc76a554693..bb87d719bad 100644 --- a/addons/web/common/http.py +++ b/addons/web/common/http.py @@ -28,6 +28,7 @@ import werkzeug.wsgi from . import nonliterals from . import session from . import openerplib +import urlparse __all__ = ['Root', 'jsonrequest', 'httprequest', 'Controller', 'WebRequest', 'JsonRequest', 'HttpRequest'] @@ -417,6 +418,20 @@ class ControllerType(type): class Controller(object): __metaclass__ = ControllerType +class DisableCacheMiddleware(object): + def __init__(self, app): + self.app = app + def __call__(self, environ, start_response): + def start_wrapped(status, headers): + referer = environ.get('HTTP_REFERER', '') + parsed = urlparse.urlparse(referer) + debug = not urlparse.parse_qs(parsed.query).has_key('debug') + filtered_headers = [(k,v) for k,v in headers if not (k=='Last-Modified' or (debug and k=='Cache-Control'))] + if debug: + filtered_headers.append(('Cache-Control', 'no-cache')) + start_response(status, filtered_headers) + return self.app(environ, start_wrapped) + class Root(object): """Root WSGI application for the OpenERP Web Client. @@ -452,8 +467,8 @@ class Root(object): static_dirs = self._load_addons(openerp_addons_namespace) if options.serve_static: - self.dispatch = werkzeug.wsgi.SharedDataMiddleware( - self.dispatch, static_dirs, cache=False) + app = werkzeug.wsgi.SharedDataMiddleware( self.dispatch, static_dirs) + self.dispatch = DisableCacheMiddleware(app) if options.session_storage: if not os.path.exists(options.session_storage): diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 412ea9abda2..7f9710f8aa6 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -258,8 +258,7 @@ class WebClient(openerpweb.Controller): file_map = dict(files) rx_import = re.compile(r"""@import\s+('|")(?!'|"|/|https?://)""", re.U) - rx_url = re.compile(r"""url\s*\(\s*('|"|)(?!'|"|/|https?://)""", re.U) - + rx_url = re.compile(r"""url\s*\(\s*('|"|)(?!'|"|/|https?://|data:)""", re.U) def reader(f): """read the a css file and absolutify all relative uris""" @@ -1494,10 +1493,6 @@ class Binary(openerpweb.Controller): class Action(openerpweb.Controller): _cp_path = "/web/action" - - action_mapping = { - "ir.actions.act_url": "ir.actions.url", - } # For most actions, the type attribute and the model name are the same, but # there are exceptions. This dict is used to remap action type attributes @@ -1511,6 +1506,17 @@ class Action(openerpweb.Controller): Actions = req.session.model('ir.actions.actions') value = False context = req.session.eval_context(req.context) + + try: + action_id = int(action_id) + except ValueError: + try: + module, xmlid = action_id.split('.', 1) + model, action_id = req.session.model('ir.model.data').get_object_reference(module, xmlid) + assert model.startswith('ir.actions.') + except Exception: + action_id = 0 # force failed read + base_action = Actions.read([action_id], ['type'], context) if base_action: ctx = {} diff --git a/addons/web/i18n/ja.po b/addons/web/i18n/ja.po index 66f1f5d584b..41154a91a72 100644 --- a/addons/web/i18n/ja.po +++ b/addons/web/i18n/ja.po @@ -8,179 +8,183 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" "POT-Creation-Date: 2012-07-02 09:06+0200\n" -"PO-Revision-Date: 2012-03-31 18:44+0000\n" -"Last-Translator: Masaki Yamaya <Unknown>\n" +"PO-Revision-Date: 2012-07-19 01:18+0000\n" +"Last-Translator: Akira Hiyama <Unknown>\n" "Language-Team: Japanese <ja@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-07-03 05:54+0000\n" -"X-Generator: Launchpad (build 15531)\n" +"X-Launchpad-Export-Date: 2012-07-20 04:45+0000\n" +"X-Generator: Launchpad (build 15644)\n" #. openerp-web -#: addons/web/static/src/js/chrome.js:170 -#: addons/web/static/src/js/chrome.js:196 -#: addons/web/static/src/js/chrome.js:364 -#: addons/web/static/src/js/view_form.js:531 -#: addons/web/static/src/js/view_form.js:1665 -#: addons/web/static/src/xml/base.xml:1641 +#: addons/web/static/src/js/chrome.js:176 +#: addons/web/static/src/js/chrome.js:202 +#: addons/web/static/src/js/chrome.js:380 +#: addons/web/static/src/js/view_form.js:457 +#: addons/web/static/src/js/view_form.js:1292 +#: addons/web/static/src/xml/base.xml:1701 msgid "Ok" -msgstr "正常" +msgstr "OK" #. openerp-web -#: addons/web/static/src/js/chrome.js:178 +#: addons/web/static/src/js/chrome.js:184 msgid "Send OpenERP Enterprise Report" msgstr "OpenERPエンタープライズレポートを送る" #. openerp-web -#: addons/web/static/src/js/chrome.js:192 +#: addons/web/static/src/js/chrome.js:198 msgid "Dont send" msgstr "送らない" #. openerp-web -#: addons/web/static/src/js/chrome.js:212 -#: addons/web/static/src/js/chrome.js:914 +#: addons/web/static/src/js/chrome.js:1119 msgid "Client Error" msgstr "クライアントのエラー" #. openerp-web -#: addons/web/static/src/js/chrome.js:253 +#: addons/web/static/src/js/chrome.js:260 #, python-format msgid "Loading (%d)" msgstr "ロード中 (%d)" #. openerp-web -#: addons/web/static/src/js/chrome.js:276 +#: addons/web/static/src/js/chrome.js:292 msgid "Invalid database name" msgstr "無効なデータベース名" #. openerp-web -#: addons/web/static/src/js/chrome.js:402 +#: addons/web/static/src/js/chrome.js:455 msgid "Backed" msgstr "バックアップされました" #. openerp-web -#: addons/web/static/src/js/chrome.js:402 +#: addons/web/static/src/js/chrome.js:456 msgid "Database backed up successfully" msgstr "データベースは正常にバックアップされました" #. openerp-web -#: addons/web/static/src/js/chrome.js:442 +#: addons/web/static/src/js/chrome.js:499 msgid "Restored" msgstr "リストアされました" #. openerp-web -#: addons/web/static/src/js/chrome.js:442 +#: addons/web/static/src/js/chrome.js:499 msgid "Database restored successfully" msgstr "データベースは正常にリストアされました" #. openerp-web -#: addons/web/static/src/js/chrome.js:735 -#: addons/web/static/src/xml/base.xml:259 -#: addons/web/static/src/xml/base.xml:367 +#: addons/web/static/src/js/chrome.js:783 +#: addons/web/static/src/xml/base.xml:226 +#: addons/web/static/src/xml/base.xml:1735 msgid "Change Password" msgstr "パスワードの変更" #. openerp-web -#: addons/web/static/src/js/chrome.js:809 -#: addons/web/static/src/xml/base.xml:326 +#: addons/web/static/src/js/chrome.js:759 +#: addons/web/static/src/xml/base.xml:356 msgid "Preferences" msgstr "個人設定" #. openerp-web -#: addons/web/static/src/js/chrome.js:812 +#: addons/web/static/src/js/chrome.js:763 msgid "Change password" msgstr "パスワードの変更" #. openerp-web -#: addons/web/static/src/js/chrome.js:813 -#: addons/web/static/src/js/view_editor.js:96 -#: addons/web/static/src/js/view_editor.js:832 -#: addons/web/static/src/js/view_editor.js:960 -#: addons/web/static/src/js/view_form.js:1660 -#: addons/web/static/src/xml/base.xml:1468 -#: addons/web/static/src/xml/base.xml:1478 +#: addons/web/static/src/js/chrome.js:762 +#: addons/web/static/src/js/search.js:241 +#: addons/web/static/src/js/search.js:300 +#: addons/web/static/src/js/view_editor.js:95 +#: addons/web/static/src/js/view_editor.js:836 +#: addons/web/static/src/js/view_editor.js:962 +#: addons/web/static/src/js/view_form.js:1287 +#: addons/web/static/src/xml/base.xml:743 +#: addons/web/static/src/xml/base.xml:1502 +#: addons/web/static/src/xml/base.xml:1512 +#: addons/web/static/src/xml/base.xml:1521 msgid "Cancel" msgstr "キャンセル" #. openerp-web -#: addons/web/static/src/js/chrome.js:814 -#: addons/web/static/src/js/view_editor.js:74 -#: addons/web/static/src/js/views.js:899 addons/web/static/src/xml/base.xml:687 -#: addons/web/static/src/xml/base.xml:1384 -#: addons/web/static/src/xml/base.xml:1472 +#: addons/web/static/src/js/chrome.js:764 +#: addons/web/static/src/js/view_editor.js:73 +#: addons/web/static/src/js/views.js:967 addons/web/static/src/xml/base.xml:742 +#: addons/web/static/src/xml/base.xml:1506 +#: addons/web/static/src/xml/base.xml:1520 msgid "Save" msgstr "保存" #. openerp-web -#: addons/web/static/src/js/chrome.js:839 +#: addons/web/static/src/js/chrome.js:680 +#: addons/web/static/src/xml/base.xml:359 msgid "About" msgstr "について" #. openerp-web -#: addons/web/static/src/js/chrome.js:856 +#: addons/web/static/src/js/chrome.js:1052 msgid "OpenERP - Unsupported/Community Version" msgstr "OpenERP - サポート無し/コミュニティバージョン" #. openerp-web #: addons/web/static/src/js/coresetup.js:619 msgid "less than a minute ago" -msgstr "" +msgstr "数十秒前" #. openerp-web #: addons/web/static/src/js/coresetup.js:620 msgid "about a minute ago" -msgstr "" +msgstr "1分前" #. openerp-web #: addons/web/static/src/js/coresetup.js:621 #, python-format msgid "%d minutes ago" -msgstr "" +msgstr "%d分前" #. openerp-web #: addons/web/static/src/js/coresetup.js:622 msgid "about an hour ago" -msgstr "" +msgstr "1時間前" #. openerp-web #: addons/web/static/src/js/coresetup.js:623 #, python-format msgid "%d hours ago" -msgstr "" +msgstr "%d時間前" #. openerp-web #: addons/web/static/src/js/coresetup.js:624 msgid "a day ago" -msgstr "" +msgstr "1日前" #. openerp-web #: addons/web/static/src/js/coresetup.js:625 #, python-format msgid "%d days ago" -msgstr "" +msgstr "%d 日前" #. openerp-web #: addons/web/static/src/js/coresetup.js:626 msgid "about a month ago" -msgstr "" +msgstr "1ヶ月前" #. openerp-web #: addons/web/static/src/js/coresetup.js:627 #, python-format msgid "%d months ago" -msgstr "" +msgstr "%dヶ月前" #. openerp-web #: addons/web/static/src/js/coresetup.js:628 msgid "about a year ago" -msgstr "" +msgstr "1年前" #. openerp-web #: addons/web/static/src/js/coresetup.js:629 #, python-format msgid "%d years ago" -msgstr "" +msgstr "%d年前" #. openerp-web #: addons/web/static/src/js/data_export.js:6 @@ -191,10 +195,10 @@ msgstr "データのエクスポート" #: addons/web/static/src/js/data_export.js:19 #: addons/web/static/src/js/data_import.js:70 #: addons/web/static/src/js/view_editor.js:49 -#: addons/web/static/src/js/view_editor.js:399 -#: addons/web/static/src/js/view_form.js:891 -#: addons/web/static/src/js/view_form.js:3901 -#: addons/web/static/src/js/views.js:900 +#: addons/web/static/src/js/view_editor.js:398 +#: addons/web/static/src/js/view_form.js:734 +#: addons/web/static/src/js/view_form.js:3298 +#: addons/web/static/src/js/views.js:968 msgid "Close" msgstr "閉じる" @@ -204,19 +208,19 @@ msgid "Export To File" msgstr "ファイルにエクスポート" #. openerp-web -#: addons/web/static/src/js/data_export.js:125 +#: addons/web/static/src/js/data_export.js:126 msgid "Please enter save field list name" -msgstr "保管するフィールドリスト名を入れてください" +msgstr "保管する項目リスト名を入れてください" #. openerp-web -#: addons/web/static/src/js/data_export.js:360 +#: addons/web/static/src/js/data_export.js:362 msgid "Please select fields to save export list..." -msgstr "エクスポートリストに保管するフィールドを選んでください" +msgstr "エクスポートリストに保存する項目を選んでください" #. openerp-web -#: addons/web/static/src/js/data_export.js:373 +#: addons/web/static/src/js/data_export.js:375 msgid "Please select fields to export..." -msgstr "エクスポートするフィールドを選んでください" +msgstr "エクスポートする項目を選んでください" #. openerp-web #: addons/web/static/src/js/data_import.js:34 @@ -238,93 +242,93 @@ msgstr "外部ID" msgid "" "Destination fields should only be selected once, some fields are selected " "more than once:" -msgstr "" +msgstr "宛先項目の選択は1回のみです。幾つかの項目は複数回選択されます:" #. openerp-web #: addons/web/static/src/js/data_import.js:383 msgid "*Required Fields are not selected :" -msgstr "" +msgstr "* 必須項目が選択されていません:" #. openerp-web -#: addons/web/static/src/js/formats.js:141 +#: addons/web/static/src/js/formats.js:139 #, python-format msgid "(%d records)" -msgstr "" +msgstr "(%d レコード)" #. openerp-web -#: addons/web/static/src/js/formats.js:327 -#: addons/web/static/src/js/view_form.js:4301 +#: addons/web/static/src/js/formats.js:325 +#: addons/web/static/src/js/view_page.js:268 msgid "Download" msgstr "ダウンロード" #. openerp-web -#: addons/web/static/src/js/formats.js:332 +#: addons/web/static/src/js/formats.js:330 #, python-format msgid "Download \"%s\"" -msgstr "ダウンロード \"%s\"" +msgstr "%s のダウンロード" #. openerp-web -#: addons/web/static/src/js/search.js:798 +#: addons/web/static/src/js/search.js:437 msgid "Invalid Search" msgstr "無効な検索" #. openerp-web -#: addons/web/static/src/js/search.js:798 +#: addons/web/static/src/js/search.js:437 msgid "triggered from search view" msgstr "検索ビューによって起動" #. openerp-web -#: addons/web/static/src/js/search.js:839 +#: addons/web/static/src/js/search.js:528 #, python-format msgid "Incorrect value for field %(fieldname)s: [%(value)s] is %(message)s" -msgstr "フィールド %(fieldname)s の正しくない値: [%(value)s] は %(message)s" +msgstr "項目 %(fieldname)s の誤った値: [%(value)s] は %(message)s" #. openerp-web #: addons/web/static/src/js/search.js:948 #, python-format msgid "Filter on: %s" -msgstr "" +msgstr "フィルタ:%s" #. openerp-web #: addons/web/static/src/js/search.js:999 msgid "Filter" -msgstr "" +msgstr "フィルタ" #. openerp-web #: addons/web/static/src/js/search.js:1108 #, python-format msgid "Group by: %s" -msgstr "" +msgstr "グループ:%s" #. openerp-web #: addons/web/static/src/js/search.js:1132 msgid "GroupBy" -msgstr "" +msgstr "グループ化" #. openerp-web #: addons/web/static/src/js/search.js:1267 #, python-format msgid "Search %(field)s for: %(value)s" -msgstr "" +msgstr "%(field)s を検索:%(value)s" #. openerp-web -#: addons/web/static/src/js/search.js:1301 +#: addons/web/static/src/js/search.js:869 msgid "not a valid integer" msgstr "正しいトリガーではありません" #. openerp-web -#: addons/web/static/src/js/search.js:1315 +#: addons/web/static/src/js/search.js:883 msgid "not a valid number" msgstr "正しい数値ではありません" #. openerp-web -#: addons/web/static/src/js/search.js:1398 -#: addons/web/static/src/xml/base.xml:840 +#: addons/web/static/src/js/search.js:962 +#: addons/web/static/src/xml/base.xml:973 msgid "Yes" msgstr "はい" #. openerp-web -#: addons/web/static/src/js/search.js:1399 +#: addons/web/static/src/js/search.js:963 msgid "No" msgstr "いいえ" @@ -332,18 +336,17 @@ msgstr "いいえ" #: addons/web/static/src/js/search.js:1416 #, python-format msgid "Search %(field)s at: %(value)s" -msgstr "" +msgstr "%(field)s の検索:%(value)s" #. openerp-web -#: addons/web/static/src/js/search.js:1622 -#: addons/web/static/src/xml/base.xml:1229 +#: addons/web/static/src/xml/base.xml:1286 msgid "Filters" msgstr "フィルタ" #. openerp-web #: addons/web/static/src/js/search.js:1762 msgid "Advanced" -msgstr "" +msgstr "高度" #. openerp-web #: addons/web/static/src/js/search.js:1853 @@ -352,77 +355,87 @@ msgid "%(field)s %(operator)s \"%(value)s\"" msgstr "" #. openerp-web -#: addons/web/static/src/js/search.js:1888 +#: addons/web/static/src/js/search.js:1341 msgid "contains" -msgstr "次を含む" +msgstr "含む" #. openerp-web -#: addons/web/static/src/js/search.js:1889 +#: addons/web/static/src/js/search.js:1342 msgid "doesn't contain" msgstr "含まない" #. openerp-web -#: addons/web/static/src/js/search.js:1890 -#: addons/web/static/src/js/search.js:1900 -#: addons/web/static/src/js/search.js:1928 -#: addons/web/static/src/js/search.js:1952 +#: addons/web/static/src/js/search.js:1343 +#: addons/web/static/src/js/search.js:1359 +#: addons/web/static/src/js/search.js:1380 +#: addons/web/static/src/js/search.js:1401 +#: addons/web/static/src/js/search.js:1424 msgid "is equal to" msgstr "は次と一致する" #. openerp-web -#: addons/web/static/src/js/search.js:1891 -#: addons/web/static/src/js/search.js:1901 -#: addons/web/static/src/js/search.js:1929 -#: addons/web/static/src/js/search.js:1953 +#: addons/web/static/src/js/search.js:1344 +#: addons/web/static/src/js/search.js:1360 +#: addons/web/static/src/js/search.js:1381 +#: addons/web/static/src/js/search.js:1402 +#: addons/web/static/src/js/search.js:1425 msgid "is not equal to" msgstr "は次と一致しない" #. openerp-web -#: addons/web/static/src/js/search.js:1902 -#: addons/web/static/src/js/search.js:1930 -#: addons/web/static/src/js/search.js:1954 +#: addons/web/static/src/js/search.js:1345 +#: addons/web/static/src/js/search.js:1361 +#: addons/web/static/src/js/search.js:1382 +#: addons/web/static/src/js/search.js:1403 +#: addons/web/static/src/js/search.js:1426 msgid "greater than" msgstr "次より大きい" #. openerp-web -#: addons/web/static/src/js/search.js:1903 -#: addons/web/static/src/js/search.js:1931 -#: addons/web/static/src/js/search.js:1955 +#: addons/web/static/src/js/search.js:1346 +#: addons/web/static/src/js/search.js:1362 +#: addons/web/static/src/js/search.js:1383 +#: addons/web/static/src/js/search.js:1404 +#: addons/web/static/src/js/search.js:1427 msgid "less than" msgstr "次より小さい" #. openerp-web -#: addons/web/static/src/js/search.js:1904 -#: addons/web/static/src/js/search.js:1932 -#: addons/web/static/src/js/search.js:1956 +#: addons/web/static/src/js/search.js:1347 +#: addons/web/static/src/js/search.js:1363 +#: addons/web/static/src/js/search.js:1384 +#: addons/web/static/src/js/search.js:1405 +#: addons/web/static/src/js/search.js:1428 msgid "greater or equal than" msgstr "次より大きいか等しい" #. openerp-web -#: addons/web/static/src/js/search.js:1905 -#: addons/web/static/src/js/search.js:1933 -#: addons/web/static/src/js/search.js:1957 +#: addons/web/static/src/js/search.js:1348 +#: addons/web/static/src/js/search.js:1364 +#: addons/web/static/src/js/search.js:1385 +#: addons/web/static/src/js/search.js:1406 +#: addons/web/static/src/js/search.js:1429 msgid "less or equal than" msgstr "次より小さいか等しい" #. openerp-web -#: addons/web/static/src/js/search.js:1947 -#: addons/web/static/src/js/search.js:1973 +#: addons/web/static/src/js/search.js:1419 +#: addons/web/static/src/js/search.js:1444 msgid "is" msgstr "が次である" #. openerp-web -#: addons/web/static/src/js/search.js:1974 +#: addons/web/static/src/js/search.js:1445 msgid "is not" msgstr "は次ではない" #. openerp-web -#: addons/web/static/src/js/search.js:1988 +#: addons/web/static/src/js/search.js:1459 msgid "is true" msgstr "は正しい" #. openerp-web -#: addons/web/static/src/js/search.js:1989 +#: addons/web/static/src/js/search.js:1460 msgid "is false" msgstr "は正しくない" @@ -435,195 +448,194 @@ msgstr "管理ビュー (%s)" #. openerp-web #: addons/web/static/src/js/view_editor.js:46 #: addons/web/static/src/js/view_list.js:17 -#: addons/web/static/src/xml/base.xml:121 -#: addons/web/static/src/xml/base.xml:164 -#: addons/web/static/src/xml/base.xml:684 +#: addons/web/static/src/xml/base.xml:100 +#: addons/web/static/src/xml/base.xml:327 +#: addons/web/static/src/xml/base.xml:761 msgid "Create" msgstr "作成" #. openerp-web #: addons/web/static/src/js/view_editor.js:47 -#: addons/web/static/src/xml/base.xml:456 -#: addons/web/static/src/xml/base.xml:683 +#: addons/web/static/src/xml/base.xml:483 +#: addons/web/static/src/xml/base.xml:760 msgid "Edit" msgstr "編集" #. openerp-web #: addons/web/static/src/js/view_editor.js:48 -#: addons/web/static/src/xml/base.xml:1595 +#: addons/web/static/src/xml/base.xml:1653 msgid "Remove" msgstr "削除" #. openerp-web -#: addons/web/static/src/js/view_editor.js:72 +#: addons/web/static/src/js/view_editor.js:71 #, python-format msgid "Create a view (%s)" msgstr "ビュー (%s) を作成" #. openerp-web -#: addons/web/static/src/js/view_editor.js:169 +#: addons/web/static/src/js/view_editor.js:168 msgid "Do you really want to remove this view?" msgstr "このビューを削除しますか?" #. openerp-web -#: addons/web/static/src/js/view_editor.js:365 +#: addons/web/static/src/js/view_editor.js:364 #, python-format msgid "View Editor %d - %s" msgstr "ビューエディタ %d - %s" #. openerp-web -#: addons/web/static/src/js/view_editor.js:368 +#: addons/web/static/src/js/view_editor.js:367 msgid "Inherited View" msgstr "継承ビュー" #. openerp-web -#: addons/web/static/src/js/view_editor.js:372 +#: addons/web/static/src/js/view_editor.js:371 msgid "Do you really wants to create an inherited view here?" msgstr "継承ビューを作成しますか?" #. openerp-web -#: addons/web/static/src/js/view_editor.js:382 +#: addons/web/static/src/js/view_editor.js:381 msgid "Preview" msgstr "プレビュー" #. openerp-web -#: addons/web/static/src/js/view_editor.js:502 +#: addons/web/static/src/js/view_editor.js:501 msgid "Do you really want to remove this node?" msgstr "このノードを削除しますか?" #. openerp-web -#: addons/web/static/src/js/view_editor.js:811 -#: addons/web/static/src/js/view_editor.js:937 +#: addons/web/static/src/js/view_editor.js:815 +#: addons/web/static/src/js/view_editor.js:939 msgid "Properties" msgstr "属性" #. openerp-web -#: addons/web/static/src/js/view_editor.js:814 -#: addons/web/static/src/js/view_editor.js:940 +#: addons/web/static/src/js/view_editor.js:818 +#: addons/web/static/src/js/view_editor.js:942 msgid "Update" msgstr "更新" #. openerp-web -#: addons/web/static/src/js/view_form.js:43 +#: addons/web/static/src/js/view_form.js:16 +#: addons/web/static/src/js/view_form.js:210 msgid "Form" msgstr "フォーム" #. openerp-web -#: addons/web/static/src/js/view_form.js:147 -#: addons/web/static/src/js/view_list.js:358 -#: addons/web/static/src/xml/base.xml:1653 +#: addons/web/static/src/xml/base.xml:632 +#: addons/web/static/src/xml/base.xml:763 +#: addons/web/static/src/xml/base.xml:1714 msgid "Delete" msgstr "削除" #. openerp-web -#: addons/web/static/src/js/view_form.js:148 +#: addons/web/static/src/xml/base.xml:762 msgid "Duplicate" -msgstr "重複" +msgstr "複製" #. openerp-web -#: addons/web/static/src/js/view_form.js:149 -#: addons/web/static/src/js/view_form.js:885 +#: addons/web/static/src/js/view_form.js:133 +#: addons/web/static/src/js/view_form.js:728 msgid "Set Default" msgstr "デフォルトに設定" #. openerp-web -#: addons/web/static/src/js/view_form.js:643 +#: addons/web/static/src/js/view_page.js:59 msgid "Do you really want to delete this record?" msgstr "このレコードを削除しますか?" #. openerp-web -#: addons/web/static/src/js/view_form.js:657 +#: addons/web/static/src/js/view_form.js:508 msgid "" "Warning, the record has been modified, your changes will be discarded." -msgstr "警告,レコードは変更されて,あなたが行った変更は無視されます" +msgstr "警告,レコードは変更されて,あなたが行った変更は無視されます。" #. openerp-web -#: addons/web/static/src/js/view_form.js:892 +#: addons/web/static/src/js/view_form.js:735 msgid "Save default" -msgstr "デフォルトを保管" +msgstr "デフォルトに保存" #. openerp-web -#: addons/web/static/src/js/view_form.js:1402 +#: addons/web/static/src/js/view_form.js:867 #, python-format msgid "Unknown operator %s in domain %s" msgstr "ドメイン %s に無効な演算 %s があります" #. openerp-web -#: addons/web/static/src/js/view_form.js:1410 +#: addons/web/static/src/js/view_form.js:875 #, python-format msgid "Unknown field %s in domain %s" -msgstr "ドメイン %s に無効なフィールド %s があります" +msgstr "ドメイン %s に無効な項目 %s があります" #. openerp-web -#: addons/web/static/src/js/view_form.js:1448 +#: addons/web/static/src/js/view_form.js:913 #, python-format msgid "Unsupported operator %s in domain %s" msgstr "ドメイン %s に無効な演算 %s があります" #. openerp-web -#: addons/web/static/src/js/view_form.js:1657 +#: addons/web/static/src/js/view_form.js:1284 msgid "Confirm" msgstr "確認" #. openerp-web -#: addons/web/static/src/js/view_form.js:2478 +#: addons/web/static/src/js/view_form.js:2193 msgid "<em> Search More...</em>" -msgstr "<em> もっと検索…</em>" +msgstr "<em> さらに検索…</em>" #. openerp-web -#: addons/web/static/src/js/view_form.js:2488 +#: addons/web/static/src/js/view_form.js:2211 #, python-format msgid "<em> Create \"<strong>%s</strong>\"</em>" msgstr "<em> 作成 \"<strong>%s</strong>\"</em>" #. openerp-web -#: addons/web/static/src/js/view_form.js:2494 +#: addons/web/static/src/js/view_form.js:2217 msgid "<em> Create and Edit...</em>" -msgstr "<em> 作成して編集…</em>" +msgstr "<em> 作成&編集…</em>" #. openerp-web -#: addons/web/static/src/js/view_form.js:2527 +#: addons/web/static/src/js/view_form.js:2250 +#: addons/web/static/src/js/views.js:680 msgid "Search: " msgstr "検索: " #. openerp-web -#: addons/web/static/src/js/view_form.js:2527 -#: addons/web/static/src/js/view_form.js:3210 +#: addons/web/static/src/js/view_form.js:2250 +#: addons/web/static/src/js/view_form.js:2738 msgid "Create: " msgstr "作成: " #. openerp-web -#: addons/web/static/src/js/view_form.js:2596 -#: addons/web/static/src/js/view_form.js:3125 -#: addons/web/static/src/js/view_form.js:3238 -#: addons/web/static/src/js/view_form.js:3586 -#: addons/web/static/src/js/view_form.js:3702 +#: addons/web/static/src/js/view_form.js:2040 +#: addons/web/static/src/js/view_form.js:2766 +#: addons/web/static/src/js/view_form.js:2991 msgid "Open: " msgstr "開く: " #. openerp-web -#: addons/web/static/src/js/view_form.js:3517 -#: addons/web/static/src/js/view_form.js:3644 -#: addons/web/static/src/xml/base.xml:1184 -#: addons/web/static/src/xml/base.xml:1594 +#: addons/web/static/src/js/view_form.js:2911 +#: addons/web/static/src/xml/base.xml:755 +#: addons/web/static/src/xml/base.xml:777 +#: addons/web/static/src/xml/base.xml:1652 msgid "Add" msgstr "追加" #. openerp-web -#: addons/web/static/src/js/view_form.js:3566 -#: addons/web/static/src/js/view_form.js:3684 +#: addons/web/static/src/js/view_form.js:2971 msgid "Add: " msgstr "追加: " #. openerp-web #: addons/web/static/src/js/view_form.js:4230 msgid "Save As..." -msgstr "" +msgstr "名前を付けて保存" #. openerp-web #: addons/web/static/src/js/view_form.js:4230 msgid "The field is empty, there's nothing to save !" -msgstr "" +msgstr "項目は空です。何も保存するものはありません。" #. openerp-web #: addons/web/static/src/js/view_list.js:8 @@ -631,54 +643,52 @@ msgid "List" msgstr "リスト" #. openerp-web -#: addons/web/static/src/js/view_list.js:338 +#: addons/web/static/src/js/view_list.js:277 msgid "Unlimited" msgstr "制限なし" #. openerp-web -#: addons/web/static/src/js/view_list.js:356 -#: addons/web/static/src/xml/base.xml:622 -#: addons/web/static/src/xml/base.xml:1657 +#: addons/web/static/src/js/views.js:819 +#: addons/web/static/src/xml/base.xml:1742 msgid "Import" msgstr "インポート" #. openerp-web -#: addons/web/static/src/js/view_list.js:357 -#: addons/web/static/src/xml/base.xml:1554 +#: addons/web/static/src/js/views.js:822 +#: addons/web/static/src/xml/base.xml:1612 msgid "Export" msgstr "エクスポート" #. openerp-web -#: addons/web/static/src/js/view_list.js:436 +#: addons/web/static/src/js/view_list.js:374 msgid "Group" -msgstr "" +msgstr "グループ" #. openerp-web -#: addons/web/static/src/js/view_list.js:623 +#: addons/web/static/src/js/view_list.js:549 msgid "Do you really want to remove these records?" msgstr "このレコードを削除しますか?" #. openerp-web -#: addons/web/static/src/js/view_list.js:716 -#: addons/web/static/src/js/views.js:820 +#: addons/web/static/src/js/views.js:925 msgid "Warning" msgstr "注意" #. openerp-web #: addons/web/static/src/js/view_list.js:716 msgid "You must select at least one record." -msgstr "" +msgstr "最低限1レコード選択して下さい。" #. openerp-web -#: addons/web/static/src/js/view_list.js:1332 +#: addons/web/static/src/js/view_list.js:1243 msgid "Undefined" msgstr "未定義" #. openerp-web -#: addons/web/static/src/js/view_list.js:1428 +#: addons/web/static/src/js/view_list.js:1342 #, python-format msgid "%(page)d/%(page_count)d" -msgstr "%(page)d/%(page_count)d" +msgstr "%(page)d / %(page_count)d" #. openerp-web #: addons/web/static/src/js/view_tree.js:11 @@ -686,336 +696,337 @@ msgid "Tree" msgstr "ツリー" #. openerp-web -#: addons/web/static/src/js/views.js:566 addons/web/static/src/xml/base.xml:452 +#: addons/web/static/src/js/views.js:570 addons/web/static/src/xml/base.xml:480 msgid "Fields View Get" -msgstr "フィールドのビューを得る" +msgstr "項目ビューの取得" #. openerp-web -#: addons/web/static/src/js/views.js:574 +#: addons/web/static/src/js/views.js:578 #, python-format msgid "View Log (%s)" msgstr "ビューのログ (%s)" #. openerp-web -#: addons/web/static/src/js/views.js:604 +#: addons/web/static/src/js/views.js:605 #, python-format msgid "Model %s fields" -msgstr "モデル %s フィールド" +msgstr "モデル %s 項目" #. openerp-web -#: addons/web/static/src/js/views.js:614 addons/web/static/src/xml/base.xml:455 +#: addons/web/static/src/js/views.js:615 addons/web/static/src/xml/base.xml:482 msgid "Manage Views" msgstr "ビューの管理" #. openerp-web -#: addons/web/static/src/js/views.js:615 +#: addons/web/static/src/js/views.js:616 msgid "Could not find current view declaration" msgstr "このビューの定義が見つかりません" #. openerp-web #: addons/web/static/src/js/views.js:716 msgid "Print" -msgstr "" +msgstr "印刷" #. openerp-web #: addons/web/static/src/js/views.js:717 msgid "Attachment" -msgstr "" +msgstr "添付" #. openerp-web #: addons/web/static/src/js/views.js:718 addons/web/static/src/xml/base.xml:276 msgid "More" -msgstr "" +msgstr "さらに" #. openerp-web -#: addons/web/static/src/js/views.js:726 +#: addons/web/static/src/js/views.js:810 msgid "Translate" msgstr "翻訳" #. openerp-web -#: addons/web/static/src/js/views.js:726 +#: addons/web/static/src/js/views.js:812 msgid "Technical translation" msgstr "技術翻訳" #. openerp-web -#: addons/web/static/src/js/views.js:820 +#: addons/web/static/src/js/views.js:924 msgid "You must choose at least one record." -msgstr "少なくとも1つのレコードを選んでください" +msgstr "少なくとも1つのレコードを選んで下さい。" #. openerp-web #: addons/web/static/src/js/views.js:875 msgid "Uploading..." -msgstr "" +msgstr "アップロード中..." #. openerp-web #: addons/web/static/src/js/views.js:885 msgid "Do you really want to delete this attachment ?" -msgstr "" +msgstr "この添付を本当に削除しますか?" #. openerp-web -#: addons/web/static/src/js/views.js:894 +#: addons/web/static/src/js/views.js:962 msgid "Translations" msgstr "翻訳" #. openerp-web -#: addons/web/static/src/xml/base.xml:9 +#: addons/web/static/src/xml/base.xml:52 msgid "Loading..." msgstr "読込み中..." #. openerp-web -#: addons/web/static/src/xml/base.xml:48 +#: addons/web/static/src/xml/base.xml:251 msgid "" "Your version of OpenERP is unsupported. Support & maintenance services are " "available here:" -msgstr "このOpenERPはサポートされていあせん。サポート保守サービスはこちらまで:" +msgstr "このOpenERPのバージョンはサポートされていません。サポート保守サービスはこちらから:" #. openerp-web -#: addons/web/static/src/xml/base.xml:48 +#: addons/web/static/src/xml/base.xml:251 msgid "OpenERP Entreprise" msgstr "OpenERPエンタープライズ" #. openerp-web -#: addons/web/static/src/xml/base.xml:53 +#: addons/web/static/src/xml/base.xml:256 msgid "OpenERP Enterprise Contract." msgstr "OpenERPエンタープライズ契約" #. openerp-web -#: addons/web/static/src/xml/base.xml:54 +#: addons/web/static/src/xml/base.xml:257 msgid "Your report will be sent to the OpenERP Enterprise team." -msgstr "あなたのレポートをOpenERPエンタープライズチームに送ります" +msgstr "あなたのレポートをOpenERPエンタープライズチームに送ります。" #. openerp-web -#: addons/web/static/src/xml/base.xml:56 +#: addons/web/static/src/xml/base.xml:259 msgid "Summary:" -msgstr "要約:" +msgstr "要約:" #. openerp-web -#: addons/web/static/src/xml/base.xml:60 +#: addons/web/static/src/xml/base.xml:263 msgid "Description:" -msgstr "説明:" +msgstr "説明:" #. openerp-web -#: addons/web/static/src/xml/base.xml:64 +#: addons/web/static/src/xml/base.xml:267 msgid "What you did:" msgstr "あなたが行ったこと:" #. openerp-web -#: addons/web/static/src/xml/base.xml:80 +#: addons/web/static/src/xml/base.xml:297 msgid "Invalid username or password" msgstr "ユーザ名またはパスワードが間違っています" #. openerp-web -#: addons/web/static/src/xml/base.xml:84 addons/web/static/src/xml/base.xml:174 -#: addons/web/static/src/xml/base.xml:200 +#: addons/web/static/src/xml/base.xml:116 +#: addons/web/static/src/xml/base.xml:150 +#: addons/web/static/src/xml/base.xml:301 msgid "Database:" msgstr "データベース:" #. openerp-web -#: addons/web/static/src/xml/base.xml:89 +#: addons/web/static/src/xml/base.xml:306 msgid "Username" msgstr "ユーザ名" #. openerp-web -#: addons/web/static/src/xml/base.xml:91 addons/web/static/src/xml/base.xml:125 +#: addons/web/static/src/xml/base.xml:308 +#: addons/web/static/src/xml/base.xml:331 msgid "Password" msgstr "パスワード" #. openerp-web -#: addons/web/static/src/xml/base.xml:93 +#: addons/web/static/src/xml/base.xml:310 msgid "Log in" msgstr "ログイン" #. openerp-web -#: addons/web/static/src/xml/base.xml:97 +#: addons/web/static/src/xml/base.xml:314 msgid "Manage Databases" msgstr "データベースの管理" #. openerp-web -#: addons/web/static/src/xml/base.xml:98 addons/web/static/src/xml/base.xml:389 +#: addons/web/static/src/xml/base.xml:44 addons/web/static/src/xml/base.xml:315 msgid "Powered by" msgstr "で動く" #. openerp-web -#: addons/web/static/src/xml/base.xml:98 addons/web/static/src/xml/base.xml:334 +#: addons/web/static/src/xml/base.xml:44 addons/web/static/src/xml/base.xml:315 +#: addons/web/static/src/xml/base.xml:1819 msgid "OpenERP" msgstr "OpenERP" #. openerp-web -#: addons/web/static/src/xml/base.xml:122 -#: addons/web/static/src/xml/base.xml:189 +#: addons/web/static/src/xml/base.xml:132 +#: addons/web/static/src/xml/base.xml:328 msgid "Drop" -msgstr "破棄" +msgstr "削除" #. openerp-web -#: addons/web/static/src/xml/base.xml:123 -#: addons/web/static/src/xml/base.xml:215 +#: addons/web/static/src/xml/base.xml:166 +#: addons/web/static/src/xml/base.xml:329 msgid "Backup" msgstr "バックアップ" #. openerp-web -#: addons/web/static/src/xml/base.xml:124 -#: addons/web/static/src/xml/base.xml:237 +#: addons/web/static/src/xml/base.xml:195 +#: addons/web/static/src/xml/base.xml:330 msgid "Restore" msgstr "リストア" #. openerp-web -#: addons/web/static/src/xml/base.xml:126 +#: addons/web/static/src/xml/base.xml:332 msgid "Back to Login" msgstr "ログインへ戻る" #. openerp-web -#: addons/web/static/src/xml/base.xml:131 +#: addons/web/static/src/xml/base.xml:61 msgid "CREATE DATABASE" msgstr "データベース作成" #. openerp-web -#: addons/web/static/src/xml/base.xml:134 -#: addons/web/static/src/xml/base.xml:247 +#: addons/web/static/src/xml/base.xml:68 addons/web/static/src/xml/base.xml:211 msgid "Master password:" msgstr "マスタパスワード:" #. openerp-web -#: addons/web/static/src/xml/base.xml:138 -#: addons/web/static/src/xml/base.xml:233 +#: addons/web/static/src/xml/base.xml:72 addons/web/static/src/xml/base.xml:191 msgid "New database name:" msgstr "新しいデータベース名:" #. openerp-web -#: addons/web/static/src/xml/base.xml:142 +#: addons/web/static/src/xml/base.xml:77 msgid "Load Demonstration data:" msgstr "デモ用のデータを読込み中:" #. openerp-web -#: addons/web/static/src/xml/base.xml:146 +#: addons/web/static/src/xml/base.xml:81 msgid "Default language:" msgstr "デフォルトの言語:" #. openerp-web -#: addons/web/static/src/xml/base.xml:156 +#: addons/web/static/src/xml/base.xml:91 msgid "Admin password:" msgstr "アドミン用パスワード:" #. openerp-web -#: addons/web/static/src/xml/base.xml:160 +#: addons/web/static/src/xml/base.xml:95 msgid "Confirm password:" msgstr "パスワード確認" #. openerp-web -#: addons/web/static/src/xml/base.xml:171 +#: addons/web/static/src/xml/base.xml:109 msgid "DROP DATABASE" -msgstr "データベースを破棄" +msgstr "データベースを削除" #. openerp-web -#: addons/web/static/src/xml/base.xml:185 -#: addons/web/static/src/xml/base.xml:211 -#: addons/web/static/src/xml/base.xml:229 +#: addons/web/static/src/xml/base.xml:128 +#: addons/web/static/src/xml/base.xml:162 +#: addons/web/static/src/xml/base.xml:187 msgid "Master Password:" msgstr "マスタパスワード:" #. openerp-web -#: addons/web/static/src/xml/base.xml:197 +#: addons/web/static/src/xml/base.xml:143 msgid "BACKUP DATABASE" msgstr "データベースをバックアップ" #. openerp-web -#: addons/web/static/src/xml/base.xml:222 +#: addons/web/static/src/xml/base.xml:175 msgid "RESTORE DATABASE" msgstr "データベースをリストア" #. openerp-web -#: addons/web/static/src/xml/base.xml:225 +#: addons/web/static/src/xml/base.xml:182 msgid "File:" msgstr "ファイル:" #. openerp-web -#: addons/web/static/src/xml/base.xml:244 +#: addons/web/static/src/xml/base.xml:204 msgid "CHANGE MASTER PASSWORD" msgstr "マスタパスワードの変更" #. openerp-web -#: addons/web/static/src/xml/base.xml:251 +#: addons/web/static/src/xml/base.xml:216 msgid "New master password:" msgstr "新しいマスタパスワード:" #. openerp-web -#: addons/web/static/src/xml/base.xml:255 +#: addons/web/static/src/xml/base.xml:221 msgid "Confirm new master password:" msgstr "新しいマスタパスワードの確認:" #. openerp-web #: addons/web/static/src/xml/base.xml:325 msgid "About OpenERP" -msgstr "" +msgstr "OpenERPについて" #. openerp-web #: addons/web/static/src/xml/base.xml:327 msgid "Log out" -msgstr "" +msgstr "ログアウト" #. openerp-web #: addons/web/static/src/xml/base.xml:333 msgid "Activate the developer mode" -msgstr "" +msgstr "開発者モードを有効化" #. openerp-web -#: addons/web/static/src/xml/base.xml:335 +#: addons/web/static/src/xml/base.xml:1820 msgid "Version" msgstr "バージョン" #. openerp-web -#: addons/web/static/src/xml/base.xml:336 +#: addons/web/static/src/xml/base.xml:1821 msgid "Copyright © 2004-TODAY OpenERP SA. All Rights Reserved." msgstr "Copyright © 2004-TODAY OpenERP SA. All Rights Reserved." #. openerp-web -#: addons/web/static/src/xml/base.xml:337 +#: addons/web/static/src/xml/base.xml:1822 msgid "OpenERP is a trademark of the" msgstr "OpenERPは商標です" #. openerp-web -#: addons/web/static/src/xml/base.xml:338 +#: addons/web/static/src/xml/base.xml:1823 msgid "OpenERP SA Company" msgstr "OpenERP SA Company" #. openerp-web -#: addons/web/static/src/xml/base.xml:340 +#: addons/web/static/src/xml/base.xml:1825 msgid "Licenced under the terms of" msgstr "ライセンスに準拠" #. openerp-web -#: addons/web/static/src/xml/base.xml:341 +#: addons/web/static/src/xml/base.xml:1826 msgid "GNU Affero General Public License" msgstr "GNU Affero General Public License" #. openerp-web -#: addons/web/static/src/xml/base.xml:343 +#: addons/web/static/src/xml/base.xml:1828 msgid "For more information visit" msgstr "もっと詳しい情報はこちらへ" #. openerp-web -#: addons/web/static/src/xml/base.xml:344 +#: addons/web/static/src/xml/base.xml:1829 msgid "OpenERP.com" msgstr "OpenERP.com" #. openerp-web -#: addons/web/static/src/xml/base.xml:352 +#: addons/web/static/src/xml/base.xml:1720 msgid "Old Password:" msgstr "古いパスワード" #. openerp-web -#: addons/web/static/src/xml/base.xml:357 +#: addons/web/static/src/xml/base.xml:1725 msgid "New Password:" msgstr "新しいパスワード:" #. openerp-web -#: addons/web/static/src/xml/base.xml:362 +#: addons/web/static/src/xml/base.xml:1730 msgid "Confirm Password:" msgstr "パスワードの確認:" #. openerp-web #: addons/web/static/src/xml/base.xml:390 msgid "Open" -msgstr "" +msgstr "開く" #. openerp-web #: addons/web/static/src/xml/base.xml:390 @@ -1023,85 +1034,84 @@ msgid "ERP" msgstr "" #. openerp-web -#: addons/web/static/src/xml/base.xml:448 +#: addons/web/static/src/xml/base.xml:477 msgid "Debug View#" -msgstr "ビュー#をデバッグ" +msgstr "ビューをデバッグ" #. openerp-web -#: addons/web/static/src/xml/base.xml:449 +#: addons/web/static/src/xml/base.xml:478 msgid "View Log (perm_read)" msgstr "ログ (perm_read) のビュー" #. openerp-web #: addons/web/static/src/xml/base.xml:450 msgid "Toggle Form Layout Outline" -msgstr "" +msgstr "トグル形式のレイアウトの概観" #. openerp-web -#: addons/web/static/src/xml/base.xml:451 +#: addons/web/static/src/xml/base.xml:479 msgid "View Fields" -msgstr "フィールドのビュー" +msgstr "項目のビュー" #. openerp-web -#: addons/web/static/src/xml/base.xml:453 -#: addons/web/static/src/xml/base.xml:1242 +#: addons/web/static/src/xml/base.xml:1300 msgid "Manage Filters" msgstr "フィルタの管理" #. openerp-web -#: addons/web/static/src/xml/base.xml:456 +#: addons/web/static/src/xml/base.xml:483 msgid "View" msgstr "ビュー" #. openerp-web -#: addons/web/static/src/xml/base.xml:457 +#: addons/web/static/src/xml/base.xml:484 msgid "Edit SearchView" -msgstr "サーチビューを編集" +msgstr "検索ビューの編集" #. openerp-web -#: addons/web/static/src/xml/base.xml:458 +#: addons/web/static/src/xml/base.xml:485 msgid "Edit Action" -msgstr "アクションを編集" +msgstr "アクションの編集" #. openerp-web -#: addons/web/static/src/xml/base.xml:459 +#: addons/web/static/src/xml/base.xml:486 msgid "Edit Workflow" msgstr "ワークフローを編集" #. openerp-web -#: addons/web/static/src/xml/base.xml:464 +#: addons/web/static/src/xml/base.xml:491 msgid "ID:" -msgstr "ID:" +msgstr "ID:" #. openerp-web -#: addons/web/static/src/xml/base.xml:467 +#: addons/web/static/src/xml/base.xml:494 msgid "XML ID:" msgstr "XML ID:" #. openerp-web -#: addons/web/static/src/xml/base.xml:470 +#: addons/web/static/src/xml/base.xml:497 msgid "Creation User:" msgstr "ユーザの作成:" #. openerp-web -#: addons/web/static/src/xml/base.xml:473 +#: addons/web/static/src/xml/base.xml:500 msgid "Creation Date:" msgstr "日付の作成:" #. openerp-web -#: addons/web/static/src/xml/base.xml:476 +#: addons/web/static/src/xml/base.xml:503 msgid "Latest Modification by:" -msgstr "最近の修正は:" +msgstr "最終更新者:" #. openerp-web -#: addons/web/static/src/xml/base.xml:479 +#: addons/web/static/src/xml/base.xml:506 msgid "Latest Modification Date:" -msgstr "最近修正した日付:" +msgstr "最終更新日:" #. openerp-web #: addons/web/static/src/xml/base.xml:518 msgid "Delete this attachment" -msgstr "" +msgstr "この添付の削除" #. openerp-web #: addons/web/static/src/xml/base.xml:523 @@ -1111,446 +1121,450 @@ msgstr "" #. openerp-web #: addons/web/static/src/xml/base.xml:527 msgid "Add..." -msgstr "" +msgstr "追加" #. openerp-web #: addons/web/static/src/xml/base.xml:622 #: addons/web/static/src/xml/base.xml:687 msgid "or" -msgstr "" +msgstr "または" #. openerp-web #: addons/web/static/src/xml/base.xml:687 msgid "Discard" -msgstr "" +msgstr "破棄" #. openerp-web -#: addons/web/static/src/xml/base.xml:704 +#: addons/web/static/src/xml/base.xml:806 msgid "Default:" msgstr "デフォルト:" #. openerp-web -#: addons/web/static/src/xml/base.xml:721 +#: addons/web/static/src/xml/base.xml:823 msgid "Condition:" msgstr "状態:" #. openerp-web -#: addons/web/static/src/xml/base.xml:740 +#: addons/web/static/src/xml/base.xml:842 msgid "Only you" msgstr "あなただけ" #. openerp-web -#: addons/web/static/src/xml/base.xml:747 +#: addons/web/static/src/xml/base.xml:849 msgid "All users" msgstr "全てのユーザ" #. openerp-web -#: addons/web/static/src/xml/base.xml:797 +#: addons/web/static/src/xml/base.xml:856 msgid "Unhandled widget" msgstr "処理されないウィジェット" #. openerp-web -#: addons/web/static/src/xml/base.xml:803 +#: addons/web/static/src/xml/base.xml:936 msgid "(nolabel)" -msgstr "(nolabel)" +msgstr "(ラベルなし)" #. openerp-web -#: addons/web/static/src/xml/base.xml:808 +#: addons/web/static/src/xml/base.xml:941 msgid "Field:" -msgstr "フィールド:" +msgstr "項目:" #. openerp-web -#: addons/web/static/src/xml/base.xml:812 +#: addons/web/static/src/xml/base.xml:945 msgid "Object:" msgstr "オブジェクト:" #. openerp-web -#: addons/web/static/src/xml/base.xml:816 +#: addons/web/static/src/xml/base.xml:949 msgid "Type:" -msgstr "タイプ:" +msgstr "タイプ:" #. openerp-web -#: addons/web/static/src/xml/base.xml:820 +#: addons/web/static/src/xml/base.xml:953 msgid "Widget:" msgstr "ウィジェット:" #. openerp-web -#: addons/web/static/src/xml/base.xml:824 +#: addons/web/static/src/xml/base.xml:957 msgid "Size:" msgstr "サイズ:" #. openerp-web -#: addons/web/static/src/xml/base.xml:828 +#: addons/web/static/src/xml/base.xml:961 msgid "Context:" -msgstr "コンテキスト" +msgstr "コンテキスト:" #. openerp-web -#: addons/web/static/src/xml/base.xml:832 +#: addons/web/static/src/xml/base.xml:965 msgid "Domain:" -msgstr "ドメイン:" +msgstr "ドメイン:" #. openerp-web -#: addons/web/static/src/xml/base.xml:836 +#: addons/web/static/src/xml/base.xml:910 +#: addons/web/static/src/xml/base.xml:969 msgid "Modifiers:" -msgstr "修飾:" +msgstr "修飾:" #. openerp-web -#: addons/web/static/src/xml/base.xml:840 +#: addons/web/static/src/xml/base.xml:973 msgid "Change default:" msgstr "デフォルトの変更:" #. openerp-web -#: addons/web/static/src/xml/base.xml:844 +#: addons/web/static/src/xml/base.xml:977 msgid "On change:" msgstr "変更:" #. openerp-web -#: addons/web/static/src/xml/base.xml:848 +#: addons/web/static/src/xml/base.xml:981 msgid "Relation:" msgstr "関係:" #. openerp-web -#: addons/web/static/src/xml/base.xml:852 +#: addons/web/static/src/xml/base.xml:985 msgid "Selection:" msgstr "選択:" #. openerp-web -#: addons/web/static/src/xml/base.xml:895 +#: addons/web/static/src/xml/base.xml:1040 msgid "Open this resource" msgstr "このリソースを開く" #. openerp-web -#: addons/web/static/src/xml/base.xml:922 +#: addons/web/static/src/xml/base.xml:1063 msgid "Select date" msgstr "日付を選択" #. openerp-web #: addons/web/static/src/xml/base.xml:948 msgid "Open Resource" -msgstr "" +msgstr "リソースを開く" #. openerp-web -#: addons/web/static/src/xml/base.xml:1026 -#: addons/web/static/src/xml/base.xml:1067 +#: addons/web/static/src/xml/base.xml:1162 +#: addons/web/static/src/xml/base.xml:1205 msgid "Set Image" -msgstr "イメージをセット" +msgstr "画像をセット" #. openerp-web -#: addons/web/static/src/xml/base.xml:1030 -#: addons/web/static/src/xml/base.xml:1082 -#: addons/web/static/src/xml/base.xml:1084 +#: addons/web/static/src/js/view_form.js:1620 +#: addons/web/static/src/xml/base.xml:1170 +#: addons/web/static/src/xml/base.xml:1220 +#: addons/web/static/src/xml/base.xml:1222 +#: addons/web/static/src/xml/base.xml:1279 msgid "Clear" -msgstr "クリアー" +msgstr "クリア" #. openerp-web -#: addons/web/static/src/xml/base.xml:1035 -#: addons/web/static/src/xml/base.xml:1092 +#: addons/web/static/src/xml/base.xml:1179 +#: addons/web/static/src/xml/base.xml:1230 msgid "Uploading ..." msgstr "アップロード中…" #. openerp-web #: addons/web/static/src/xml/base.xml:1066 msgid "width: 83px;" -msgstr "" +msgstr "幅:83px;" #. openerp-web -#: addons/web/static/src/xml/base.xml:1069 -#: addons/web/static/src/xml/base.xml:1467 +#: addons/web/static/src/xml/base.xml:1207 +#: addons/web/static/src/xml/base.xml:1501 msgid "Select" msgstr "選択" #. openerp-web -#: addons/web/static/src/xml/base.xml:1075 -#: addons/web/static/src/xml/base.xml:1077 +#: addons/web/static/src/xml/base.xml:1214 +#: addons/web/static/src/xml/base.xml:1216 msgid "Save As" msgstr "名前を付けて保存" #. openerp-web -#: addons/web/static/src/xml/base.xml:1126 +#: addons/web/static/src/xml/base.xml:1245 msgid "Button" msgstr "ボタン" #. openerp-web -#: addons/web/static/src/xml/base.xml:1129 +#: addons/web/static/src/xml/base.xml:1248 msgid "(no string)" -msgstr "(ストリングなし)" +msgstr "(文字列なし)" #. openerp-web -#: addons/web/static/src/xml/base.xml:1136 +#: addons/web/static/src/xml/base.xml:1255 msgid "Special:" msgstr "特別:" #. openerp-web -#: addons/web/static/src/xml/base.xml:1141 +#: addons/web/static/src/xml/base.xml:1260 msgid "Button Type:" msgstr "ボタンのタイプ:" #. openerp-web -#: addons/web/static/src/xml/base.xml:1145 +#: addons/web/static/src/xml/base.xml:1264 msgid "Method:" -msgstr "メソッド:" +msgstr "メソッド:" #. openerp-web -#: addons/web/static/src/xml/base.xml:1149 +#: addons/web/static/src/xml/base.xml:1268 msgid "Action ID:" msgstr "アクションID:" #. openerp-web -#: addons/web/static/src/xml/base.xml:1159 +#: addons/web/static/src/xml/base.xml:542 msgid "Field" -msgstr "フィールド" +msgstr "項目" #. openerp-web #: addons/web/static/src/xml/base.xml:1205 msgid "Advanced Search..." -msgstr "" +msgstr "高度な検索..." #. openerp-web -#: addons/web/static/src/xml/base.xml:1230 +#: addons/web/static/src/xml/base.xml:1287 msgid "-- Filters --" msgstr "--フィルタ--" #. openerp-web -#: addons/web/static/src/xml/base.xml:1239 +#: addons/web/static/src/xml/base.xml:1296 msgid "-- Actions --" msgstr "--アクション--" #. openerp-web -#: addons/web/static/src/xml/base.xml:1240 +#: addons/web/static/src/xml/base.xml:1297 msgid "Add Advanced Filter" msgstr "高度なフィルタを追加" #. openerp-web -#: addons/web/static/src/xml/base.xml:1241 +#: addons/web/static/src/xml/base.xml:1298 msgid "Save Filter" msgstr "フィルタを保存" #. openerp-web -#: addons/web/static/src/xml/base.xml:1247 +#: addons/web/static/src/xml/base.xml:1305 msgid "Filter Name:" -msgstr "フィルタ名" +msgstr "フィルタ名:" #. openerp-web -#: addons/web/static/src/xml/base.xml:1249 +#: addons/web/static/src/xml/base.xml:1307 msgid "(Any existing filter with the same name will be replaced)" msgstr "(同じ名前の既存のフィルタは置き換えられます)" #. openerp-web #: addons/web/static/src/xml/base.xml:1376 msgid "Custom Filters" -msgstr "" +msgstr "カスタムフィルタ" #. openerp-web #: addons/web/static/src/xml/base.xml:1379 msgid "Save current filter" -msgstr "" +msgstr "現在のフィルタを保存" #. openerp-web #: addons/web/static/src/xml/base.xml:1381 msgid "Filter name" -msgstr "" +msgstr "フィルタ名" #. openerp-web #: addons/web/static/src/xml/base.xml:1383 msgid "Share with all users" -msgstr "" +msgstr "全てのユーザと共有" #. openerp-web -#: addons/web/static/src/xml/base.xml:1392 +#: addons/web/static/src/js/search.js:298 +#: addons/web/static/src/xml/base.xml:1299 msgid "Add to Dashboard" msgstr "ダッシュボードに追加" #. openerp-web #: addons/web/static/src/xml/base.xml:1394 msgid "Title of new Dashboard item" -msgstr "" +msgstr "新しいダッシュボード項目のタイトル" #. openerp-web #: addons/web/static/src/xml/base.xml:1395 msgid "save" -msgstr "" +msgstr "保存" #. openerp-web #: addons/web/static/src/xml/base.xml:1399 msgid "Select Dashboard to add this filter to" -msgstr "" +msgstr "このフィルタを加えるためのダッシュボードの選択" #. openerp-web #: addons/web/static/src/xml/base.xml:1406 msgid "Advanced Search" -msgstr "" +msgstr "高度な検索" #. openerp-web #: addons/web/static/src/xml/base.xml:1411 msgid "Add a condition" -msgstr "" +msgstr "条件の追加" #. openerp-web #: addons/web/static/src/xml/base.xml:1412 msgid "Apply" -msgstr "" +msgstr "適用" #. openerp-web -#: addons/web/static/src/xml/base.xml:1475 +#: addons/web/static/src/xml/base.xml:1509 msgid "Save & New" msgstr "保存して新規" #. openerp-web -#: addons/web/static/src/xml/base.xml:1476 +#: addons/web/static/src/xml/base.xml:1510 msgid "Save & Close" msgstr "保存して閉じる" #. openerp-web -#: addons/web/static/src/xml/base.xml:1559 +#: addons/web/static/src/xml/base.xml:1617 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 "" -"このウェザードは,検索条件に合った全てのデータをCSVファイルとしてエクスポートします。\n" -" 全てのデータあるいは変更したあと再インポートできるフィールドのみをエクスポートできます。" +"このウィザードは,現在の検索条件に合致した全てのデータをCSVファイルとしてエクスポートします。\n" +" 全てのデータ,または変更後に再インポートした項目のみをエクスポートできます。" #. openerp-web -#: addons/web/static/src/xml/base.xml:1566 +#: addons/web/static/src/xml/base.xml:1624 msgid "Export Type:" msgstr "エクスポートのタイプ:" #. openerp-web -#: addons/web/static/src/xml/base.xml:1568 +#: addons/web/static/src/xml/base.xml:1626 msgid "Import Compatible Export" msgstr "インポートと互換性があるエクスポート" #. openerp-web -#: addons/web/static/src/xml/base.xml:1569 +#: addons/web/static/src/xml/base.xml:1627 msgid "Export all Data" msgstr "全てのデータをエクスポート" #. openerp-web -#: addons/web/static/src/xml/base.xml:1572 +#: addons/web/static/src/xml/base.xml:1630 msgid "Export Formats" msgstr "エクスポートの形式" #. openerp-web -#: addons/web/static/src/xml/base.xml:1578 +#: addons/web/static/src/xml/base.xml:1636 msgid "Available fields" -msgstr "利用可能なフィールド" +msgstr "利用可能な項目" #. openerp-web -#: addons/web/static/src/xml/base.xml:1580 +#: addons/web/static/src/xml/base.xml:1638 msgid "Fields to export" -msgstr "エクスポートするフィールド" +msgstr "エクスポートする項目" #. openerp-web -#: addons/web/static/src/xml/base.xml:1582 +#: addons/web/static/src/xml/base.xml:1640 msgid "Save fields list" -msgstr "フィールドリストを保存" +msgstr "項目リストを保存" #. openerp-web -#: addons/web/static/src/xml/base.xml:1596 +#: addons/web/static/src/xml/base.xml:1654 msgid "Remove All" msgstr "全てを削除" #. openerp-web -#: addons/web/static/src/xml/base.xml:1607 +#: addons/web/static/src/xml/base.xml:1666 msgid "Name" msgstr "名前" #. openerp-web -#: addons/web/static/src/xml/base.xml:1639 +#: addons/web/static/src/xml/base.xml:1699 msgid "Save as:" msgstr "名前を付けて保存 :" #. openerp-web -#: addons/web/static/src/xml/base.xml:1645 +#: addons/web/static/src/xml/base.xml:1706 msgid "Saved exports:" -msgstr "保存されたエクスポート" +msgstr "保存されたエクスポート:" #. openerp-web -#: addons/web/static/src/xml/base.xml:1663 +#: addons/web/static/src/xml/base.xml:1748 msgid "1. Import a .CSV file" msgstr "1. CVSファイルのインポート" #. openerp-web -#: addons/web/static/src/xml/base.xml:1664 +#: addons/web/static/src/xml/base.xml:1749 msgid "" "Select a .CSV file to import. If you need a sample of file to import,\n" " you should use the export tool with the \"Import Compatible\" option." msgstr "" -"インポートするファイルのサンプルが必要ならば,インポートするCSVファイルを選択\n" -" インポート互換のエクスポートツールを使ってください" +"インポートするファイルのサンプルが必要ならば、インポートするCSVファイルを選択します。\n" +" エクスポートツールでインポート互換オプションを使って下さい。" #. openerp-web -#: addons/web/static/src/xml/base.xml:1668 +#: addons/web/static/src/xml/base.xml:1753 msgid "CSV File:" -msgstr "CSVファイル" +msgstr "CSVファイル:" #. openerp-web -#: addons/web/static/src/xml/base.xml:1671 +#: addons/web/static/src/xml/base.xml:1756 msgid "2. Check your file format" -msgstr "2. ファイル形式をチェックしてください" +msgstr "2. ファイル形式のチェック" #. openerp-web -#: addons/web/static/src/xml/base.xml:1674 +#: addons/web/static/src/xml/base.xml:1759 msgid "Import Options" msgstr "インポートオプション" #. openerp-web -#: addons/web/static/src/xml/base.xml:1678 +#: addons/web/static/src/xml/base.xml:1763 msgid "Does your file have titles?" msgstr "そのファイルはタイトルを持っていますか?" #. openerp-web -#: addons/web/static/src/xml/base.xml:1684 +#: addons/web/static/src/xml/base.xml:1769 msgid "Separator:" -msgstr "区切り文字:" +msgstr "区切り文字:" #. openerp-web -#: addons/web/static/src/xml/base.xml:1686 +#: addons/web/static/src/xml/base.xml:1771 msgid "Delimiter:" -msgstr "区切り文字:" +msgstr "区切り文字:" #. openerp-web -#: addons/web/static/src/xml/base.xml:1690 +#: addons/web/static/src/xml/base.xml:1775 msgid "Encoding:" -msgstr "エンコーディング:" +msgstr "エンコード:" #. openerp-web -#: addons/web/static/src/xml/base.xml:1693 +#: addons/web/static/src/xml/base.xml:1778 msgid "UTF-8" msgstr "UTF-8" #. openerp-web -#: addons/web/static/src/xml/base.xml:1694 +#: addons/web/static/src/xml/base.xml:1779 msgid "Latin 1" msgstr "ラテン1" #. openerp-web -#: addons/web/static/src/xml/base.xml:1697 +#: addons/web/static/src/xml/base.xml:1782 msgid "Lines to skip" msgstr "スキップする行" #. openerp-web -#: addons/web/static/src/xml/base.xml:1697 +#: addons/web/static/src/xml/base.xml:1782 msgid "" "For use if CSV files have titles on multiple lines, skips more than a single " "line during import" -msgstr "CVSファイルが,複数行にタイトルを持っていたら,インポートの際に1行以上をスキップする" +msgstr "CVSファイルが複数行であり、タイトルを持っていた場合、インポートの際に1行以上をスキップするために使用します" #. openerp-web #: addons/web/static/src/xml/base.xml:1713 msgid "--- Don't Import ---" -msgstr "" +msgstr "---インポートなし---" #. openerp-web -#: addons/web/static/src/xml/base.xml:1724 +#: addons/web/static/src/xml/base.xml:1809 msgid "The import failed due to:" msgstr "次の理由でインポートに失敗しました:" #. openerp-web -#: addons/web/static/src/xml/base.xml:1726 +#: addons/web/static/src/xml/base.xml:1811 msgid "Here is a preview of the file we could not import:" -msgstr "インポートできなかったファイルのポレビュー:" +msgstr "インポートできなかったファイルのプレビュー:" #~ msgid "Filter Entry" #~ msgstr "フィルター項目" diff --git a/addons/web/static/lib/cleditor/images/buttons.gif b/addons/web/static/lib/cleditor/images/buttons.gif Binary files differnew file mode 100644 index 00000000000..2e464d0c8c7 --- /dev/null +++ b/addons/web/static/lib/cleditor/images/buttons.gif diff --git a/addons/web/static/lib/cleditor/images/toolbar.gif b/addons/web/static/lib/cleditor/images/toolbar.gif Binary files differnew file mode 100644 index 00000000000..e6eb2da5549 --- /dev/null +++ b/addons/web/static/lib/cleditor/images/toolbar.gif diff --git a/addons/web/static/lib/cleditor/jquery.cleditor.css b/addons/web/static/lib/cleditor/jquery.cleditor.css new file mode 100644 index 00000000000..6ac490bcfc4 --- /dev/null +++ b/addons/web/static/lib/cleditor/jquery.cleditor.css @@ -0,0 +1,24 @@ +.cleditorMain {border:1px solid #999; padding:0 1px 1px; background-color:white}
+.cleditorMain iframe {border:none; margin:0; padding:0}
+.cleditorMain textarea {border:none; margin:0; padding:0; overflow-y:scroll; font:10pt Arial,Verdana; resize:none; outline:none /* webkit grip focus */}
+.cleditorToolbar {background: url('images/toolbar.gif') repeat}
+.cleditorGroup {float:left; height:26px}
+.cleditorButton {float:left; width:24px; height:24px; margin:1px 0 1px 0; background: url('images/buttons.gif')}
+.cleditorDisabled {opacity:0.3; filter:alpha(opacity=30)}
+.cleditorDivider {float:left; width:1px; height:23px; margin:1px 0 1px 0; background:#CCC}
+.cleditorPopup {border:solid 1px #999; background-color:white; position:absolute; font:10pt Arial,Verdana; cursor:default; z-index:10000}
+.cleditorList div {padding:2px 4px 2px 4px}
+.cleditorList p,
+.cleditorList h1,
+.cleditorList h2,
+.cleditorList h3,
+.cleditorList h4,
+.cleditorList h5,
+.cleditorList h6,
+.cleditorList font {padding:0; margin:0; background-color:Transparent}
+.cleditorColor {width:150px; padding:1px 0 0 1px}
+.cleditorColor div {float:left; width:14px; height:14px; margin:0 1px 1px 0}
+.cleditorPrompt {background-color:#F6F7F9; padding:4px; font-size:8.5pt}
+.cleditorPrompt input,
+.cleditorPrompt textarea {font:8.5pt Arial,Verdana;}
+.cleditorMsg {background-color:#FDFCEE; width:150px; padding:4px; font-size:8.5pt}
diff --git a/addons/web/static/lib/cleditor/jquery.cleditor.js b/addons/web/static/lib/cleditor/jquery.cleditor.js new file mode 100644 index 00000000000..c0763136c99 --- /dev/null +++ b/addons/web/static/lib/cleditor/jquery.cleditor.js @@ -0,0 +1,1132 @@ +/**
+ @preserve CLEditor WYSIWYG HTML Editor v1.3.0
+ http://premiumsoftware.net/cleditor
+ requires jQuery v1.4.2 or later
+
+ Copyright 2010, Chris Landowski, Premium Software, LLC
+ Dual licensed under the MIT or GPL Version 2 licenses.
+*/
+
+// ==ClosureCompiler==
+// @compilation_level SIMPLE_OPTIMIZATIONS
+// @output_file_name jquery.cleditor.min.js
+// ==/ClosureCompiler==
+
+(function($) {
+
+ //==============
+ // jQuery Plugin
+ //==============
+
+ $.cleditor = {
+
+ // Define the defaults used for all new cleditor instances
+ defaultOptions: {
+ width: 500, // width not including margins, borders or padding
+ height: 250, // height not including margins, borders or padding
+ controls: // controls to add to the toolbar
+ "bold italic underline strikethrough subscript superscript | font size " +
+ "style | color highlight removeformat | bullets numbering | outdent " +
+ "indent | alignleft center alignright justify | undo redo | " +
+ "rule image link unlink | cut copy paste pastetext | print source",
+ colors: // colors in the color popup
+ "FFF FCC FC9 FF9 FFC 9F9 9FF CFF CCF FCF " +
+ "CCC F66 F96 FF6 FF3 6F9 3FF 6FF 99F F9F " +
+ "BBB F00 F90 FC6 FF0 3F3 6CC 3CF 66C C6C " +
+ "999 C00 F60 FC3 FC0 3C0 0CC 36F 63F C3C " +
+ "666 900 C60 C93 990 090 399 33F 60C 939 " +
+ "333 600 930 963 660 060 366 009 339 636 " +
+ "000 300 630 633 330 030 033 006 309 303",
+ fonts: // font names in the font popup
+ "Arial,Arial Black,Comic Sans MS,Courier New,Narrow,Garamond," +
+ "Georgia,Impact,Sans Serif,Serif,Tahoma,Trebuchet MS,Verdana",
+ sizes: // sizes in the font size popup
+ "1,2,3,4,5,6,7",
+ styles: // styles in the style popup
+ [["Paragraph", "<p>"], ["Header 1", "<h1>"], ["Header 2", "<h2>"],
+ ["Header 3", "<h3>"], ["Header 4","<h4>"], ["Header 5","<h5>"],
+ ["Header 6","<h6>"]],
+ useCSS: false, // use CSS to style HTML when possible (not supported in ie)
+ docType: // Document type contained within the editor
+ '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
+ docCSSFile: // CSS file used to style the document contained within the editor
+ "",
+ bodyStyle: // style to assign to document body contained within the editor
+ "margin:4px; font:10pt Arial,Verdana; cursor:text"
+ },
+
+ // Define all usable toolbar buttons - the init string property is
+ // expanded during initialization back into the buttons object and
+ // seperate object properties are created for each button.
+ // e.g. buttons.size.title = "Font Size"
+ buttons: {
+ // name,title,command,popupName (""=use name)
+ init:
+ "bold,,|" +
+ "italic,,|" +
+ "underline,,|" +
+ "strikethrough,,|" +
+ "subscript,,|" +
+ "superscript,,|" +
+ "font,,fontname,|" +
+ "size,Font Size,fontsize,|" +
+ "style,,formatblock,|" +
+ "color,Font Color,forecolor,|" +
+ "highlight,Text Highlight Color,hilitecolor,color|" +
+ "removeformat,Remove Formatting,|" +
+ "bullets,,insertunorderedlist|" +
+ "numbering,,insertorderedlist|" +
+ "outdent,,|" +
+ "indent,,|" +
+ "alignleft,Align Text Left,justifyleft|" +
+ "center,,justifycenter|" +
+ "alignright,Align Text Right,justifyright|" +
+ "justify,,justifyfull|" +
+ "undo,,|" +
+ "redo,,|" +
+ "rule,Insert Horizontal Rule,inserthorizontalrule|" +
+ "image,Insert Image,insertimage,url|" +
+ "link,Insert Hyperlink,createlink,url|" +
+ "unlink,Remove Hyperlink,|" +
+ "cut,,|" +
+ "copy,,|" +
+ "paste,,|" +
+ "pastetext,Paste as Text,inserthtml,|" +
+ "print,,|" +
+ "source,Show Source"
+ },
+
+ // imagesPath - returns the path to the images folder
+ imagesPath: function() { return imagesPath(); }
+
+ };
+
+ // cleditor - creates a new editor for each of the matched textareas
+ $.fn.cleditor = function(options) {
+
+ // Create a new jQuery object to hold the results
+ var $result = $([]);
+
+ // Loop through all matching textareas and create the editors
+ this.each(function(idx, elem) {
+ if (elem.tagName == "TEXTAREA") {
+ var data = $.data(elem, CLEDITOR);
+ if (!data) data = new cleditor(elem, options);
+ $result = $result.add(data);
+ }
+ });
+
+ // return the new jQuery object
+ return $result;
+
+ };
+
+ //==================
+ // Private Variables
+ //==================
+
+ var
+
+ // Misc constants
+ BACKGROUND_COLOR = "backgroundColor",
+ BUTTON = "button",
+ BUTTON_NAME = "buttonName",
+ CHANGE = "change",
+ CLEDITOR = "cleditor",
+ CLICK = "click",
+ DISABLED = "disabled",
+ DIV_TAG = "<div>",
+ TRANSPARENT = "transparent",
+ UNSELECTABLE = "unselectable",
+
+ // Class name constants
+ MAIN_CLASS = "cleditorMain", // main containing div
+ TOOLBAR_CLASS = "cleditorToolbar", // toolbar div inside main div
+ GROUP_CLASS = "cleditorGroup", // group divs inside the toolbar div
+ BUTTON_CLASS = "cleditorButton", // button divs inside group div
+ DISABLED_CLASS = "cleditorDisabled",// disabled button divs
+ DIVIDER_CLASS = "cleditorDivider", // divider divs inside group div
+ POPUP_CLASS = "cleditorPopup", // popup divs inside body
+ LIST_CLASS = "cleditorList", // list popup divs inside body
+ COLOR_CLASS = "cleditorColor", // color popup div inside body
+ PROMPT_CLASS = "cleditorPrompt", // prompt popup divs inside body
+ MSG_CLASS = "cleditorMsg", // message popup div inside body
+
+ // Test for ie
+ ie = $.browser.msie,
+ ie6 = /msie\s6/i.test(navigator.userAgent),
+
+ // Test for iPhone/iTouch/iPad
+ iOS = /iphone|ipad|ipod/i.test(navigator.userAgent),
+
+ // Popups are created once as needed and shared by all editor instances
+ popups = {},
+
+ // Used to prevent the document click event from being bound more than once
+ documentClickAssigned,
+
+ // Local copy of the buttons object
+ buttons = $.cleditor.buttons;
+
+ //===============
+ // Initialization
+ //===============
+
+ // Expand the buttons.init string back into the buttons object
+ // and create seperate object properties for each button.
+ // e.g. buttons.size.title = "Font Size"
+ $.each(buttons.init.split("|"), function(idx, button) {
+ var items = button.split(","), name = items[0];
+ buttons[name] = {
+ stripIndex: idx,
+ name: name,
+ title: items[1] === "" ? name.charAt(0).toUpperCase() + name.substr(1) : items[1],
+ command: items[2] === "" ? name : items[2],
+ popupName: items[3] === "" ? name : items[3]
+ };
+ });
+ delete buttons.init;
+
+ //============
+ // Constructor
+ //============
+
+ // cleditor - creates a new editor for the passed in textarea element
+ cleditor = function(area, options) {
+
+ var editor = this;
+
+ // Get the defaults and override with options
+ editor.options = options = $.extend({}, $.cleditor.defaultOptions, options);
+
+ // Hide the textarea and associate it with this editor
+ var $area = editor.$area = $(area)
+ .hide()
+ .data(CLEDITOR, editor)
+ .blur(function() {
+ // Update the iframe when the textarea loses focus
+ updateFrame(editor, true);
+ });
+
+ // Create the main container and append the textarea
+ var $main = editor.$main = $(DIV_TAG)
+ .addClass(MAIN_CLASS)
+ .width(options.width)
+ .height(options.height);
+
+ // Create the toolbar
+ var $toolbar = editor.$toolbar = $(DIV_TAG)
+ .addClass(TOOLBAR_CLASS)
+ .appendTo($main);
+
+ // Add the first group to the toolbar
+ var $group = $(DIV_TAG)
+ .addClass(GROUP_CLASS)
+ .appendTo($toolbar);
+
+ // Add the buttons to the toolbar
+ $.each(options.controls.split(" "), function(idx, buttonName) {
+ if (buttonName === "") return true;
+
+ // Divider
+ if (buttonName == "|") {
+
+ // Add a new divider to the group
+ var $div = $(DIV_TAG)
+ .addClass(DIVIDER_CLASS)
+ .appendTo($group);
+
+ // Create a new group
+ $group = $(DIV_TAG)
+ .addClass(GROUP_CLASS)
+ .appendTo($toolbar);
+
+ }
+
+ // Button
+ else {
+
+ // Get the button definition
+ var button = buttons[buttonName];
+
+ // Add a new button to the group
+ var $buttonDiv = $(DIV_TAG)
+ .data(BUTTON_NAME, button.name)
+ .addClass(BUTTON_CLASS)
+ .attr("title", button.title)
+ .bind(CLICK, $.proxy(buttonClick, editor))
+ .appendTo($group)
+ .hover(hoverEnter, hoverLeave);
+
+ // Prepare the button image
+ var map = {};
+ if (button.css) map = button.css;
+ else if (button.image) map.backgroundImage = imageUrl(button.image);
+ if (button.stripIndex) map.backgroundPosition = button.stripIndex * -24;
+ $buttonDiv.css(map);
+
+ // Add the unselectable attribute for ie
+ if (ie)
+ $buttonDiv.attr(UNSELECTABLE, "on");
+
+ // Create the popup
+ if (button.popupName)
+ createPopup(button.popupName, options, button.popupClass,
+ button.popupContent, button.popupHover);
+
+ }
+
+ });
+
+ // Add the main div to the DOM and append the textarea
+ $main.insertBefore($area)
+ .append($area);
+
+ // Bind the document click event handler
+ if (!documentClickAssigned) {
+ $(document).click(function(e) {
+ // Dismiss all non-prompt popups
+ var $target = $(e.target);
+ if (!$target.add($target.parents()).is("." + PROMPT_CLASS))
+ hidePopups();
+ });
+ documentClickAssigned = true;
+ }
+
+ // Bind the window resize event when the width or height is auto or %
+ if (/auto|%/.test("" + options.width + options.height))
+ $(window).resize(function() {refresh(editor);});
+
+ // Create the iframe and resize the controls
+ refresh(editor);
+
+ };
+
+ //===============
+ // Public Methods
+ //===============
+
+ var fn = cleditor.prototype,
+
+ // Expose the following private functions as methods on the cleditor object.
+ // The closure compiler will rename the private functions. However, the
+ // exposed method names on the cleditor object will remain fixed.
+ methods = [
+ ["clear", clear],
+ ["disable", disable],
+ ["execCommand", execCommand],
+ ["focus", focus],
+ ["hidePopups", hidePopups],
+ ["sourceMode", sourceMode, true],
+ ["refresh", refresh],
+ ["select", select],
+ ["selectedHTML", selectedHTML, true],
+ ["selectedText", selectedText, true],
+ ["showMessage", showMessage],
+ ["updateFrame", updateFrame],
+ ["updateTextArea", updateTextArea]
+ ];
+
+ $.each(methods, function(idx, method) {
+ fn[method[0]] = function() {
+ var editor = this, args = [editor];
+ // using each here would cast booleans into objects!
+ for(var x = 0; x < arguments.length; x++) {args.push(arguments[x]);}
+ var result = method[1].apply(editor, args);
+ if (method[2]) return result;
+ return editor;
+ };
+ });
+
+ // change - shortcut for .bind("change", handler) or .trigger("change")
+ fn.change = function(handler) {
+ var $this = $(this);
+ return handler ? $this.bind(CHANGE, handler) : $this.trigger(CHANGE);
+ };
+
+ //===============
+ // Event Handlers
+ //===============
+
+ // buttonClick - click event handler for toolbar buttons
+ function buttonClick(e) {
+
+ var editor = this,
+ buttonDiv = e.target,
+ buttonName = $.data(buttonDiv, BUTTON_NAME),
+ button = buttons[buttonName],
+ popupName = button.popupName,
+ popup = popups[popupName];
+
+ // Check if disabled
+ if (editor.disabled || $(buttonDiv).attr(DISABLED) == DISABLED)
+ return;
+
+ // Fire the buttonClick event
+ var data = {
+ editor: editor,
+ button: buttonDiv,
+ buttonName: buttonName,
+ popup: popup,
+ popupName: popupName,
+ command: button.command,
+ useCSS: editor.options.useCSS
+ };
+
+ if (button.buttonClick && button.buttonClick(e, data) === false)
+ return false;
+
+ // Toggle source
+ if (buttonName == "source") {
+
+ // Show the iframe
+ if (sourceMode(editor)) {
+ delete editor.range;
+ editor.$area.hide();
+ editor.$frame.show();
+ buttonDiv.title = button.title;
+ }
+
+ // Show the textarea
+ else {
+ editor.$frame.hide();
+ editor.$area.show();
+ buttonDiv.title = "Show Rich Text";
+ }
+
+ // Enable or disable the toolbar buttons
+ // IE requires the timeout
+ setTimeout(function() {refreshButtons(editor);}, 100);
+
+ }
+
+ // Check for rich text mode
+ else if (!sourceMode(editor)) {
+
+ // Handle popups
+ if (popupName) {
+ var $popup = $(popup);
+
+ // URL
+ if (popupName == "url") {
+
+ // Check for selection before showing the link url popup
+ if (buttonName == "link" && selectedText(editor) === "") {
+ showMessage(editor, "A selection is required when inserting a link.", buttonDiv);
+ return false;
+ }
+
+ // Wire up the submit button click event handler
+ $popup.children(":button")
+ .unbind(CLICK)
+ .bind(CLICK, function() {
+
+ // Insert the image or link if a url was entered
+ var $text = $popup.find(":text"),
+ url = $.trim($text.val());
+ if (url !== "")
+ execCommand(editor, data.command, url, null, data.button);
+
+ // Reset the text, hide the popup and set focus
+ $text.val("http://");
+ hidePopups();
+ focus(editor);
+
+ });
+
+ }
+
+ // Paste as Text
+ else if (popupName == "pastetext") {
+
+ // Wire up the submit button click event handler
+ $popup.children(":button")
+ .unbind(CLICK)
+ .bind(CLICK, function() {
+
+ // Insert the unformatted text replacing new lines with break tags
+ var $textarea = $popup.find("textarea"),
+ text = $textarea.val().replace(/\n/g, "<br />");
+ if (text !== "")
+ execCommand(editor, data.command, text, null, data.button);
+
+ // Reset the text, hide the popup and set focus
+ $textarea.val("");
+ hidePopups();
+ focus(editor);
+
+ });
+
+ }
+
+ // Show the popup if not already showing for this button
+ if (buttonDiv !== $.data(popup, BUTTON)) {
+ showPopup(editor, popup, buttonDiv);
+ return false; // stop propagination to document click
+ }
+
+ // propaginate to documnt click
+ return;
+
+ }
+
+ // Print
+ else if (buttonName == "print")
+ editor.$frame[0].contentWindow.print();
+
+ // All other buttons
+ else if (!execCommand(editor, data.command, data.value, data.useCSS, buttonDiv))
+ return false;
+
+ }
+
+ // Focus the editor
+ focus(editor);
+
+ }
+
+ // hoverEnter - mouseenter event handler for buttons and popup items
+ function hoverEnter(e) {
+ var $div = $(e.target).closest("div");
+ $div.css(BACKGROUND_COLOR, $div.data(BUTTON_NAME) ? "#FFF" : "#FFC");
+ }
+
+ // hoverLeave - mouseleave event handler for buttons and popup items
+ function hoverLeave(e) {
+ $(e.target).closest("div").css(BACKGROUND_COLOR, "transparent");
+ }
+
+ // popupClick - click event handler for popup items
+ function popupClick(e) {
+
+ var editor = this,
+ popup = e.data.popup,
+ target = e.target;
+
+ // Check for message and prompt popups
+ if (popup === popups.msg || $(popup).hasClass(PROMPT_CLASS))
+ return;
+
+ // Get the button info
+ var buttonDiv = $.data(popup, BUTTON),
+ buttonName = $.data(buttonDiv, BUTTON_NAME),
+ button = buttons[buttonName],
+ command = button.command,
+ value,
+ useCSS = editor.options.useCSS;
+
+ // Get the command value
+ if (buttonName == "font")
+ // Opera returns the fontfamily wrapped in quotes
+ value = target.style.fontFamily.replace(/"/g, "");
+ else if (buttonName == "size") {
+ if (target.tagName == "DIV")
+ target = target.children[0];
+ value = target.innerHTML;
+ }
+ else if (buttonName == "style")
+ value = "<" + target.tagName + ">";
+ else if (buttonName == "color")
+ value = hex(target.style.backgroundColor);
+ else if (buttonName == "highlight") {
+ value = hex(target.style.backgroundColor);
+ if (ie) command = 'backcolor';
+ else useCSS = true;
+ }
+
+ // Fire the popupClick event
+ var data = {
+ editor: editor,
+ button: buttonDiv,
+ buttonName: buttonName,
+ popup: popup,
+ popupName: button.popupName,
+ command: command,
+ value: value,
+ useCSS: useCSS
+ };
+
+ if (button.popupClick && button.popupClick(e, data) === false)
+ return;
+
+ // Execute the command
+ if (data.command && !execCommand(editor, data.command, data.value, data.useCSS, buttonDiv))
+ return false;
+
+ // Hide the popup and focus the editor
+ hidePopups();
+ focus(editor);
+
+ }
+
+ //==================
+ // Private Functions
+ //==================
+ + // checksum - returns a checksum using the Adler-32 method
+ function checksum(text)
+ {
+ var a = 1, b = 0;
+ for (var index = 0; index < text.length; ++index) {
+ a = (a + text.charCodeAt(index)) % 65521;
+ b = (b + a) % 65521;
+ }
+ return (b << 16) | a;
+ }
+
+ // clear - clears the contents of the editor
+ function clear(editor) {
+ editor.$area.val("");
+ updateFrame(editor);
+ }
+
+ // createPopup - creates a popup and adds it to the body
+ function createPopup(popupName, options, popupTypeClass, popupContent, popupHover) {
+
+ // Check if popup already exists
+ if (popups[popupName])
+ return popups[popupName];
+
+ // Create the popup
+ var $popup = $(DIV_TAG)
+ .hide()
+ .addClass(POPUP_CLASS)
+ .appendTo("body");
+
+ // Add the content
+
+ // Custom popup
+ if (popupContent)
+ $popup.html(popupContent);
+
+ // Color
+ else if (popupName == "color") {
+ var colors = options.colors.split(" ");
+ if (colors.length < 10)
+ $popup.width("auto");
+ $.each(colors, function(idx, color) {
+ $(DIV_TAG).appendTo($popup)
+ .css(BACKGROUND_COLOR, "#" + color);
+ });
+ popupTypeClass = COLOR_CLASS;
+ }
+
+ // Font
+ else if (popupName == "font")
+ $.each(options.fonts.split(","), function(idx, font) {
+ $(DIV_TAG).appendTo($popup)
+ .css("fontFamily", font)
+ .html(font);
+ });
+
+ // Size
+ else if (popupName == "size")
+ $.each(options.sizes.split(","), function(idx, size) {
+ $(DIV_TAG).appendTo($popup)
+ .html("<font size=" + size + ">" + size + "</font>");
+ });
+
+ // Style
+ else if (popupName == "style")
+ $.each(options.styles, function(idx, style) {
+ $(DIV_TAG).appendTo($popup)
+ .html(style[1] + style[0] + style[1].replace("<", "</"));
+ });
+
+ // URL
+ else if (popupName == "url") {
+ $popup.html('Enter URL:<br><input type=text value="http://" size=35><br><input type=button value="Submit">');
+ popupTypeClass = PROMPT_CLASS;
+ }
+
+ // Paste as Text
+ else if (popupName == "pastetext") {
+ $popup.html('Paste your content here and click submit.<br /><textarea cols=40 rows=3></textarea><br /><input type=button value=Submit>');
+ popupTypeClass = PROMPT_CLASS;
+ }
+
+ // Add the popup type class name
+ if (!popupTypeClass && !popupContent)
+ popupTypeClass = LIST_CLASS;
+ $popup.addClass(popupTypeClass);
+
+ // Add the unselectable attribute to all items
+ if (ie) {
+ $popup.attr(UNSELECTABLE, "on")
+ .find("div,font,p,h1,h2,h3,h4,h5,h6")
+ .attr(UNSELECTABLE, "on");
+ }
+
+ // Add the hover effect to all items
+ if ($popup.hasClass(LIST_CLASS) || popupHover === true)
+ $popup.children().hover(hoverEnter, hoverLeave);
+
+ // Add the popup to the array and return it
+ popups[popupName] = $popup[0];
+ return $popup[0];
+
+ }
+
+ // disable - enables or disables the editor
+ function disable(editor, disabled) {
+
+ // Update the textarea and save the state
+ if (disabled) {
+ editor.$area.attr(DISABLED, DISABLED);
+ editor.disabled = true;
+ }
+ else {
+ editor.$area.removeAttr(DISABLED);
+ delete editor.disabled;
+ }
+
+ // Switch the iframe into design mode.
+ // ie6 does not support designMode.
+ // ie7 & ie8 do not properly support designMode="off".
+ try {
+ if (ie) editor.doc.body.contentEditable = !disabled;
+ else editor.doc.designMode = !disabled ? "on" : "off";
+ }
+ // Firefox 1.5 throws an exception that can be ignored
+ // when toggling designMode from off to on.
+ catch (err) {}
+
+ // Enable or disable the toolbar buttons
+ refreshButtons(editor);
+
+ }
+
+ // execCommand - executes a designMode command
+ function execCommand(editor, command, value, useCSS, button) {
+
+ // Restore the current ie selection
+ restoreRange(editor);
+
+ // Set the styling method
+ if (!ie) {
+ if (useCSS === undefined || useCSS === null)
+ useCSS = editor.options.useCSS;
+ editor.doc.execCommand("styleWithCSS", 0, useCSS.toString());
+ }
+
+ // Execute the command and check for error
+ var success = true, description;
+ if (ie && command.toLowerCase() == "inserthtml")
+ getRange(editor).pasteHTML(value);
+ else {
+ try { success = editor.doc.execCommand(command, 0, value || null); }
+ catch (err) { description = err.description; success = false; }
+ if (!success) {
+ if ("cutcopypaste".indexOf(command) > -1)
+ showMessage(editor, "For security reasons, your browser does not support the " +
+ command + " command. Try using the keyboard shortcut or context menu instead.",
+ button);
+ else
+ showMessage(editor,
+ (description ? description : "Error executing the " + command + " command."),
+ button);
+ }
+ }
+
+ // Enable the buttons
+ refreshButtons(editor);
+ return success;
+
+ }
+
+ // focus - sets focus to either the textarea or iframe
+ function focus(editor) {
+ setTimeout(function() {
+ if (sourceMode(editor)) editor.$area.focus();
+ else editor.$frame[0].contentWindow.focus();
+ refreshButtons(editor);
+ }, 0);
+ }
+
+ // getRange - gets the current text range object
+ function getRange(editor) {
+ if (ie) return getSelection(editor).createRange();
+ return getSelection(editor).getRangeAt(0);
+ }
+
+ // getSelection - gets the current text range object
+ function getSelection(editor) {
+ if (ie) return editor.doc.selection;
+ return editor.$frame[0].contentWindow.getSelection();
+ }
+
+ // Returns the hex value for the passed in string.
+ // hex("rgb(255, 0, 0)"); // #FF0000
+ // hex("#FF0000"); // #FF0000
+ // hex("#F00"); // #FF0000
+ function hex(s) {
+ var m = /rgba?\((\d+), (\d+), (\d+)/.exec(s),
+ c = s.split("");
+ if (m) {
+ s = ( m[1] << 16 | m[2] << 8 | m[3] ).toString(16);
+ while (s.length < 6)
+ s = "0" + s;
+ }
+ return "#" + (s.length == 6 ? s : c[1] + c[1] + c[2] + c[2] + c[3] + c[3]);
+ }
+
+ // hidePopups - hides all popups
+ function hidePopups() {
+ $.each(popups, function(idx, popup) {
+ $(popup)
+ .hide()
+ .unbind(CLICK)
+ .removeData(BUTTON);
+ });
+ }
+
+ // imagesPath - returns the path to the images folder
+ function imagesPath() {
+ var cssFile = "jquery.cleditor.css",
+ href = $("link[href$='" + cssFile +"']").attr("href");
+ return href.substr(0, href.length - cssFile.length) + "images/";
+ }
+
+ // imageUrl - Returns the css url string for a filemane
+ function imageUrl(filename) {
+ return "url(" + imagesPath() + filename + ")";
+ }
+
+ // refresh - creates the iframe and resizes the controls
+ function refresh(editor) {
+
+ var $main = editor.$main,
+ options = editor.options;
+
+ // Remove the old iframe
+ if (editor.$frame)
+ editor.$frame.remove();
+
+ // Create a new iframe
+ var $frame = editor.$frame = $('<iframe frameborder="0" src="javascript:true;">')
+ .hide()
+ .appendTo($main);
+
+ // Load the iframe document content
+ var contentWindow = $frame[0].contentWindow,
+ doc = editor.doc = contentWindow.document,
+ $doc = $(doc);
+
+ doc.open();
+ doc.write(
+ options.docType +
+ '<html>' +
+ ((options.docCSSFile === '') ? '' : '<head><link rel="stylesheet" type="text/css" href="' + options.docCSSFile + '" /></head>') +
+ '<body style="' + options.bodyStyle + '"></body></html>'
+ );
+ doc.close();
+
+ // Work around for bug in IE which causes the editor to lose
+ // focus when clicking below the end of the document.
+ if (ie)
+ $doc.click(function() {focus(editor);});
+
+ // Load the content
+ updateFrame(editor);
+
+ // Bind the ie specific iframe event handlers
+ if (ie) {
+
+ // Save the current user selection. This code is needed since IE will
+ // reset the selection just after the beforedeactivate event and just
+ // before the beforeactivate event.
+ $doc.bind("beforedeactivate beforeactivate selectionchange keypress", function(e) {
+
+ // Flag the editor as inactive
+ if (e.type == "beforedeactivate")
+ editor.inactive = true;
+
+ // Get rid of the bogus selection and flag the editor as active
+ else if (e.type == "beforeactivate") {
+ if (!editor.inactive && editor.range && editor.range.length > 1)
+ editor.range.shift();
+ delete editor.inactive;
+ }
+
+ // Save the selection when the editor is active
+ else if (!editor.inactive) {
+ if (!editor.range)
+ editor.range = [];
+ editor.range.unshift(getRange(editor));
+
+ // We only need the last 2 selections
+ while (editor.range.length > 2)
+ editor.range.pop();
+ }
+
+ });
+
+ // Restore the text range when the iframe gains focus
+ $frame.focus(function() {
+ restoreRange(editor);
+ });
+
+ }
+
+ // Update the textarea when the iframe loses focus
+ ($.browser.mozilla ? $doc : $(contentWindow)).blur(function() {
+ updateTextArea(editor, true);
+ });
+
+ // Enable the toolbar buttons as the user types or clicks
+ $doc.click(hidePopups)
+ .bind("keyup mouseup", function() {
+ refreshButtons(editor);
+ });
+
+ // Show the textarea for iPhone/iTouch/iPad or
+ // the iframe when design mode is supported.
+ if (iOS) editor.$area.show();
+ else $frame.show();
+
+ // Wait for the layout to finish - shortcut for $(document).ready()
+ $(function() {
+
+ var $toolbar = editor.$toolbar,
+ $group = $toolbar.children("div:last"),
+ wid = $main.width();
+
+ // Resize the toolbar
+ var hgt = $group.offset().top + $group.outerHeight() - $toolbar.offset().top + 1;
+ $toolbar.height(hgt);
+
+ // Resize the iframe
+ hgt = (/%/.test("" + options.height) ? $main.height() : parseInt(options.height)) - hgt;
+ $frame.width(wid).height(hgt);
+
+ // Resize the textarea. IE6 textareas have a 1px top
+ // & bottom margin that cannot be removed using css.
+ editor.$area.width(wid).height(ie6 ? hgt - 2 : hgt);
+
+ // Switch the iframe into design mode if enabled
+ disable(editor, editor.disabled);
+
+ // Enable or disable the toolbar buttons
+ refreshButtons(editor);
+
+ });
+
+ }
+
+ // refreshButtons - enables or disables buttons based on availability
+ function refreshButtons(editor) {
+
+ // Webkit requires focus before queryCommandEnabled will return anything but false
+ if (!iOS && $.browser.webkit && !editor.focused) {
+ editor.$frame[0].contentWindow.focus();
+ window.focus();
+ editor.focused = true;
+ }
+
+ // Get the object used for checking queryCommandEnabled
+ var queryObj = editor.doc;
+ if (ie) queryObj = getRange(editor);
+
+ // Loop through each button
+ var inSourceMode = sourceMode(editor);
+ $.each(editor.$toolbar.find("." + BUTTON_CLASS), function(idx, elem) {
+
+ var $elem = $(elem),
+ button = $.cleditor.buttons[$.data(elem, BUTTON_NAME)],
+ command = button.command,
+ enabled = true;
+
+ // Determine the state
+ if (editor.disabled)
+ enabled = false;
+ else if (button.getEnabled) {
+ var data = {
+ editor: editor,
+ button: elem,
+ buttonName: button.name,
+ popup: popups[button.popupName],
+ popupName: button.popupName,
+ command: button.command,
+ useCSS: editor.options.useCSS
+ };
+ enabled = button.getEnabled(data);
+ if (enabled === undefined)
+ enabled = true;
+ }
+ else if (((inSourceMode || iOS) && button.name != "source") ||
+ (ie && (command == "undo" || command == "redo")))
+ enabled = false;
+ else if (command && command != "print") {
+ if (ie && command == "hilitecolor")
+ command = "backcolor";
+ // IE does not support inserthtml, so it's always enabled
+ if (!ie || command != "inserthtml") {
+ try {enabled = queryObj.queryCommandEnabled(command);}
+ catch (err) {enabled = false;}
+ }
+ }
+
+ // Enable or disable the button
+ if (enabled) {
+ $elem.removeClass(DISABLED_CLASS);
+ $elem.removeAttr(DISABLED);
+ }
+ else {
+ $elem.addClass(DISABLED_CLASS);
+ $elem.attr(DISABLED, DISABLED);
+ }
+
+ });
+ }
+
+ // restoreRange - restores the current ie selection
+ function restoreRange(editor) {
+ if (ie && editor.range)
+ editor.range[0].select();
+ }
+
+ // select - selects all the text in either the textarea or iframe
+ function select(editor) {
+ setTimeout(function() {
+ if (sourceMode(editor)) editor.$area.select();
+ else execCommand(editor, "selectall");
+ }, 0);
+ }
+
+ // selectedHTML - returns the current HTML selection or and empty string
+ function selectedHTML(editor) {
+ restoreRange(editor);
+ var range = getRange(editor);
+ if (ie)
+ return range.htmlText;
+ var layer = $("<layer>")[0];
+ layer.appendChild(range.cloneContents());
+ var html = layer.innerHTML;
+ layer = null;
+ return html;
+ }
+
+ // selectedText - returns the current text selection or and empty string
+ function selectedText(editor) {
+ restoreRange(editor);
+ if (ie) return getRange(editor).text;
+ return getSelection(editor).toString();
+ }
+
+ // showMessage - alert replacement
+ function showMessage(editor, message, button) {
+ var popup = createPopup("msg", editor.options, MSG_CLASS);
+ popup.innerHTML = message;
+ showPopup(editor, popup, button);
+ }
+
+ // showPopup - shows a popup
+ function showPopup(editor, popup, button) {
+
+ var offset, left, top, $popup = $(popup);
+
+ // Determine the popup location
+ if (button) {
+ var $button = $(button);
+ offset = $button.offset();
+ left = --offset.left;
+ top = offset.top + $button.height();
+ }
+ else {
+ var $toolbar = editor.$toolbar;
+ offset = $toolbar.offset();
+ left = Math.floor(($toolbar.width() - $popup.width()) / 2) + offset.left;
+ top = offset.top + $toolbar.height() - 2;
+ }
+
+ // Position and show the popup
+ hidePopups();
+ $popup.css({left: left, top: top})
+ .show();
+
+ // Assign the popup button and click event handler
+ if (button) {
+ $.data(popup, BUTTON, button);
+ $popup.bind(CLICK, {popup: popup}, $.proxy(popupClick, editor));
+ }
+
+ // Focus the first input element if any
+ setTimeout(function() {
+ $popup.find(":text,textarea").eq(0).focus().select();
+ }, 100);
+
+ }
+
+ // sourceMode - returns true if the textarea is showing
+ function sourceMode(editor) {
+ return editor.$area.is(":visible");
+ }
+
+ // updateFrame - updates the iframe with the textarea contents
+ function updateFrame(editor, checkForChange) {
+
+ var code = editor.$area.val(),
+ options = editor.options,
+ updateFrameCallback = options.updateFrame,
+ $body = $(editor.doc.body);
+
+ // Check for textarea change to avoid unnecessary firing
+ // of potentially heavy updateFrame callbacks.
+ if (updateFrameCallback) {
+ var sum = checksum(code);
+ if (checkForChange && editor.areaChecksum == sum)
+ return;
+ editor.areaChecksum = sum;
+ }
+
+ // Convert the textarea source code into iframe html
+ var html = updateFrameCallback ? updateFrameCallback(code) : code;
+
+ // Prevent script injection attacks by html encoding script tags
+ html = html.replace(/<(?=\/?script)/ig, "<");
+
+ // Update the iframe checksum
+ if (options.updateTextArea)
+ editor.frameChecksum = checksum(html);
+
+ // Update the iframe and trigger the change event
+ if (html != $body.html()) {
+ $body.html(html);
+ $(editor).triggerHandler(CHANGE);
+ }
+
+ }
+
+ // updateTextArea - updates the textarea with the iframe contents
+ function updateTextArea(editor, checkForChange) {
+
+ var html = $(editor.doc.body).html(),
+ options = editor.options,
+ updateTextAreaCallback = options.updateTextArea,
+ $area = editor.$area;
+
+ // Check for iframe change to avoid unnecessary firing
+ // of potentially heavy updateTextArea callbacks.
+ if (updateTextAreaCallback) {
+ var sum = checksum(html);
+ if (checkForChange && editor.frameChecksum == sum)
+ return;
+ editor.frameChecksum = sum;
+ }
+
+ // Convert the iframe html into textarea source code
+ var code = updateTextAreaCallback ? updateTextAreaCallback(html) : html;
+
+ // Update the textarea checksum
+ if (options.updateFrame)
+ editor.areaChecksum = checksum(code);
+
+ // Update the textarea and trigger the change event
+ if (code != $area.val()) {
+ $area.val(code);
+ $(editor).triggerHandler(CHANGE);
+ }
+
+ }
+
+})(jQuery);
diff --git a/addons/web/static/lib/cleditor/jquery.cleditor.min.js b/addons/web/static/lib/cleditor/jquery.cleditor.min.js new file mode 100644 index 00000000000..5afec048867 --- /dev/null +++ b/addons/web/static/lib/cleditor/jquery.cleditor.min.js @@ -0,0 +1,31 @@ +/* + CLEditor WYSIWYG HTML Editor v1.3.0 + http://premiumsoftware.net/cleditor + requires jQuery v1.4.2 or later + + Copyright 2010, Chris Landowski, Premium Software, LLC + Dual licensed under the MIT or GPL Version 2 licenses. +*/ +(function(e){function aa(a){var b=this,c=a.target,d=e.data(c,x),h=s[d],f=h.popupName,i=p[f];if(!(b.disabled||e(c).attr(n)==n)){var g={editor:b,button:c,buttonName:d,popup:i,popupName:f,command:h.command,useCSS:b.options.useCSS};if(h.buttonClick&&h.buttonClick(a,g)===false)return false;if(d=="source"){if(t(b)){delete b.range;b.$area.hide();b.$frame.show();c.title=h.title}else{b.$frame.hide();b.$area.show();c.title="Show Rich Text"}setTimeout(function(){u(b)},100)}else if(!t(b))if(f){var j=e(i);if(f== +"url"){if(d=="link"&&M(b)===""){z(b,"A selection is required when inserting a link.",c);return false}j.children(":button").unbind(q).bind(q,function(){var k=j.find(":text"),o=e.trim(k.val());o!==""&&v(b,g.command,o,null,g.button);k.val("http://");r();w(b)})}else f=="pastetext"&&j.children(":button").unbind(q).bind(q,function(){var k=j.find("textarea"),o=k.val().replace(/\n/g,"<br />");o!==""&&v(b,g.command,o,null,g.button);k.val("");r();w(b)});if(c!==e.data(i,A)){N(b,i,c);return false}return}else if(d== +"print")b.$frame[0].contentWindow.print();else if(!v(b,g.command,g.value,g.useCSS,c))return false;w(b)}}function O(a){a=e(a.target).closest("div");a.css(H,a.data(x)?"#FFF":"#FFC")}function P(a){e(a.target).closest("div").css(H,"transparent")}function ba(a){var b=a.data.popup,c=a.target;if(!(b===p.msg||e(b).hasClass(B))){var d=e.data(b,A),h=e.data(d,x),f=s[h],i=f.command,g,j=this.options.useCSS;if(h=="font")g=c.style.fontFamily.replace(/"/g,"");else if(h=="size"){if(c.tagName=="DIV")c=c.children[0]; +g=c.innerHTML}else if(h=="style")g="<"+c.tagName+">";else if(h=="color")g=Q(c.style.backgroundColor);else if(h=="highlight"){g=Q(c.style.backgroundColor);if(l)i="backcolor";else j=true}b={editor:this,button:d,buttonName:h,popup:b,popupName:f.popupName,command:i,value:g,useCSS:j};if(!(f.popupClick&&f.popupClick(a,b)===false)){if(b.command&&!v(this,b.command,b.value,b.useCSS,d))return false;r();w(this)}}}function C(a){for(var b=1,c=0,d=0;d<a.length;++d){b=(b+a.charCodeAt(d))%65521;c=(c+b)%65521}return c<< +16|b}function R(a,b,c,d,h){if(p[a])return p[a];var f=e(m).hide().addClass(ca).appendTo("body");if(d)f.html(d);else if(a=="color"){b=b.colors.split(" ");b.length<10&&f.width("auto");e.each(b,function(i,g){e(m).appendTo(f).css(H,"#"+g)});c=da}else if(a=="font")e.each(b.fonts.split(","),function(i,g){e(m).appendTo(f).css("fontFamily",g).html(g)});else if(a=="size")e.each(b.sizes.split(","),function(i,g){e(m).appendTo(f).html("<font size="+g+">"+g+"</font>")});else if(a=="style")e.each(b.styles,function(i, +g){e(m).appendTo(f).html(g[1]+g[0]+g[1].replace("<","</"))});else if(a=="url"){f.html('Enter URL:<br><input type=text value="http://" size=35><br><input type=button value="Submit">');c=B}else if(a=="pastetext"){f.html("Paste your content here and click submit.<br /><textarea cols=40 rows=3></textarea><br /><input type=button value=Submit>");c=B}if(!c&&!d)c=S;f.addClass(c);l&&f.attr(I,"on").find("div,font,p,h1,h2,h3,h4,h5,h6").attr(I,"on");if(f.hasClass(S)||h===true)f.children().hover(O,P);p[a]=f[0]; +return f[0]}function T(a,b){if(b){a.$area.attr(n,n);a.disabled=true}else{a.$area.removeAttr(n);delete a.disabled}try{if(l)a.doc.body.contentEditable=!b;else a.doc.designMode=!b?"on":"off"}catch(c){}u(a)}function v(a,b,c,d,h){D(a);if(!l){if(d===undefined||d===null)d=a.options.useCSS;a.doc.execCommand("styleWithCSS",0,d.toString())}d=true;var f;if(l&&b.toLowerCase()=="inserthtml")y(a).pasteHTML(c);else{try{d=a.doc.execCommand(b,0,c||null)}catch(i){f=i.description;d=false}d||("cutcopypaste".indexOf(b)> +-1?z(a,"For security reasons, your browser does not support the "+b+" command. Try using the keyboard shortcut or context menu instead.",h):z(a,f?f:"Error executing the "+b+" command.",h))}u(a);return d}function w(a){setTimeout(function(){t(a)?a.$area.focus():a.$frame[0].contentWindow.focus();u(a)},0)}function y(a){if(l)return J(a).createRange();return J(a).getRangeAt(0)}function J(a){if(l)return a.doc.selection;return a.$frame[0].contentWindow.getSelection()}function Q(a){var b=/rgba?\((\d+), (\d+), (\d+)/.exec(a), +c=a.split("");if(b)for(a=(b[1]<<16|b[2]<<8|b[3]).toString(16);a.length<6;)a="0"+a;return"#"+(a.length==6?a:c[1]+c[1]+c[2]+c[2]+c[3]+c[3])}function r(){e.each(p,function(a,b){e(b).hide().unbind(q).removeData(A)})}function U(){var a=e("link[href$='jquery.cleditor.css']").attr("href");return a.substr(0,a.length-19)+"images/"}function K(a){var b=a.$main,c=a.options;a.$frame&&a.$frame.remove();var d=a.$frame=e('<iframe frameborder="0" src="javascript:true;">').hide().appendTo(b),h=d[0].contentWindow,f= +a.doc=h.document,i=e(f);f.open();f.write(c.docType+"<html>"+(c.docCSSFile===""?"":'<head><link rel="stylesheet" type="text/css" href="'+c.docCSSFile+'" /></head>')+'<body style="'+c.bodyStyle+'"></body></html>');f.close();l&&i.click(function(){w(a)});E(a);if(l){i.bind("beforedeactivate beforeactivate selectionchange keypress",function(g){if(g.type=="beforedeactivate")a.inactive=true;else if(g.type=="beforeactivate"){!a.inactive&&a.range&&a.range.length>1&&a.range.shift();delete a.inactive}else if(!a.inactive){if(!a.range)a.range= +[];for(a.range.unshift(y(a));a.range.length>2;)a.range.pop()}});d.focus(function(){D(a)})}(e.browser.mozilla?i:e(h)).blur(function(){V(a,true)});i.click(r).bind("keyup mouseup",function(){u(a)});L?a.$area.show():d.show();e(function(){var g=a.$toolbar,j=g.children("div:last"),k=b.width();j=j.offset().top+j.outerHeight()-g.offset().top+1;g.height(j);j=(/%/.test(""+c.height)?b.height():parseInt(c.height))-j;d.width(k).height(j);a.$area.width(k).height(ea?j-2:j);T(a,a.disabled);u(a)})}function u(a){if(!L&& +e.browser.webkit&&!a.focused){a.$frame[0].contentWindow.focus();window.focus();a.focused=true}var b=a.doc;if(l)b=y(a);var c=t(a);e.each(a.$toolbar.find("."+W),function(d,h){var f=e(h),i=e.cleditor.buttons[e.data(h,x)],g=i.command,j=true;if(a.disabled)j=false;else if(i.getEnabled){j=i.getEnabled({editor:a,button:h,buttonName:i.name,popup:p[i.popupName],popupName:i.popupName,command:i.command,useCSS:a.options.useCSS});if(j===undefined)j=true}else if((c||L)&&i.name!="source"||l&&(g=="undo"||g=="redo"))j= +false;else if(g&&g!="print"){if(l&&g=="hilitecolor")g="backcolor";if(!l||g!="inserthtml")try{j=b.queryCommandEnabled(g)}catch(k){j=false}}if(j){f.removeClass(X);f.removeAttr(n)}else{f.addClass(X);f.attr(n,n)}})}function D(a){l&&a.range&&a.range[0].select()}function M(a){D(a);if(l)return y(a).text;return J(a).toString()}function z(a,b,c){var d=R("msg",a.options,fa);d.innerHTML=b;N(a,d,c)}function N(a,b,c){var d,h,f=e(b);if(c){var i=e(c);d=i.offset();h=--d.left;d=d.top+i.height()}else{i=a.$toolbar; +d=i.offset();h=Math.floor((i.width()-f.width())/2)+d.left;d=d.top+i.height()-2}r();f.css({left:h,top:d}).show();if(c){e.data(b,A,c);f.bind(q,{popup:b},e.proxy(ba,a))}setTimeout(function(){f.find(":text,textarea").eq(0).focus().select()},100)}function t(a){return a.$area.is(":visible")}function E(a,b){var c=a.$area.val(),d=a.options,h=d.updateFrame,f=e(a.doc.body);if(h){var i=C(c);if(b&&a.areaChecksum==i)return;a.areaChecksum=i}c=h?h(c):c;c=c.replace(/<(?=\/?script)/ig,"<");if(d.updateTextArea)a.frameChecksum= +C(c);if(c!=f.html()){f.html(c);e(a).triggerHandler(F)}}function V(a,b){var c=e(a.doc.body).html(),d=a.options,h=d.updateTextArea,f=a.$area;if(h){var i=C(c);if(b&&a.frameChecksum==i)return;a.frameChecksum=i}c=h?h(c):c;if(d.updateFrame)a.areaChecksum=C(c);if(c!=f.val()){f.val(c);e(a).triggerHandler(F)}}e.cleditor={defaultOptions:{width:500,height:250,controls:"bold italic underline strikethrough subscript superscript | font size style | color highlight removeformat | bullets numbering | outdent indent | alignleft center alignright justify | undo redo | rule image link unlink | cut copy paste pastetext | print source", +colors:"FFF FCC FC9 FF9 FFC 9F9 9FF CFF CCF FCF CCC F66 F96 FF6 FF3 6F9 3FF 6FF 99F F9F BBB F00 F90 FC6 FF0 3F3 6CC 3CF 66C C6C 999 C00 F60 FC3 FC0 3C0 0CC 36F 63F C3C 666 900 C60 C93 990 090 399 33F 60C 939 333 600 930 963 660 060 366 009 339 636 000 300 630 633 330 030 033 006 309 303",fonts:"Arial,Arial Black,Comic Sans MS,Courier New,Narrow,Garamond,Georgia,Impact,Sans Serif,Serif,Tahoma,Trebuchet MS,Verdana",sizes:"1,2,3,4,5,6,7",styles:[["Paragraph","<p>"],["Header 1","<h1>"],["Header 2","<h2>"], +["Header 3","<h3>"],["Header 4","<h4>"],["Header 5","<h5>"],["Header 6","<h6>"]],useCSS:false,docType:'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',docCSSFile:"",bodyStyle:"margin:4px; font:10pt Arial,Verdana; cursor:text"},buttons:{init:"bold,,|italic,,|underline,,|strikethrough,,|subscript,,|superscript,,|font,,fontname,|size,Font Size,fontsize,|style,,formatblock,|color,Font Color,forecolor,|highlight,Text Highlight Color,hilitecolor,color|removeformat,Remove Formatting,|bullets,,insertunorderedlist|numbering,,insertorderedlist|outdent,,|indent,,|alignleft,Align Text Left,justifyleft|center,,justifycenter|alignright,Align Text Right,justifyright|justify,,justifyfull|undo,,|redo,,|rule,Insert Horizontal Rule,inserthorizontalrule|image,Insert Image,insertimage,url|link,Insert Hyperlink,createlink,url|unlink,Remove Hyperlink,|cut,,|copy,,|paste,,|pastetext,Paste as Text,inserthtml,|print,,|source,Show Source"}, +imagesPath:function(){return U()}};e.fn.cleditor=function(a){var b=e([]);this.each(function(c,d){if(d.tagName=="TEXTAREA"){var h=e.data(d,Y);h||(h=new cleditor(d,a));b=b.add(h)}});return b};var H="backgroundColor",A="button",x="buttonName",F="change",Y="cleditor",q="click",n="disabled",m="<div>",I="unselectable",W="cleditorButton",X="cleditorDisabled",ca="cleditorPopup",S="cleditorList",da="cleditorColor",B="cleditorPrompt",fa="cleditorMsg",l=e.browser.msie,ea=/msie\s6/i.test(navigator.userAgent), +L=/iphone|ipad|ipod/i.test(navigator.userAgent),p={},Z,s=e.cleditor.buttons;e.each(s.init.split("|"),function(a,b){var c=b.split(","),d=c[0];s[d]={stripIndex:a,name:d,title:c[1]===""?d.charAt(0).toUpperCase()+d.substr(1):c[1],command:c[2]===""?d:c[2],popupName:c[3]===""?d:c[3]}});delete s.init;cleditor=function(a,b){var c=this;c.options=b=e.extend({},e.cleditor.defaultOptions,b);var d=c.$area=e(a).hide().data(Y,c).blur(function(){E(c,true)}),h=c.$main=e(m).addClass("cleditorMain").width(b.width).height(b.height), +f=c.$toolbar=e(m).addClass("cleditorToolbar").appendTo(h),i=e(m).addClass("cleditorGroup").appendTo(f);e.each(b.controls.split(" "),function(g,j){if(j==="")return true;if(j=="|"){e(m).addClass("cleditorDivider").appendTo(i);i=e(m).addClass("cleditorGroup").appendTo(f)}else{var k=s[j],o=e(m).data(x,k.name).addClass(W).attr("title",k.title).bind(q,e.proxy(aa,c)).appendTo(i).hover(O,P),G={};if(k.css)G=k.css;else if(k.image)G.backgroundImage="url("+U()+k.image+")";if(k.stripIndex)G.backgroundPosition= +k.stripIndex*-24;o.css(G);l&&o.attr(I,"on");k.popupName&&R(k.popupName,b,k.popupClass,k.popupContent,k.popupHover)}});h.insertBefore(d).append(d);if(!Z){e(document).click(function(g){g=e(g.target);g.add(g.parents()).is("."+B)||r()});Z=true}/auto|%/.test(""+b.width+b.height)&&e(window).resize(function(){K(c)});K(c)};var $=cleditor.prototype;e.each([["clear",function(a){a.$area.val("");E(a)}],["disable",T],["execCommand",v],["focus",w],["hidePopups",r],["sourceMode",t,true],["refresh",K],["select", +function(a){setTimeout(function(){t(a)?a.$area.select():v(a,"selectall")},0)}],["selectedHTML",function(a){D(a);a=y(a);if(l)return a.htmlText;var b=e("<layer>")[0];b.appendChild(a.cloneContents());return b.innerHTML},true],["selectedText",M,true],["showMessage",z],["updateFrame",E],["updateTextArea",V]],function(a,b){$[b[0]]=function(){for(var c=[this],d=0;d<arguments.length;d++)c.push(arguments[d]);c=b[1].apply(this,c);if(b[2])return c;return this}});$.change=function(a){var b=e(this);return a?b.bind(F, +a):b.trigger(F)}})(jQuery);
\ No newline at end of file diff --git a/addons/web/static/lib/jquery.textext/jquery.textext.css b/addons/web/static/lib/jquery.textext/jquery.textext.css index fe144e48af6..f180ee66184 100644 --- a/addons/web/static/lib/jquery.textext/jquery.textext.css +++ b/addons/web/static/lib/jquery.textext/jquery.textext.css @@ -65,10 +65,6 @@ padding: 3px 5px; cursor: pointer; } -.text-core .text-wrap .text-dropdown .text-list .text-suggestion em { - font-style: normal; - text-decoration: underline; -} .text-core .text-wrap .text-dropdown .text-list .text-suggestion.text-selected { color: #fff; background: #6d84b4; diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index f92d5cbf1c2..2e26de30d5f 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -1,4 +1,4 @@ -@charset "utf-8"; +@charset "UTF-8"; @font-face { font-family: "mnmliconsRegular"; src: url("/web/static/src/font/mnmliconsv21-webfont.eot") format("eot"); @@ -188,13 +188,7 @@ } .openerp.ui-dialog { display: none; - position: fixed; padding: 6px; - top: 50%; - left: 50%; - z-index: 1050; - width: 560px; - margin: -150px 0 0 -280px; background-color: rgba(60, 60, 60, 0.7); border: 1px solid; border-color: #888888 #555555 #444444; @@ -208,6 +202,9 @@ -moz-background-clip: padding-box; background-clip: padding-box; } +.openerp.ui-dialog .ui-dialog-content { + padding: 0px; +} .openerp.ui-dialog .ui-dialog-titlebar, .openerp.ui-dialog .ui-dialog-content, .openerp.ui-dialog .ui-dialog-buttonpane { padding: 16px; } @@ -237,14 +234,16 @@ .openerp.ui-dialog .ui-dialog-buttonpane { border-top: 1px solid #e0e0e0; background: #f5f7f9; - padding: 8px; margin: 0; -moz-border-radius: 0 0 2px 2px; -webkit-border-radius: 0 0 2px 2px; border-radius: 0 0 2px 2px; } .openerp.ui-dialog .ui-dialog-buttonpane button { - margin-left: 8px; + margin: 0; +} +.openerp.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { + float: left; } .openerp.ui-dialog .ui-dialog-titlebar-close { padding: 0; @@ -268,6 +267,9 @@ color: black; text-decoration: none; } +.openerp.ui-dialog.oe_act_window .ui-dialog-content { + padding: 0px; +} .openerp .modal-backdrop { position: fixed; top: 0; @@ -308,6 +310,7 @@ } .openerp .oe_fade { color: #888888; + font-weight: normal; } .openerp .oe_bold { font-weight: bold; @@ -376,7 +379,8 @@ background: #ed6f6a; } .openerp .oe_title { - width: 60%; + width: 50%; + float: left; } .openerp .oe_title:after { content: "."; @@ -386,17 +390,18 @@ visibility: hidden; } .openerp .oe_button_box { - width: 38%; + width: 270px; text-align: right; } .openerp .oe_button_box button { margin: 4px; } .openerp .oe_avatar { - margin: 0 16px 0 0; + margin: 0 6px 15px 0; } -.openerp .oe_avatar img { - height: 50px; +.openerp .oe_avatar > img { + height: 90px; + max-width: 100px; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; @@ -405,6 +410,9 @@ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); border: none; } +.openerp .oe_avatar + div { + margin-left: 5px; +} .openerp .oe_button.oe_link { border: none; padding: 0; @@ -450,6 +458,29 @@ .openerp .oe_webclient .oe_star_on { color: gold; } +.openerp .oe_tag { + border-radius: 2px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + border: 1px solid #9daccc; + background: #e2e6f0; + color: black !important; + padding: 0px 3px 0px 3px; + margin: 0 2px 2px 0; + height: 16px; +} +.openerp .oe_tags .text-wrap { + width: 100% !important; +} +.openerp .oe_tags .text-wrap textarea { + width: 100% !important; +} +.openerp .oe_tags .text-core .text-wrap .text-dropdown .text-list .text-suggestion em { + font-style: italic; + text-decoration: none; +} .openerp.oe_tooltip { font-size: 12px; } @@ -1136,63 +1167,63 @@ .openerp .oe_view_manager .oe_view_manager_view_kanban { height: inherit; } -.openerp .oe_view_manager .oe_view_manager_header { +.openerp .oe_view_manager table.oe_view_manager_header { width: 100%; + table-layout: fixed; } -.openerp .oe_view_manager .oe_view_manager_header .oe_header_row { +.openerp .oe_view_manager table.oe_view_manager_header .oe_header_row { clear: both; text-shadow: 0 1px 1px white; } -.openerp .oe_view_manager .oe_view_manager_header .oe_header_row:last-child td { +.openerp .oe_view_manager table.oe_view_manager_header .oe_header_row:last-child td { padding-top: 0; } -.openerp .oe_view_manager .oe_view_manager_header .oe_view_manager_sidebar { +.openerp .oe_view_manager table.oe_view_manager_header .oe_view_manager_sidebar { margin: 0px auto; - width: 400px; text-align: center; } -.openerp .oe_view_manager .oe_view_manager_header td { +.openerp .oe_view_manager table.oe_view_manager_header td { line-height: 26px; } -.openerp .oe_view_manager .oe_view_manager_header h2 { +.openerp .oe_view_manager table.oe_view_manager_header h2 { font-size: 18px; margin: 0; float: left; } -.openerp .oe_view_manager .oe_view_manager_header h2 a { +.openerp .oe_view_manager table.oe_view_manager_header h2 a { color: #8a89ba; } -.openerp .oe_view_manager .oe_view_manager_header .oe_button_group { +.openerp .oe_view_manager table.oe_view_manager_header .oe_button_group { display: inline-block; border: 1px solid #ababab; -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; } -.openerp .oe_view_manager .oe_view_manager_header .oe_button_group li { +.openerp .oe_view_manager table.oe_view_manager_header .oe_button_group li { float: left; border-right: 1px solid #ababab; } -.openerp .oe_view_manager .oe_view_manager_header .oe_button_group li:last-child { +.openerp .oe_view_manager table.oe_view_manager_header .oe_button_group li:last-child { border: none; } -.openerp .oe_view_manager .oe_view_manager_header .oe_button_group a { +.openerp .oe_view_manager table.oe_view_manager_header .oe_button_group a { color: #4c4c4c; } -.openerp .oe_view_manager .oe_view_manager_header .oe_button_group a:hover { +.openerp .oe_view_manager table.oe_view_manager_header .oe_button_group a:hover { text-decoration: none; } -.openerp .oe_view_manager .oe_view_manager_header .oe_button_group .active { +.openerp .oe_view_manager table.oe_view_manager_header .oe_button_group .active { background: #999999; -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) inset; -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) inset; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) inset; } -.openerp .oe_view_manager .oe_view_manager_header .oe_button_group .active a { +.openerp .oe_view_manager table.oe_view_manager_header .oe_button_group .active a { color: white; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4); } -.openerp .oe_view_manager .oe_view_manager_header .oe_view_manager_buttons { +.openerp .oe_view_manager table.oe_view_manager_header .oe_view_manager_buttons { white-space: nowrap; } .openerp .oe_view_manager .oe_view_manager_pager { @@ -1319,7 +1350,7 @@ float: right; padding: 1px 0; line-height: 18px; - width: 480px; + width: 400px; border: 1px solid #ababab; background: white; -moz-border-radius: 13px; @@ -1741,12 +1772,12 @@ width: auto; } .openerp .oe_form_nosheet { - margin-left: 10px; - margin-right: 10px; + margin: 20px; } .openerp .oe_form_nosheet > header { - margin-left: -10px; - margin-right: -10px; + margin-top: -20px; + margin-left: -20px; + margin-right: -20px; } .openerp .oe_form header { position: relative; @@ -1765,7 +1796,7 @@ display: inline-block; float: right; } -.openerp .oe_form footer { +.openerp .oe_form div.oe_chatter { min-width: 650px; max-width: 860px; margin: 0 auto; @@ -1817,17 +1848,21 @@ .openerp .oe_form .oe_subtotal_footer td.oe_form_group_cell_label { border-right: none; } -.openerp .oe_form .oe_subtotal_footer .oe_form_field { - width: auto !important; -} .openerp .oe_form .oe_subtotal_footer .oe_subtotal_footer_separator { + width: 108px; border-top: 1px solid #cacaca; - font-sie: 120%; font-weight: bold; + font-size: 18px; +} +.openerp .oe_form .oe_subtotal_footer label:after { + content: ":"; } .openerp .oe_form .oe_subtotal_footer label.oe_subtotal_footer_separator { font-weight: bold !important; - padding: 2px 8px 2px 0px !important; + padding: 2px 11px 2px 0px !important; +} +.openerp .oe_form .oe_subtotal_footer label.oe_form_label_help { + font-weight: normal; } .openerp .oe_application .oe_form_sheetbg { background: url(/web/static/src/img/form_sheetbg.png); @@ -1854,6 +1889,9 @@ .openerp .oe_application .oe_form_sheet .oe_notebook_page { padding: 0 16px; } +.openerp .oe_form .oe_form_button { + margin: 2px; +} .openerp .oe_form td.oe_form_group_cell_label { border-right: 1px solid #dddddd; padding: 2px 0px 2px 0px; @@ -1861,17 +1899,17 @@ .openerp .oe_form td.oe_form_group_cell_label label { line-height: 18px; display: block; - min-width: 110px; + min-width: 120px; } .openerp .oe_form td.oe_form_group_cell + .oe_form_group_cell { padding-left: 6px; } .openerp .oe_form .oe_form_group { width: 100%; - margin: 4px 0 4px 0; + margin: 6px 0 6px 0; } -.openerp .oe_form .oe_form_group .oe_group_right > tbody > tr > td:first-child { - padding-left: 18px; +.openerp .oe_form .oe_form_group .oe_form_group_cell.oe_group_right { + padding-left: 20px; } .openerp .oe_form .oe_form_label_help[for], .openerp .oe_form .oe_form_label[for] { font-weight: bold; @@ -1941,15 +1979,6 @@ .openerp .oe_form .oe_form_field_text.oe_inline, .openerp .oe_form .oe_form_field_text.oe_inline > textarea { width: 500px; } -.openerp .oe_form .oe_form_field_float input { - width: 100px; -} -.openerp .oe_form h1 .oe_form_field_float input { - width: 140px; -} -.openerp .oe_form h2 .oe_form_field_float input { - width: 120px; -} .openerp .oe_form h1, .openerp .oe_form h2, .openerp .oe_form h3, .openerp .oe_form h4, .openerp .oe_form h5, .openerp .oe_form h6 { margin: 0 0 4px 0; } @@ -1966,18 +1995,6 @@ .openerp .oe_form .oe_form_field input { margin: 0px; } -.openerp .oe_form .oe_form_field_integer { - width: 180px; -} -.openerp .oe_form .oe_form_field_float { - width: 180px; -} -.openerp .oe_form .oe_form_field_date { - width: 7.5em; -} -.openerp .oe_form .oe_form_field_datetime { - width: 11em; -} .openerp .oe_form input[type="text"], .openerp .oe_form input[type="password"], .openerp .oe_form input[type="file"], .openerp .oe_form select { height: 22px; padding-top: 2px; @@ -2017,32 +2034,6 @@ padding-top: 4px; width: auto; } -.openerp .oe_form .oe_form_field_many2manytags .text-wrap { - width: 100% !important; -} -.openerp .oe_form .oe_form_field_many2manytags .text-wrap textarea { - width: 100% !important; -} -.openerp .oe_form .oe_form_field_many2manytags .oe_form_field_many2manytags_box { - border-radius: 2px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; - position: relative; - float: left; - border: 1px solid #9daccc; - background: #e2e6f0; - color: black; - padding: 0px 3px 0px 3px; - margin: 0 2px 2px 0; - height: 16px; - font: 11px "lucida grande", tahoma, verdana, arial, sans-serif; -} -.openerp .oe_form .oe_form_field_many2manytags .text-core .text-wrap .text-dropdown .text-list .text-suggestion em { - font-style: italic; - text-decoration: none; -} .openerp .oe_form .oe_datepicker_container { display: none; } @@ -2072,15 +2063,6 @@ .openerp .oe_form .oe_form_field_with_button.oe_no_button > .oe_button { display: none; } -.openerp .oe_form .oe_form_field_with_button:not(.oe_no_button) input { - border-right: none; - -webkit-border-top-right-radius: 0px; - -webkit-border-bottom-right-radius: 0px; - -moz-border-radius-topright: 0px; - -moz-border-radius-bottomright: 0px; - border-top-right-radius: 0px; - border-bottom-right-radius: 0px; -} .openerp .oe_form .oe_form_field_with_button:not(.oe_no_button) > .oe_button { float: right; -moz-border-radius: 0; @@ -2096,6 +2078,18 @@ position: relative; overflow: hidden; } +.openerp .oe_form_editable .oe_form .oe_form_field_integer { + width: 7em !important; +} +.openerp .oe_form_editable .oe_form .oe_form_field_float { + width: 8em !important; +} +.openerp .oe_form_editable .oe_form .oe_form_field_date { + width: 7.5em !important; +} +.openerp .oe_form_editable .oe_form .oe_form_field_datetime { + width: 11.5em !important; +} .openerp .oe_hidden_input_file { overflow: hidden; position: relative; @@ -2125,6 +2119,7 @@ } .openerp .oe_form .oe_form_field_image .oe_form_field_image_controls { position: absolute; + white-space: nowrap; top: 1px; padding: 3px 0 0 0; margin: 0 1px; @@ -2146,33 +2141,42 @@ } .openerp .oe_form_field_many2one span.oe_m2o_drop_down_button { position: absolute; - top: 1px; + top: 2px; right: 0px; } +.openerp .oe_form_field_many2one .oe_m2o_cm_button { + line-height: 14px; +} .openerp .oe_form .oe_form_field_one2many > .oe_view_manager .oe_list_pager_single_page { display: none; } -.openerp .oe_form_field_one2many .oe_list .oe_list_edit_row_save { +.openerp .oe_form_field_one2many .oe_list_content > thead, .openerp .oe_form_field_many2many .oe_list_content > thead { + border-bottom: 1px; +} +.openerp .oe_form_field_one2many .oe_list_content > tbody tr:nth-child(odd), .openerp .oe_form_field_many2many .oe_list_content > tbody tr:nth-child(odd) { + background: transparent; +} +.openerp .oe_form_field_one2many .oe_list .oe_list_edit_row_save, .openerp .oe_form_field_many2many .oe_list .oe_list_edit_row_save { background: url(/web/static/src/img/iconset-b-remove.png) 50% 50% no-repeat; } -.openerp .oe_form_field_one2many .oe_list .oe_list_edit_row_save:before { +.openerp .oe_form_field_one2many .oe_list .oe_list_edit_row_save:before, .openerp .oe_form_field_many2many .oe_list .oe_list_edit_row_save:before { visibility: hidden; } -.openerp .oe_form_field_one2many > .oe_view_manager .oe_header_row_top { +.openerp .oe_form_field_one2many > .oe_view_manager .oe_header_row_top, .openerp .oe_form_field_many2many > .oe_view_manager .oe_header_row_top { display: none; } -.openerp .oe_form_field_one2many > .oe_view_manager .oe_view_manager_header2 td { +.openerp .oe_form_field_one2many > .oe_view_manager .oe_view_manager_header2 td, .openerp .oe_form_field_many2many > .oe_view_manager .oe_view_manager_header2 td { padding: 0px 8px; line-height: 16px; } -.openerp .oe_form_field_one2many > .oe_view_manager .oe_view_manager_header2 td .oe_i { +.openerp .oe_form_field_one2many > .oe_view_manager .oe_view_manager_header2 td .oe_i, .openerp .oe_form_field_many2many > .oe_view_manager .oe_view_manager_header2 td .oe_i { font-size: 13px; } -.openerp .oe_form_field_one2many > .oe_view_manager .oe_view_manager_header2 td .oe_pager_group { +.openerp .oe_form_field_one2many > .oe_view_manager .oe_view_manager_header2 td .oe_pager_group, .openerp .oe_form_field_many2many > .oe_view_manager .oe_view_manager_header2 td .oe_pager_group { height: auto; line-height: 16px; } -.openerp .oe_form_field_one2many > .oe_view_manager .oe_view_manager_header2 td .oe_pager_group li { +.openerp .oe_form_field_one2many > .oe_view_manager .oe_view_manager_header2 td .oe_pager_group li, .openerp .oe_form_field_many2many > .oe_view_manager .oe_view_manager_header2 td .oe_pager_group li { height: auto; line-height: 16px; } @@ -2209,6 +2213,10 @@ .openerp .oe_list_content td:first-child:after, .openerp .oe_list_content th:first-child:after { border-width: 0; } +.openerp .oe_list_content td.oe_number { + text-align: right !important; + max-width: 100px; +} .openerp .oe_list_content > thead { border-bottom: 2px solid #cacaca; background: #eeeeee; @@ -2258,8 +2266,8 @@ padding: 3px 6px; white-space: pre-line; } -.openerp .oe_list_content > tbody > tr > td, .openerp .oe_list_content > tbody > tr > th { - line-height: 18px; +.openerp .oe_list_content > tbody > tr > td.oe_list_field_cell progress { + width: 100%; } .openerp .oe_list_content > tbody > tr > td > button, .openerp .oe_list_content > tbody > tr > th > button { border: none; @@ -2275,9 +2283,6 @@ .openerp .oe_list_content > tbody > tr > td.oe_list_checkbox:first-child:after, .openerp .oe_list_content > tbody > tr th.oe_list_checkbox:first-child:after { border-width: 0; } -.openerp .oe_list_content > tbody > tr > td.oe_number { - text-align: right !important; -} .openerp .oe_list_content > tbody > tr:nth-child(odd) { background-color: #f0f0fa; background-color: #f0f0fa; @@ -2375,6 +2380,59 @@ color: #333333; } +.openerp .tree_header { + background-color: #f0f0f0; + border-bottom: 1px solid #cacaca; + color: #4c4c4c; + padding: 5px; + height: 25px; +} +.openerp .tree_header button { + float: right; + height: 27px; + margin-right: 5px; +} +.openerp .oe-treeview-table { + width: 100%; + background-color: white; + border-spacing: 0; +} +.openerp .oe-treeview-table th { + padding: 10px; + color: #4c4c4c; + font-weight: bold; + background-color: #f0f0f0; + border-bottom: 2px solid #cacaca; +} +.openerp .oe-treeview-table .treeview-tr, .openerp .oe-treeview-table .treeview-td { + cursor: pointer; + border-right: 1px dotted #afafb6; + vertical-align: top; + text-align: left; + border-bottom: 1px solid #cfcccc; +} +.openerp .oe-treeview-table tr:hover { + background-color: #e0e0f8; +} +.openerp .oe-treeview-table .oe-number { + text-align: right !important; +} +.openerp .oe-treeview-table span { + font-size: 90%; + font-weight: normal; + white-space: nowrap; + display: block; +} +.openerp .oe-treeview-table .treeview-tr.oe-treeview-first { + background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat; +} +.openerp .oe-treeview-table .oe_open .treeview-tr.oe-treeview-first { + background-image: url(/web/static/src/img/collapse.gif); +} +.openerp .oe-treeview-table .treeview-tr.oe-treeview-first span, .openerp .oe-treeview-table .treeview-td.oe-treeview-first span { + margin-left: 16px; +} + .kitten-mode-activated { background-image: url(http://placekitten.com/g/1365/769); background-size: cover; diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index 2ad33c8ca62..393716da1f4 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -204,13 +204,7 @@ $sheet-max-width: 860px // Modal box &.ui-dialog display: none - position: fixed padding: 6px - top: 50% - left: 50% - z-index: 1050 - width: 560px - margin: -150px 0 0 -280px //overflow: hidden background-color: rgba(60,60,60,0.7) border: 1px solid @@ -219,6 +213,8 @@ $sheet-max-width: 860px @include radius(8px) @include box-shadow(0 1px 12px rgba(0, 0, 0, 0.6)) @include background-clip() + .ui-dialog-content + padding: 0px .ui-dialog-titlebar, .ui-dialog-content, .ui-dialog-buttonpane padding: 16px .ui-dialog-titlebar @@ -235,11 +231,12 @@ $sheet-max-width: 860px .ui-dialog-buttonpane border-top: 1px solid #e0e0e0 background: #f5f7f9 - padding: 8px margin: 0 @include radius(0 0 2px 2px) button - margin-left: 8px + margin: 0 + .ui-dialog-buttonset + float: left .ui-dialog-titlebar-close padding: 0 .ui-icon-closethick @@ -259,6 +256,10 @@ $sheet-max-width: 860px color: black text-decoration: none + &.ui-dialog.oe_act_window + .ui-dialog-content + padding: 0px + .modal-backdrop position: fixed top: 0 @@ -293,6 +294,7 @@ $sheet-max-width: 860px cursor: wait .oe_fade color: #888 + font-weight: normal .oe_bold font-weight: bold .oe_inline @@ -321,7 +323,8 @@ $sheet-max-width: 860px &:hover background: #ED6F6A .oe_title - width: 60% + width: 50% + float: left .oe_title:after content: "." display: block @@ -329,17 +332,20 @@ $sheet-max-width: 860px clear: both visibility: hidden .oe_button_box - width: 38% + width: 270px text-align: right button margin: 4px .oe_avatar - margin: 0 16px 0 0 - img - height: 50px + margin: 0 6px 15px 0 + > img + height: 90px + max-width: 100px @include radius(3px) @include box-shadow(0 1px 3px rgba(0, 0, 0, 0.3)) border: none + .oe_avatar + div + margin-left: 5px .oe_button.oe_link @include reset() img @@ -361,8 +367,26 @@ $sheet-max-width: 860px text-decoration: none .oe_star_on color: gold - - //.oe_edit_only + // }}} + // Tags (for many2many tags, among others) {{{ + .oe_tag + border-radius: 2px + @include box-sizing(border) + border: 1px solid #9DACCC + background: #E2E6F0 + color: black !important + padding: 0px 3px 0px 3px + margin: 0 2px 2px 0 + height: 16px + // font: 11px "lucida grande", tahoma, verdana, arial, sans-serif + .oe_tags + .text-wrap + width: 100% !important + textarea + width: 100% !important + .text-core .text-wrap .text-dropdown .text-list .text-suggestion em + font-style: italic + text-decoration: none // }}} // Tooltips {{{ &.oe_tooltip @@ -822,7 +846,7 @@ $sheet-max-width: 860px text-shadow: 0 1px 1px rgba(0,0,0,0.2) @include radius(4px) @include box-shadow(inset 0 1px 1px rgba(0, 0, 0, 0.2)) - .oe_menu_counter + .oe_menu_counter float: right background: #8a89ba color: #eee @@ -845,7 +869,7 @@ $sheet-max-width: 860px color: $colour4 text-shadow: 0 1px 1px white @include box-shadow(0 1px 1px rgba(0, 0, 0, 0.2)) - .oe_menu_counter + .oe_menu_counter background: #eee color: #8a89ba .oe_menu_toggler:before @@ -887,8 +911,9 @@ $sheet-max-width: 860px .oe_view_manager_view_kanban height: inherit - .oe_view_manager_header + table.oe_view_manager_header width: 100% + table-layout: fixed .oe_header_row //min-height: 26px //line-height: 26px @@ -899,7 +924,6 @@ $sheet-max-width: 860px padding-top: 0 .oe_view_manager_sidebar margin: 0px auto - width: 400px text-align: center td line-height: 26px @@ -1032,7 +1056,7 @@ $sheet-max-width: 860px float: right padding: 1px 0 line-height: 18px - width: 480px + width: 400px border: 1px solid #ababab background: white @include radius(13px) @@ -1311,7 +1335,7 @@ $sheet-max-width: 860px margin: 0 0 0 4px padding: 0 - + // }}} // Views Common {{{ .oe_view_nocontent @@ -1355,25 +1379,25 @@ $sheet-max-width: 860px display: none !important .oe_form .oe_form_field_date width: auto - .oe_form_nosheet - margin-left: 10px - margin-right: 10px + .oe_form_nosheet + margin: 20px .oe_form_nosheet > header - margin-left: -10px - margin-right: -10px + margin-top: -20px + margin-left: -20px + margin-right: -20px // }}} // FormView.custom tags and classes {{{ - .oe_form + .oe_form header position: relative border-bottom: 1px solid #cacaca @include vertical-gradient(#fcfcfc, #dedede) padding: 0 8px - line-height: 30px + line-height: 30px ul display: inline-block float: right - footer + div.oe_chatter min-width: 650px max-width: $sheet-max-width margin: 0 auto @@ -1386,12 +1410,12 @@ $sheet-max-width: 860px vertical-align: top margin-left: 8px li - border-right: none + border-right: none padding: 0 margin: 0 - float: left + float: left vertical-align: top - height: 30px + height: 30px padding: 0 0 0 12px &:first-child border-left: 1px solid #cacaca @@ -1413,21 +1437,24 @@ $sheet-max-width: 860px padding: 0 !important td.oe_form_group_cell_label border-right: none - .oe_form_field - width: auto !important .oe_subtotal_footer_separator + width: 108px border-top: 1px solid #cacaca - font-sie: 120% font-weight: bold + font-size: 18px + label:after + content: ":" label.oe_subtotal_footer_separator font-weight: bold !important - padding: 2px 8px 2px 0px !important + padding: 2px 11px 2px 0px !important + label.oe_form_label_help + font-weight: normal // no sheet in popups .oe_application .oe_form_sheetbg background: url(/web/static/src/img/form_sheetbg.png) padding: 8px 0 - border-bottom: 1px solid #ddd + border-bottom: 1px solid #ddd .oe_form_sheet_width min-width: 650px max-width: $sheet-max-width @@ -1445,21 +1472,22 @@ $sheet-max-width: 860px // }}} // FormView.group {{{ .oe_form + .oe_form_button + margin: 2px td.oe_form_group_cell_label border-right: 1px solid #ddd padding: 2px 0px 2px 0px label line-height: 18px display: block - min-width: 110px + min-width: 120px td.oe_form_group_cell + .oe_form_group_cell padding-left: 6px .oe_form_group width: 100% - margin: 4px 0 4px 0 - .oe_group_right - > tbody > tr > td:first-child - padding-left: 18px + margin: 6px 0 6px 0 + .oe_form_group_cell.oe_group_right + padding-left: 20px // }}} // FormView.label {{{ .oe_form @@ -1520,12 +1548,6 @@ $sheet-max-width: 860px width: 100% .oe_form_field_text.oe_inline, .oe_form_field_text.oe_inline > textarea width: 500px - .oe_form_field_float input - width: 100px - h1 .oe_form_field_float input - width: 140px - h2 .oe_form_field_float input - width: 120px h1, h2, h3, h4, h5, h6 margin: 0 0 4px 0 input @@ -1538,14 +1560,6 @@ $sheet-max-width: 860px line-height: 18px input margin: 0px - .oe_form_field_integer - width: 180px - .oe_form_field_float - width: 180px - .oe_form_field_date - width: 7.5em - .oe_form_field_datetime - width: 11em input[type="text"], input[type="password"], input[type="file"], select height: 22px padding-top: 2px @@ -1571,26 +1585,6 @@ $sheet-max-width: 860px .oe_form_field_boolean padding-top: 4px width: auto - .oe_form_field_many2manytags - .text-wrap - width: 100% !important - textarea - width: 100% !important - .oe_form_field_many2manytags_box - border-radius: 2px - @include box-sizing(border) - position: relative - float: left - border: 1px solid #9DACCC - background: #E2E6F0 - color: black - padding: 0px 3px 0px 3px - margin: 0 2px 2px 0 - height: 16px - font: 11px "lucida grande", tahoma, verdana, arial, sans-serif - .text-core .text-wrap .text-dropdown .text-list .text-suggestion em - font-style: italic - text-decoration: none .oe_datepicker_container display: none .oe_datepicker_root @@ -1616,14 +1610,6 @@ $sheet-max-width: 860px .oe_form_field_with_button.oe_no_button > .oe_button display: none .oe_form_field_with_button:not(.oe_no_button) - input - border-right: none - -webkit-border-top-right-radius: 0px - -webkit-border-bottom-right-radius: 0px - -moz-border-radius-topright: 0px - -moz-border-radius-bottomright: 0px - border-top-right-radius: 0px - border-bottom-right-radius: 0px > .oe_button float: right @include radius(0) @@ -1635,6 +1621,16 @@ $sheet-max-width: 860px > div position: relative overflow: hidden + .oe_form_editable + .oe_form + .oe_form_field_integer + width: 7em !important + .oe_form_field_float + width: 8em !important + .oe_form_field_date + width: 7.5em !important + .oe_form_field_datetime + width: 11.5em !important // }}} // FormView.fields_binary {{{ /* http://www.quirksmode.org/dom/inputfile.html @@ -1668,6 +1664,7 @@ $sheet-max-width: 860px vertical-align: top .oe_form_field_image_controls position: absolute + white-space: nowrap top: 1px padding: 3px 0 0 0 margin: 0 1px @@ -1686,15 +1683,23 @@ $sheet-max-width: 860px position: relative span.oe_m2o_drop_down_button position: absolute - top: 1px + top: 2px right: 0px + .oe_m2o_cm_button + line-height: 14px // }}} // FormView.one2many {{{ .oe_form .oe_form_field_one2many > .oe_view_manager .oe_list_pager_single_page display: none - .oe_form_field_one2many + .oe_form_field_one2many,.oe_form_field_many2many // TODO: oe_form_field_one2many_list? + .oe_list_content + > thead + border-bottom: 1px + > tbody + tr:nth-child(odd) + background: transparent .oe_list .oe_list_edit_row_save background: url(/web/static/src/img/iconset-b-remove.png) 50% 50% no-repeat &:before @@ -1749,6 +1754,9 @@ $sheet-max-width: 860px td:first-child, th:first-child &:after border-width: 0 + td.oe_number + text-align: right !important + max-width: 100px > thead border-bottom: 2px solid #cacaca background: #eee @@ -1786,7 +1794,6 @@ $sheet-max-width: 860px padding: 3px 6px white-space: pre-line > td, > th - line-height: 18px > button border: none background: transparent @@ -1796,8 +1803,6 @@ $sheet-max-width: 860px width: 17px &:after border-width: 0 - > td.oe_number - text-align: right !important > tr:nth-child(odd) background-color: #f0f0fa @include vertical-gradient(#f0f0fa, #eeeef6) @@ -1873,6 +1878,49 @@ $sheet-max-width: 860px float: right color: #333 // }}} +//Tree view +.openerp + .tree_header + background-color: #f0f0f0 + border-bottom: 1px solid #cacaca + color: #4c4c4c + padding: 5px + height: 25px + button + float: right + height: 27px + margin-right: 5px + .oe-treeview-table + width: 100% + background-color: white + border-spacing: 0 + th + padding: 10px + color: #4c4c4c + font-weight: bold + background-color: #f0f0f0 + border-bottom: 2px solid #cacaca + .treeview-tr, .treeview-td + cursor: pointer + border-right: 1px dotted #afafb6 + vertical-align: top + text-align: left + border-bottom: 1px solid #cfcccc + tr:hover + background-color: #e0e0f8 + .oe-number + text-align: right !important + span + font-size: 90% + font-weight: normal + white-space: nowrap + display: block + .treeview-tr.oe-treeview-first + background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat + .oe_open .treeview-tr.oe-treeview-first + background-image: url(/web/static/src/img/collapse.gif) + .treeview-tr.oe-treeview-first span, .treeview-td.oe-treeview-first span + margin-left: 16px // Kitten Mode {{{ .kitten-mode-activated background-image: url(http://placekitten.com/g/1365/769) diff --git a/addons/web/static/src/js/boot.js b/addons/web/static/src/js/boot.js index 86f8077b151..c1b1b984abe 100644 --- a/addons/web/static/src/js/boot.js +++ b/addons/web/static/src/js/boot.js @@ -24,7 +24,7 @@ init: function(modules) { // By default only web will be loaded, the rest will be by loaded // by openerp.web.Session on the first session_authenticate - modules = modules || ["web"]; + modules = _.union(['web'], modules || []); var new_instance = { // links to the global openerp _openerp: openerp, diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index b87ebe56856..71010ef6d74 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -63,7 +63,7 @@ instance.web.Dialog = instance.web.Widget.extend({ this.dialog_options = { modal: true, destroy_on_close: true, - width: $(window).width() * (($(window).width() > 1024) ? 0.5 : 0.75), + width: 900, min_width: 0, max_width: '95%', height: 'auto', @@ -135,8 +135,12 @@ instance.web.Dialog = instance.web.Widget.extend({ this.$element.dialog('close'); }, on_close: function() { + if (this.__tmp_dialog_destroying) + return; if (this.dialog_options.destroy_on_close) { + this.__tmp_dialog_closing = true; this.destroy(); + this.__tmp_dialog_closing = undefined; } }, on_resized: function() { @@ -145,9 +149,14 @@ instance.web.Dialog = instance.web.Widget.extend({ _.each(this.getChildren(), function(el) { el.destroy(); }); - if (! this.isDestroyed()) { - this.$element.dialog('destroy'); + if (! this.__tmp_dialog_closing) { + this.__tmp_dialog_destroying = true; + this.close(); + this.__tmp_dialog_destroying = undefined; } + if (! this.isDestroyed()) { + this.$element.dialog('destroy'); + } this._super(); } }); @@ -212,11 +221,11 @@ instance.web.CrashManager = instance.web.CallbackEnabled.extend({ dialog.$element.html(QWeb.render('CrashManager.error', {session: instance.connection, error: error})); }, on_javascript_exception: function(exception) { - this.on_traceback({ - type: _t("Client Error"), - message: exception, - data: {debug: ""} - }); + this.on_traceback({ + type: _t("Client Error"), + message: exception, + data: {debug: ""} + }); }, }); @@ -254,7 +263,11 @@ instance.web.Loading = instance.web.Widget.extend({ this.count += increment; if (this.count > 0) { - this.$element.text(_.str.sprintf( _t("Loading (%d)"), this.count)); + if (instance.connection.debug) { + this.$element.text(_.str.sprintf( _t("Loading (%d)"), this.count)); + } else { + this.$element.text(_t("Loading")); + } this.$element.show(); this.getParent().$element.addClass('oe_wait'); } else { @@ -482,24 +495,26 @@ instance.web.Login = instance.web.Widget.extend({ } } }, + open_db_manager: function(){ + var self = this; + self.$element.find('.oe_login_bottom').hide(); + self.$element.find('.oe_login_pane').hide(); + self.databasemanager = new instance.web.DatabaseManager(self); + self.databasemanager.appendTo(self.$element); + self.databasemanager.do_exit.add_last(function() { + self.databasemanager.destroy(); + self.$element.find('.oe_login_bottom').show(); + self.$element.find('.oe_login_pane').show(); + self.load_db_list(true).then(self.on_db_list_loaded); + }); + }, start: function() { var self = this; - self.$element.find("form").submit(self.on_submit); - self.$element.find('.oe_login_manage_db').click(function() { - self.$element.find('.oe_login_bottom').hide(); - self.$element.find('.oe_login_pane').hide(); - self.databasemanager = new instance.web.DatabaseManager(self); - self.databasemanager.appendTo(self.$element); - self.databasemanager.do_exit.add_last(function() { - self.databasemanager.destroy(); - self.$element.find('.oe_login_bottom').show(); - self.$element.find('.oe_login_pane').show(); - self.load_db_list(true).then(self.proxy('_db_list_loaded')); - }); + self.open_db_manager(); }); - return self.load_db_list().then(self.proxy('_db_list_loaded')); + return self.load_db_list().then(self.on_db_list_loaded); }, load_db_list: function (force) { var d = $.when(), self = this; @@ -514,11 +529,14 @@ instance.web.Login = instance.web.Widget.extend({ } return d; }, - _db_list_loaded: function () { - var list = this._db_list, - dbdiv = this.$element.find('div.oe_login_dbpane'); + on_db_list_loaded: function () { + var self = this; + var list = this._db_list; + var dbdiv = this.$element.find('div.oe_login_dbpane'); this.$element.find("[name=db]").replaceWith(instance.web.qweb.render('Login.dblist', { db_list: list, selected_db: this.selected_db})); - if(list && list.length === 1) { + if(list.length === 0) { + self.open_db_manager(); + } else if(list && list.length === 1) { dbdiv.hide(); } else { dbdiv.show(); @@ -667,7 +685,7 @@ instance.web.Menu = instance.web.Widget.extend({ * @param {Number} id the action_id to match */ open_action: function (id) { - var $menu = this.$element.add(this.$secondary_menus).find('a[data-action-id=' + id + ']'); + var $menu = this.$element.add(this.$secondary_menus).find('a[data-action-id="' + id + '"]'); var menu_id = $menu.data('menu'); if (menu_id) { this.open_menu(menu_id); @@ -822,8 +840,8 @@ instance.web.UserMenu = instance.web.Widget.extend({ {text: _t("Change password"), click: function(){ self.change_password(); }}, {text: _t("Cancel"), click: function(){ $(this).dialog('destroy'); }}, {text: _t("Save"), click: function(){ - var inner_viewmanager = action_manager.inner_viewmanager; - inner_viewmanager.views[inner_viewmanager.active_view].controller.do_save() + var inner_widget = action_manager.inner_widget; + inner_widget.views[inner_widget.active_view].controller.do_save() .then(function() { self.dialog.destroy(); // needs to refresh interface in case language changed @@ -851,54 +869,35 @@ instance.web.UserMenu = instance.web.Widget.extend({ }, }); -instance.web.WebClient = instance.web.Widget.extend({ - init: function(parent) { - var self = this; +instance.web.Client = instance.web.Widget.extend({ + init: function(parent, origin) { + instance.client = instance.webclient = this; this._super(parent); - instance.webclient = this; - this.querystring = '?' + jQuery.param.querystring(); - this._current_state = null; - }, - _get_version_label: function() { - if (this.session.openerp_entreprise) { - return 'OpenERP'; - } else { - return _t("OpenERP - Unsupported/Community Version"); - } - }, - set_title: function(title) { - title = _.str.clean(title); - var sep = _.isEmpty(title) ? '' : ' - '; - document.title = title + sep + 'OpenERP'; + this.origin = origin; }, start: function() { var self = this; - this.$element.addClass("openerp openerp_webclient_container"); - if (jQuery.param !== undefined && jQuery.deparam(jQuery.param.querystring()).kitten !== undefined) { - $("body").addClass("kitten-mode-activated"); - if ($.blockUI) { - $.blockUI.defaults.message = '<img src="http://www.amigrave.com/kitten.gif">'; - } - } - this.session.session_bind().then(function() { - self.destroy_content(); + return instance.connection.session_bind(this.origin).then(function() { + var $e = $(QWeb.render(self._template, {})); + self.$element.replaceWith($e); + self.$element = $e; + self.bind_events(); self.show_common(); - if (!self.session.session_is_valid()) { - self.show_login(); - } else { - self.show_application(); - } }); + }, + bind_events: function() { + var self = this; this.$element.on('mouseenter', '.oe_systray > div:not([data-tipsy=true])', function() { $(this).attr('data-tipsy', 'true').tipsy().trigger('mouseenter'); }); this.$element.on('click', '.oe_dropdown_toggle', function(ev) { ev.preventDefault(); - var $menu = $(this).find('.oe_dropdown_menu'); + var $toggle = $(this); + var $menu = $toggle.find('.oe_dropdown_menu'); var state = $menu.is('.oe_opened'); setTimeout(function() { // Do not alter propagation - $menu.toggleClass('oe_opened', !state); + $toggle.add($menu).toggleClass('oe_opened', !state); if (!state) { // Move $menu if outside window's edge var doc_width = $(document).width(); @@ -919,6 +918,45 @@ instance.web.WebClient = instance.web.Widget.extend({ var self = this; this.crashmanager = new instance.web.CrashManager(); instance.connection.on_rpc_error.add(this.crashmanager.on_rpc_error); + self.notification = new instance.web.Notification(this); + self.notification.appendTo(self.$element); + self.loading = new instance.web.Loading(self); + self.loading.appendTo(self.$element); + self.action_manager = new instance.web.ActionManager(self); + self.action_manager.appendTo(self.$('.oe_application')); + }, +}); + +instance.web.WebClient = instance.web.Client.extend({ + _template: 'WebClient', + init: function(parent) { + this._super(parent); + this._current_state = null; + }, + start: function() { + var self = this; + return $.when(this._super()).pipe(function() { + if (jQuery.param !== undefined && jQuery.deparam(jQuery.param.querystring()).kitten !== undefined) { + $("body").addClass("kitten-mode-activated"); + if ($.blockUI) { + $.blockUI.defaults.message = '<img src="http://www.amigrave.com/kitten.gif">'; + } + } + if (!self.session.session_is_valid()) { + self.show_login(); + } else { + self.show_application(); + } + }); + }, + set_title: function(title) { + title = _.str.clean(title); + var sep = _.isEmpty(title) ? '' : ' - '; + document.title = title + sep + 'OpenERP'; + }, + show_common: function() { + var self = this; + this._super(); window.onerror = function (message, file, line) { self.crashmanager.on_traceback({ type: _t("Client Error"), @@ -926,23 +964,18 @@ instance.web.WebClient = instance.web.Widget.extend({ data: {debug: file + ':' + line} }); }; - self.notification = new instance.web.Notification(this); - self.notification.appendTo(self.$element); - self.loading = new instance.web.Loading(self); - self.loading.appendTo(self.$element); + // TODO: deprecate and use login client action self.login = new instance.web.Login(self); self.login.on("login",self,self.show_application); - self.$table = $(QWeb.render("WebClient", {})); - self.action_manager = new instance.web.ActionManager(self); - self.action_manager.appendTo(self.$table.find('.oe_application')); }, show_login: function() { var self = this; + self.$('.oe_topbar').hide(); self.login.appendTo(self.$element); }, show_application: function() { var self = this; - self.$element.append(self.$table); + self.$('.oe_topbar').show(); self.login.$element.hide(); self.menu = new instance.web.Menu(self); self.menu.replace(this.$element.find('.oe_menu_placeholder')); @@ -954,7 +987,7 @@ instance.web.WebClient = instance.web.Widget.extend({ self.user_menu.do_update(); self.bind_hashchange(); if (!self.session.openerp_entreprise) { - var version_label = self._get_version_label(); + var version_label = _t("OpenERP - Unsupported/Community Version"); self.$element.find('.oe_footer_powered').append(_.str.sprintf('<span> - <a href="http://www.openerp.com/support-or-publisher-warranty-contract" target="_blank">%s</a></span>', version_label)); } self.set_title(); @@ -1036,6 +1069,7 @@ instance.web.WebClient = instance.web.Widget.extend({ if (options.needaction) { action.context.search_default_needaction_pending = true; } + self.action_manager.clear_breadcrumbs(); self.action_manager.do_action(action); }); }, @@ -1056,31 +1090,36 @@ instance.web.WebClient = instance.web.Widget.extend({ } }); -instance.web.EmbeddedClient = instance.web.Widget.extend({ - template: 'EmptyComponent', - init: function(parent, action_id, options) { - this._super(parent); - // TODO take the xmlid of a action instead of its id +instance.web.EmbeddedClient = instance.web.Client.extend({ + _template: 'EmbedClient', + init: function(parent, origin, dbname, login, key, action_id, options) { + this._super(parent, origin); + + this.dbname = dbname; + this.login = login; + this.key = key; this.action_id = action_id; this.options = options || {}; - this.am = new instance.web.ActionManager(this); }, start: function() { var self = this; - this.am.appendTo(this.$element.addClass('openerp')); - return this.rpc("/web/action/load", { action_id: this.action_id }, function(result) { - var action = result.result; - action.flags = _.extend({ - //views_switcher : false, - search_view : false, - action_buttons : false, - sidebar : false - //pager : false - }, self.options, action.flags || {}); + return $.when(this._super()).pipe(function() { + return instance.connection.session_authenticate(self.dbname, self.login, self.key, true).pipe(function() { + return self.rpc("/web/action/load", { action_id: self.action_id }, function(result) { + var action = result.result; + action.flags = _.extend({ + //views_switcher : false, + search_view : false, + action_buttons : false, + sidebar : false + //pager : false + }, self.options, action.flags || {}); - self.am.do_action(action); + self.action_manager.do_action(action); + }); + }); }); - } + }, }); instance.web.embed = function (origin, dbname, login, key, action, options) { @@ -1094,13 +1133,8 @@ instance.web.embed = function (origin, dbname, login, key, action, options) { var sc = document.getElementsByTagName('script'); currentScript = sc[sc.length-1]; } - instance.connection.session_bind(origin).then(function () { - instance.connection.session_authenticate(dbname, login, key, true).then(function () { - var client = new instance.web.EmbeddedClient(null, action, options); - client.insertAfter(currentScript); - }); - }); - + var client = new instance.web.EmbeddedClient(null, origin, dbname, login, key, action, options); + client.insertAfter(currentScript); }; }; diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js index a00ca4002e5..a5a62b9bcc1 100644 --- a/addons/web/static/src/js/coresetup.js +++ b/addons/web/static/src/js/coresetup.js @@ -404,10 +404,11 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess } }); + /** * Event Bus used to bind events scoped in the current instance */ -instance.web.bus = new (instance.web.Class.extend(instance.web.EventDispatcherMixin, { +instance.web.Bus = instance.web.Class.extend(instance.web.EventDispatcherMixin, { init: function() { instance.web.EventDispatcherMixin.init.call(this, parent); var self = this; @@ -425,7 +426,8 @@ instance.web.bus = new (instance.web.Class.extend(instance.web.EventDispatcherMi }); }); } -}))(); +}) +instance.web.bus = new instance.web.Bus(); /** OpenERP Translations */ instance.web.TranslationDataBase = instance.web.Class.extend(/** @lends instance.web.TranslationDataBase# */{ diff --git a/addons/web/static/src/js/view_editor.js b/addons/web/static/src/js/view_editor.js index 8733a191b21..6df78679ecb 100644 --- a/addons/web/static/src/js/view_editor.js +++ b/addons/web/static/src/js/view_editor.js @@ -53,7 +53,7 @@ instance.web.ViewEditor = instance.web.OldWidget.extend({ this.main_view_id = this.parent.fields_view.view_id; this.action_manager = new instance.web.ActionManager(this); $.when(this.action_manager.do_action(action)).then(function() { - var viewmanager = self.action_manager.inner_viewmanager, + var viewmanager = self.action_manager.inner_widget, controller = viewmanager.views[viewmanager.active_view].controller; self.action_manager.appendTo(self.view_edit_dialog.$element); self.action_manager.renderElement(self.view_edit_dialog); @@ -88,7 +88,7 @@ instance.web.ViewEditor = instance.web.OldWidget.extend({ } else { $.when(self.do_save_view(view_values)).then(function() { self.create_view_dialog.close(); - var controller = self.action_manager.inner_viewmanager.views[self.action_manager.inner_viewmanager.active_view].controller; + var controller = self.action_manager.inner_widget.views[self.action_manager.inner_widget.active_view].controller; controller.reload_content(); }); } @@ -167,7 +167,7 @@ instance.web.ViewEditor = instance.web.OldWidget.extend({ do_delete_view: function() { var self = this; if (confirm(_t("Do you really want to remove this view?"))) { - var controller = this.action_manager.inner_viewmanager.views[this.action_manager.inner_viewmanager.active_view].controller; + var controller = this.action_manager.inner_widget.views[this.action_manager.inner_widget.active_view].controller; this.dataset.unlink([this.main_view_id]).then(function() { controller.reload_content(); self.main_view_id = self.parent.fields_view.view_id; @@ -397,7 +397,7 @@ instance.web.ViewEditor = instance.web.OldWidget.extend({ action_manager.do_action(action); }}, {text: _t("Close"), click: function(){ - self.action_manager.inner_viewmanager.views[self.action_manager.inner_viewmanager.active_view].controller.reload_content(); + self.action_manager.inner_widget.views[self.action_manager.inner_widget.active_view].controller.reload_content(); self.edit_xml_dialog.close(); }} ] @@ -998,7 +998,7 @@ instance.web.ViewEditor = instance.web.OldWidget.extend({ }; var action_manager = new instance.web.ActionManager(self); $.when(action_manager.do_action(action)).then(function() { - var controller = action_manager.dialog_viewmanager.views['form'].controller; + var controller = action_manager.dialog_widget.views['form'].controller; controller.on_button_cancel.add_last(function(){ action_manager.destroy() }); diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 9e3db4f1b05..677b7cf7c4e 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -9,7 +9,7 @@ instance.web.form = {}; /** * Interface implemented by the form view or any other object * able to provide the features necessary for the fields to work. - * + * * Properties: * - display_invalid_fields : if true, all fields where is_valid() return true should * be displayed as invalid. @@ -80,7 +80,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this.reload_mutex = new $.Mutex(); this.__clicked_inside = false; this.__blur_timeout = null; - this.rendering_engine = new instance.web.form.FormRenderingEngineReadonly(this); + this.rendering_engine = new instance.web.form.FormRenderingEngine(this); this.qweb = null; // A QWeb instance will be created if the view is a QWeb template }, destroy: function() { @@ -295,10 +295,12 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM on_record_loaded: function(record) { var self = this, set_values = []; if (!record) { + this.set({ 'title' : undefined }); this.do_warn("Form", "The record could not be found in the database.", true); return $.Deferred().reject(); } this.datarecord = record; + this.set({ 'title' : record.id ? record.name : "New record" }); if (this.qweb) { this.kill_current_form(); @@ -546,7 +548,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this.on_form_changed(); } if (!_.isEmpty(result.warning)) { - instance.web.dialog($(QWeb.render("CrashManager.warning", result.warning)), { + instance.web.dialog($(QWeb.render("CrashManager.warning", result.warning)), { title:result.warning.title, modal: true, buttons: [ @@ -690,7 +692,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM if (!first_invalid_field) { first_invalid_field = f; } - } else if (f.name !== 'id' && !f.get("readonly") && (!self.datarecord.id || f._dirty_flag)) { + } else if (f.name !== 'id' && (!self.datarecord.id || (!f.get("readonly") && f._dirty_flag))) { // Special case 'id' field, do not save this field // on 'create' : save all non readonly fields // on 'edit' : save non readonly modified fields @@ -814,13 +816,13 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM }); }, get_fields_values: function(blacklist) { - blacklist = blacklist || []; + blacklist = blacklist || []; var values = {}; var ids = this.get_selected_ids(); values["id"] = ids.length > 0 ? ids[0] : false; _.each(this.fields, function(value_, key) { - if (_.include(blacklist, key)) { - return; + if (_.include(blacklist, key)) { + return; } values[key] = value_.get_value(); }); @@ -877,6 +879,9 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM return option[0] === value; })[1]; break; + case 'many2one': + displayed = field.get_displayed(); + break; } return { @@ -954,6 +959,9 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM is_create_mode: function() { return !this.datarecord.id; }, + open_translate_dialog: function(field) { + return this._super(field); + }, }); /** @@ -967,7 +975,7 @@ instance.web.form.FormRenderingEngineInterface = instance.web.Class.extend({ /** * Default rendering engine for the form view. - * + * * It is necessary to set the view using set_view() before usage. */ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInterface.extend({ @@ -1197,8 +1205,7 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt row_cols = cols; } else if (tagName==='group') { // When <group> <group/><group/> </group>, we need a spacing between the two groups - $child.addClass('oe_group_right') - + $td.addClass('oe_group_right') } row_cols -= colspan; @@ -1224,12 +1231,6 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt $child = $td.children(':first'); switch ($child[0].tagName.toLowerCase()) { case 'separator': - if ($child.attr('orientation') === 'vertical') { - $td.addClass('oe_vertical_separator').attr('width', '1'); - $td.empty(); - row_cols-= $td.attr('colspan') || 1; - total--; - } break; case 'label': if ($child.attr('for')) { @@ -1289,7 +1290,7 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt page_attrs.__page = $new_page; page_attrs.__ic = ic; pages.push(page_attrs); - + $new_page.children().each(function() { self.process($(this)); }); @@ -1315,7 +1316,7 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt } }); }); - + this.handle_common_properties($new_notebook, $notebook); return $new_notebook; }, @@ -1362,12 +1363,6 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt }, }); -instance.web.form.FormRenderingEngineReadonly = instance.web.form.FormRenderingEngine.extend({ - alter_field: function(field) { - field.set({"force_readonly": true}); - }, -}); - instance.web.form.FormDialog = instance.web.Dialog.extend({ init: function(parent, options, view_id, dataset) { this._super(parent, options); @@ -1602,7 +1597,7 @@ instance.web.form.FormWidget = instance.web.Widget.extend(instance.web.form.Invi parent: {} }); if (a_dataset.parent_view) { - fields_values.parent = a_dataset.parent_view.get_fields_values([a_dataset.child_name]); + fields_values.parent = a_dataset.parent_view.get_fields_values([a_dataset.child_name]); } return fields_values; }, @@ -1620,7 +1615,7 @@ instance.web.form.FormWidget = instance.web.Widget.extend(instance.web.form.Invi if (! v_context) { v_context = (this.field || {}).context || {}; } - + if (v_context.__ref || true) { //TODO: remove true var fields_values = this._build_eval_context(blacklist); v_context = new instance.web.CompoundContext(v_context).set_eval_context(fields_values); @@ -1707,11 +1702,7 @@ instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({ on_confirmed: function() { var self = this; - var context = this.node.attrs.context; - if (context && context.__ref) { - context = new instance.web.CompoundContext(context); - context.set_eval_context(this._build_eval_context()); - } + var context = this.build_context(); return this.view.do_execute_action( _.extend({}, this.node.attrs, {context: context}), @@ -1728,14 +1719,14 @@ instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({ /** * Interface to be implemented by fields. - * + * * Properties: * - readonly: boolean. If set to true the field should appear in readonly mode. * - force_readonly: boolean, When it is true, the field should always appear * in read only mode, no matter what the value of the "readonly" property can be. * Events: * - changed_value: triggered to inform the view to check on_changes - * + * */ instance.web.form.FieldInterface = { /** @@ -1746,14 +1737,14 @@ instance.web.form.FieldInterface = { init: function(field_manager, node) {}, /** * Called by the form view to indicate the value of the field. - * + * * set_value() may return an object that can be passed to $.when() that represents the moment when * the field has finished all operations necessary before the user can effectively use the widget. - * + * * Multiple calls to set_value() can occur at any time and must be handled correctly by the implementation, * regardless of any asynchronous operation currently running and the status of any promise that a * previous call to set_value() could have returned. - * + * * set_value() must be able, at any moment, to handle the syntax returned by the "read" method of the * osv class in the OpenERP server as well as the syntax used by the set_value() (see below). It must * also be able to handle any other format commonly used in the _defaults key on the models in the addons @@ -1763,16 +1754,16 @@ instance.web.form.FieldInterface = { set_value: function(value_) {}, /** * Get the current value of the widget. - * + * * Must always return a syntactically correct value to be passed to the "write" method of the osv class in * the OpenERP server, although it is not assumed to respect the constraints applied to the field. * For example if the field is marked as "required", a call to get_value() can return false. - * + * * get_value() can also be called *before* a call to set_value() and, in that case, is supposed to * return a default value according to the type of field. - * + * * This method is always assumed to perform synchronously, it can not return a promise. - * + * * If there was no user interaction to modify the value of the field, it is always assumed that * get_value() return the same semantic value than the one passed in the last call to set_value(), * although the syntax can be different. This can be the case for type of fields that have a different @@ -1802,14 +1793,14 @@ instance.web.form.FieldInterface = { /** * Abstract class for classes implementing FieldInterface. - * + * * Properties: * - effective_readonly: when it is true, the widget is displayed as readonly. Vary depending * the values of the "readonly" property and the "force_readonly" property on the field manager. * - value: useful property to hold the value of the field. By default, set_value() and get_value() * set and retrieve the value property. Changing the value property also triggers automatically * a 'changed_value' event that inform the view to trigger on_changes. - * + * */ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.web.form.FieldInterface, { /** @@ -1829,17 +1820,17 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w this.string = this.node.attrs.string || this.field.string || this.name; this.set({'value': false}); this.set({required: this.modifiers['required'] === true}); - + // some events to make the property "effective_readonly" sync automatically with "readonly" and // "force_readonly" this.set({"readonly": this.modifiers['readonly'] === true}); + this.set({"force_readonly": false}); var test_effective_readonly = function() { self.set({"effective_readonly": self.get("readonly") || !!self.get("force_readonly")}); }; this.on("change:readonly", this, test_effective_readonly); this.on("change:force_readonly", this, test_effective_readonly); test_effective_readonly.call(this); - this.on("change:value", this, function() { if (! this._inhibit_on_change) this.trigger('changed_value'); @@ -2021,7 +2012,7 @@ instance.web.form.FieldChar = instance.web.form.AbstractField.extend(instance.we }); instance.web.form.FieldID = instance.web.form.FieldChar.extend({ - + }); instance.web.form.FieldEmail = instance.web.form.FieldChar.extend({ @@ -2316,6 +2307,54 @@ instance.web.form.FieldText = instance.web.form.AbstractField.extend(instance.we }, }); +/** + * FieldTextHtml Widget + * Intended for FieldText widgets meant to display HTML content. This + * widget will instantiate the CLEditor (see cleditor in static/src/lib) + * To find more information about CLEditor configutation: go to + * http://premiumsoftware.net/cleditor/docs/GettingStarted.html + */ +instance.web.form.FieldTextHtml = instance.web.form.FieldText.extend({ + + initialize_content: function() { + this.$textarea = this.$element.find('textarea'); + var width = ((this.node.attrs || {}).editor_width || 468); + var height = ((this.node.attrs || {}).editor_height || 100); + this.$textarea.cleditor({ + width: width, // width not including margins, borders or padding + height: height, // height not including margins, borders or padding + controls: // controls to add to the toolbar + "bold italic underline strikethrough | size " + + "| removeformat | bullets numbering | outdent " + + "indent | link unlink", + sizes: // sizes in the font size popup + "1,2,3,4,5,6,7", + bodyStyle: // style to assign to document body contained within the editor + "margin:4px; font:12px monospace; cursor:text; color:#1F1F1F" + }); + this.$cleditor = this.$textarea.cleditor()[0]; + // call super now, because cleditor resets the disable attr + this._super.apply(this, arguments); + // propagate disabled property to cleditor + this.$cleditor.disable(this.$textarea.prop('disabled')); + }, + + set_value: function(value_) { + this._super.apply(this, arguments); + this._dirty_flag = true; + }, + + render_value: function() { + this._super.apply(this, arguments); + this.$cleditor.updateFrame(); + }, + + get_value: function() { + this.$cleditor.updateTextArea(); + return this.$textarea.val(); + }, +}); + instance.web.form.FieldBoolean = instance.web.form.AbstractField.extend({ template: 'FieldBoolean', start: function() { @@ -2420,7 +2459,7 @@ instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(instan } else { var self = this; var option = _(this.values) - .detect(function (record) { return record[0] === self.get('value'); }); + .detect(function (record) { return record[0] === self.get('value'); }); this.$element.text(option ? option[1] : this.values[0][1]); } }, @@ -2599,7 +2638,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc render_editable: function() { var self = this; this.$input = this.$element.find("input"); - + self.$input.tipsy({ title: function() { return "No element was selected, you should create or select one from the dropdown list."; @@ -2607,10 +2646,10 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc trigger:'manual', fade: true, }); - + this.$drop_down = this.$element.find(".oe_m2o_drop_down_button"); this.$follow_button = $(".oe_m2o_cm_button", this.$element); - + this.$follow_button.click(function() { if (!self.get('value')) { self.focus(); @@ -2768,10 +2807,20 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc this.$input.val(str.split("\n")[0]); this.current_display = this.$input.val(); } else { - str = _.escape(str).split("\n").join("<br />"); + var lines = _.escape(str).split("\n"); + var link = ""; + var follow = ""; + if (! this.get_definition_options().highlight_first_line) { + link = lines.join("<br />"); + } else { + link = lines[0]; + follow = _.rest(lines).join("<br />"); + if (follow) + link += "<br />"; + } this.$element.find('a') .unbind('click') - .html(str) + .html(link) .click(function () { self.do_action({ type: 'ir.actions.act_window', @@ -2783,6 +2832,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc }); return false; }); + $(".oe_form_m2o_follow", this.$element).html(follow); } }, set_value: function(value_) { @@ -2799,6 +2849,9 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc this._super(value_); this.inhibit_on_change = false; }, + get_displayed: function() { + return this.display_value["" + this.get("value")]; + }, add_id: function(id) { this.display_value = {}; this.set({value: id}); @@ -2904,7 +2957,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ }, load_views: function() { var self = this; - + var modes = this.node.attrs.mode; modes = !!modes ? modes.split(",") : ["tree"]; var views = []; @@ -3107,30 +3160,30 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ save_any_view: function() { if (this.doing_on_change) return false; - return this.session.synchronized_mode(_.bind(function() { - if (this.viewmanager && this.viewmanager.views && this.viewmanager.active_view && - this.viewmanager.views[this.viewmanager.active_view] && - this.viewmanager.views[this.viewmanager.active_view].controller) { - var view = this.viewmanager.views[this.viewmanager.active_view].controller; - if (this.viewmanager.active_view === "form") { - if (!view.is_initialized.isResolved()) { - return false; - } - var res = $.when(view.do_save()); - if (!res.isResolved() && !res.isRejected()) { - console.warn("Asynchronous get_value() is not supported in form view."); - } - return res; - } else if (this.viewmanager.active_view === "list") { - var res = $.when(view.ensure_saved()); - if (!res.isResolved() && !res.isRejected()) { - console.warn("Asynchronous get_value() is not supported in list view."); - } - return res; - } - } - return false; - }, this)); + return this.session.synchronized_mode(_.bind(function() { + if (this.viewmanager && this.viewmanager.views && this.viewmanager.active_view && + this.viewmanager.views[this.viewmanager.active_view] && + this.viewmanager.views[this.viewmanager.active_view].controller) { + var view = this.viewmanager.views[this.viewmanager.active_view].controller; + if (this.viewmanager.active_view === "form") { + if (!view.is_initialized.isResolved()) { + return false; + } + var res = $.when(view.do_save()); + if (!res.isResolved() && !res.isRejected()) { + console.warn("Asynchronous get_value() is not supported in form view."); + } + return res; + } else if (this.viewmanager.active_view === "list") { + var res = $.when(view.ensure_saved()); + if (!res.isResolved() && !res.isRejected()) { + console.warn("Asynchronous get_value() is not supported in list view."); + } + return res; + } + } + return false; + }, this)); }, is_syntax_valid: function() { if (!this.viewmanager.views[this.viewmanager.active_view]) @@ -3493,7 +3546,7 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in $("textarea", self.$element).css("padding-left", "3px"); self.tags.addTags(_.map(data, function(el) {return {name: el[1], id:el[0]};})); } else { - self.$element.html(QWeb.render("FieldMany2ManyTags.box", {elements: data})); + self.$element.html(QWeb.render("FieldMany2ManyTag", {elements: data})); } }; if (! self.get('values') || self.get('values').length > 0) { @@ -3665,7 +3718,7 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend( this.dataset.on_unlink.add_last(function(ids) { self.dataset_changed(); }); - + this.is_setted.then(function() { self.load_view(); }); @@ -3781,7 +3834,7 @@ instance.web.form.Many2ManyKanbanView = instance.web_kanban.KanbanView.extend({ }); instance.web.form.Many2ManyQuickCreate = instance.web.Widget.extend({ template: 'Many2ManyKanban.quick_create', - + /** * close_btn: If true, the widget will display a "Close" button able to trigger * a "close" event. @@ -3896,14 +3949,16 @@ instance.web.form.AbstractFormPopup = instance.web.OldWidget.extend({ display_popup: function() { var self = this; this.renderElement(); - new instance.web.Dialog(this, { - width: '90%', + var dialog = new instance.web.Dialog(this, { min_width: '800px', + dialogClass: 'oe_act_window', close: function() { self.check_exit(true); }, title: this.options.title || "", + buttons: [{text:"tmp"}], }, this.$element).open(); + this.$buttonpane = dialog.$element.dialog("widget").find(".ui-dialog-buttonpane").html(""); this.start(); }, on_write_completed: function() {}, @@ -3919,16 +3974,18 @@ instance.web.form.AbstractFormPopup = instance.web.OldWidget.extend({ if (this.row_id !== null) { options.initial_mode = this.options.readonly ? "view" : "edit"; } + _.extend(options, { + $buttons: this.$buttonpane, + }); this.view_form = new instance.web.FormView(this, this.dataset, false, options); if (this.options.alternative_form_view) { this.view_form.set_embedded_view(this.options.alternative_form_view); } this.view_form.appendTo(this.$element.find(".oe_popup_form")); this.view_form.on_loaded.add_last(function() { - var $buttons = self.view_form.$element.find(".oe_form_buttons"); var multi_select = self.row_id === null && ! self.options.disable_multiple_selection; - $buttons.html(QWeb.render("AbstractFormPopup.buttons", {multi_select: multi_select})); - var $snbutton = $buttons.find(".oe_abstractformpopup-form-save-new"); + self.$buttonpane.html(QWeb.render("AbstractFormPopup.buttons", {multi_select: multi_select})); + var $snbutton = self.$buttonpane.find(".oe_abstractformpopup-form-save-new"); $snbutton.click(function() { $.when(self.view_form.do_save()).then(function() { self.view_form.reload_mutex.exec(function() { @@ -3936,7 +3993,7 @@ instance.web.form.AbstractFormPopup = instance.web.OldWidget.extend({ }); }); }); - var $sbutton = $buttons.find(".oe_abstractformpopup-form-save"); + var $sbutton = self.$buttonpane.find(".oe_abstractformpopup-form-save"); $sbutton.click(function() { $.when(self.view_form.do_save()).then(function() { self.view_form.reload_mutex.exec(function() { @@ -3944,7 +4001,7 @@ instance.web.form.AbstractFormPopup = instance.web.OldWidget.extend({ }); }); }); - var $cbutton = $buttons.find(".oe_abstractformpopup-form-close"); + var $cbutton = self.$buttonpane.find(".oe_abstractformpopup-form-close"); $cbutton.click(function() { self.check_exit(); }); @@ -4053,6 +4110,7 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend 'selectable': !self.options.disable_multiple_selection, 'read_only': true, 'import_enabled': false, + '$buttons': self.$buttonpane, }, self.options.list_view_options || {})); self.view_list.popup = self; self.view_list.appendTo($(".oe_popup_list", self.$element)).pipe(function() { @@ -4061,16 +4119,12 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend self.searchview.do_search(); }); self.view_list.on_loaded.add_last(function() { - var $buttons = self.view_list.$element.find(".oe-actions"); - $buttons.prepend(QWeb.render("SelectCreatePopup.search.buttons")); - var $cbutton = $buttons.find(".oe_selectcreatepopup-search-close"); + self.$buttonpane.html(QWeb.render("SelectCreatePopup.search.buttons", {widget:self})); + var $cbutton = self.$buttonpane.find(".oe_selectcreatepopup-search-close"); $cbutton.click(function() { self.destroy(); }); - var $sbutton = $buttons.find(".oe_selectcreatepopup-search-select"); - if(self.options.disable_multiple_selection) { - $sbutton.hide(); - } + var $sbutton = self.$buttonpane.find(".oe_selectcreatepopup-search-select"); $sbutton.click(function() { self.on_select_elements(self.selected_ids); self.destroy(); @@ -4474,7 +4528,7 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({ this.selection = []; // get fold information from widget var fold = ((this.node.attrs || {}).statusbar_fold || true); - // build final domain: if fold option required, add the + // build final domain: if fold option required, add the if (fold == true) { var domain = new instance.web.CompoundDomain(['|'], ['&'], self.build_domain(), [['fold', '=', false]], [['id', '=', self.selected_value]]); } else { @@ -4506,7 +4560,7 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({ var shown = _.map(((this.node.attrs || {}).statusbar_visible || "").split(","), function(x) { return _.str.trim(x); }); shown = _.select(shown, function(x) { return x.length > 0; }); - + if (shown.length == 0) { this.to_show = this.selection; } else { @@ -4548,6 +4602,7 @@ instance.web.form.widgets = new instance.web.Registry({ 'email' : 'instance.web.form.FieldEmail', 'url' : 'instance.web.form.FieldUrl', 'text' : 'instance.web.form.FieldText', + 'text_html' : 'instance.web.form.FieldTextHtml', 'date' : 'instance.web.form.FieldDate', 'datetime' : 'instance.web.form.FieldDatetime', 'selection' : 'instance.web.form.FieldSelection', diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index 82c9d1be12b..f68f1354099 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -1082,7 +1082,7 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web. render_cell: function () { return self.render_cell.apply(self, arguments); } }, this))); - this.pad_table_to(5); + this.pad_table_to(4); }, pad_table_to: function (count) { if (this.records.length >= count || diff --git a/addons/web/static/src/js/view_tree.js b/addons/web/static/src/js/view_tree.js index e8bd7351f1f..2181b2aa157 100644 --- a/addons/web/static/src/js/view_tree.js +++ b/addons/web/static/src/js/view_tree.js @@ -63,6 +63,12 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie } return fields; }, + store_record:function(records){ + var self = this; + _(records).each(function (record) { + self.records[record.id] = record; + }); + }, on_loaded: function (fields_view) { var self = this; var has_toolbar = !!fields_view.arch.attrs.toolbar; @@ -87,17 +93,19 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie this.$element.addClass(this.fields_view.arch.attrs['class']); this.dataset.read_slice(this.fields_list()).then(function(records) { + self.store_record(records); if (!has_toolbar) { // WARNING: will do a second read on the same ids, but only on // first load so not very important - self.getdata(null, _(records).pluck('id')); + self.render_data({'null':records}) + self.getdata(_.pluck(records,"id")); return; } var $select = self.$element.find('select') .change(function () { var $option = $(this).find(':selected'); - self.getdata($option.val(), $option.data('children')); + self.getdata($option.val()); }); _(records).each(function (record) { self.records[record.id] = record; @@ -112,7 +120,12 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie $select.change(); } }); - + this.$element.find("#tree_view_expand").click(function(){ + self.expand_all(); + }); + this.$element.find("#tree_view_collapse").click(function(){ + self.collpase_all(); + }); // TODO store open nodes in url ?... this.do_push_state({}); @@ -128,6 +141,22 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie return [color, py.parse(py.tokenize(expr)), expr]; }).value(); }, + expand_all: function(){ + var self = this; + var tr = this.$element.find(".oe-treeview-table tbody tr[id^='treerow_']"); + _.each(tr,function(rec){ + self.showcontent($(rec).attr('data-id'),true); + }); + }, + collpase_all: function(){ + var self = this; + var root_tr = this.$element.find(".oe-treeview-table tbody tr[data-level='"+1+"']"); + _.each(root_tr,function(rec){ + if($(rec).hasClass('oe_open')){ + self.showcontent($(rec).attr('data-id'),false); + } + }); + }, /** * Returns the color for the provided record in the current view (from the * ``@colors`` attribute) @@ -164,50 +193,44 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie }); this.$element.delegate('.treeview-tr', 'click', function () { - var is_loaded = 0, - $this = $(this), + var $this = $(this), record_id = $this.data('id'), - record = self.records[record_id], - children_ids = record[self.children_field]; - - _(children_ids).each(function(childid) { - if (self.$element.find('#treerow_' + childid).length) { - if (self.$element.find('#treerow_' + childid).is(':hidden')) { - is_loaded = -1; - } else { - is_loaded++; - } - } - }); - if (is_loaded === 0) { - if (!$this.parent().hasClass('oe_open')) { - self.getdata(record_id, children_ids); - } - } else { - self.showcontent(record_id, is_loaded < 0); - } + bool = $this.parent().hasClass('oe_open'); + self.showcontent(record_id, !bool); }); }, // get child data of selected value - getdata: function (id, children_ids) { + getdata: function (id) { var self = this; - - self.dataset.read_ids(children_ids, this.fields_list()).then(function(records) { - _(records).each(function (record) { - self.records[record.id] = record; - }); - - var $curr_node = self.$element.find('#treerow_' + id); + var parent_child ={}; + id = _.isArray(id)?id:parseInt(id); + var ir_model_data = new instance.web.Model(this.model,self.dataset.get_context() || {},[['id','child_of',id]]).query(); + ir_model_data._execute().then(function(records){ + self.store_record(records); + _.each(records,function(rec){ + if(rec[self.children_field].length === 0)return; + parent_child[rec.id] = []; + _.each(rec[self.children_field],function(key){ + parent_child[rec.id].push(self.records[key]); + }); + }) + self.render_data(parent_child); + }); + }, + render_data: function(groupby){ + var self = this; + _.each(_.keys(groupby),function(key){ + var $curr_node = self.$element.find('#treerow_' + key); + var record = groupby[key]; var children_rows = QWeb.render('TreeView.rows', { - 'records': records, + 'records': record, 'children_field': self.children_field, 'fields_view': self.fields_view.arch.children, 'fields': self.fields, - 'level': $curr_node.data('level') || 0, + 'level': ($curr_node.data('level') || 0) + 1, 'render': instance.web.format_value, 'color_for': self.color_for }); - if ($curr_node.length) { $curr_node.addClass('oe_open'); $curr_node.after(children_rows); @@ -215,8 +238,10 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie self.$element.find('tbody').html(children_rows); } }); + self.collpase_all(); }, + // Get details in listview activate: function(id) { var self = this; @@ -259,13 +284,5 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie }, this); }, - do_show: function () { - this.$element.show(); - }, - - do_hide: function () { - this.$element.hide(); - this.hidden = true; - } }); }; diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index cd2ccb72c49..ccf34576a1a 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -10,29 +10,112 @@ instance.web.ActionManager = instance.web.Widget.extend({ init: function(parent) { this._super(parent); this.inner_action = null; - this.inner_viewmanager = null; + this.inner_widget = null; this.dialog = null; - this.dialog_viewmanager = null; - this.client_widget = null; + this.dialog_widget = null; + this.breadcrumbs = []; + }, + start: function() { + this._super.apply(this, arguments); + this.$element.on('click', '.oe_breadcrumb_item', this.on_breadcrumb_clicked); }, dialog_stop: function () { if (this.dialog) { - this.dialog_viewmanager.destroy(); - this.dialog_viewmanager = null; + this.dialog_widget.destroy(); + this.dialog_widget = null; this.dialog.destroy(); this.dialog = null; } }, - content_stop: function () { - if (this.inner_viewmanager) { - this.inner_viewmanager.destroy(); - this.inner_viewmanager = null; + /** + * Add a new item to the breadcrumb + * + * If the title of an item is an array, the multiple title mode is in use. + * (eg: a widget with multiple views might need to display a title for each view) + * In multiple title mode, the show() callback can check the index it receives + * in order to detect which of its titles has been clicked on by the user. + * + * @param {Object} item breadcrumb item + * @param {Object} item.widget widget containing the view(s) to be added to the breadcrumb added + * @param {Function} [item.show] triggered whenever the widget should be shown back + * @param {Function} [item.hide] triggered whenever the widget should be shown hidden + * @param {Function} [item.destroy] triggered whenever the widget should be destroyed + * @param {String|Array} [item.title] title(s) of the view(s) to be displayed in the breadcrumb + * @param {Function} [item.get_title] should return the title(s) of the view(s) to be displayed in the breadcrumb + */ + push_breadcrumb: function(item) { + var last = this.breadcrumbs.slice(-1)[0]; + if (last) { + last.hide(); + } + var item = _.extend({ + show: function(index) { + this.widget.$element.show(); + }, + hide: function() { + this.widget.$element.hide(); + }, + destroy: function() { + this.widget.destroy(); + }, + get_title: function() { + return this.title || this.widget.get('title'); + } + }, item); + item.id = _.uniqueId('breadcrumb_'); + this.breadcrumbs.push(item); + }, + on_breadcrumb_clicked: function(ev) { + var $e = $(ev.target); + var id = $e.data('id'); + var item; + for (var i = this.breadcrumbs.length - 1; i >= 0; i--) { + var it = this.breadcrumbs[i]; + if (it.id == id) { + item = it; + break; + } + this.remove_breadcrumb(i); + } + var index = $e.parent().find('.oe_breadcrumb_item[data-id=' + $e.data('id') + ']').index($e); + item.show(index, $e); + this.inner_widget = item.widget; + }, + clear_breadcrumbs: function() { + while (this.breadcrumbs.length) { + this.remove_breadcrumb(0); } - if (this.client_widget) { - this.client_widget.destroy(); - this.client_widget = null; + }, + remove_breadcrumb: function(index) { + var item = this.breadcrumbs.splice(index, 1)[0]; + if (item) { + var dups = _.filter(this.breadcrumbs, function(it) { + return item.widget === it.widget; + }); + if (!dups.length) { + item.destroy(); + } } }, + get_title: function() { + var titles = []; + for (var i = 0; i < this.breadcrumbs.length; i += 1) { + var item = this.breadcrumbs[i]; + var tit = item.get_title(); + if (!_.isArray(tit)) { + tit = [tit]; + } + for (var j = 0; j < tit.length; j += 1) { + var label = _.escape(tit[j]); + if (i === this.breadcrumbs.length - 1 && j === tit.length - 1) { + titles.push(label); + } else { + titles.push(_.str.sprintf('<a href="#" class="oe_breadcrumb_item" data-id="%s">%s</a>', item.id, label)); + } + } + } + return titles.join(' <span class="oe_fade">/</span> '); + }, do_push_state: function(state) { if (this.getParent() && this.getParent().do_push_state) { if (this.inner_action) { @@ -49,7 +132,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ var self = this, action_loaded; if (state.action_id) { - var run_action = (!this.inner_viewmanager) || this.inner_viewmanager.action.id !== state.action_id; + var run_action = (!this.inner_widget || !this.inner_widget.action) || this.inner_widget.action.id !== state.action_id; if (run_action) { this.null_action(); action_loaded = this.do_action(state.action_id); @@ -89,13 +172,13 @@ instance.web.ActionManager = instance.web.Widget.extend({ } $.when(action_loaded || null).then(function() { - if (self.inner_viewmanager) { - self.inner_viewmanager.do_load_state(state, warm); + if (self.inner_widget && self.inner_widget.do_load_state) { + self.inner_widget.do_load_state(state, warm); } }); }, do_action: function(action, on_close) { - if (_.isNumber(action)) { + if (_.isNumber(action) || _.isString(action)) { var self = this; return self.rpc("/web/action/load", { action_id: action }, function(result) { self.do_action(result.result, on_close); @@ -124,7 +207,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ }, null_action: function() { this.dialog_stop(); - this.content_stop(); + this.clear_breadcrumbs(); }, ir_actions_act_window: function (action, on_close) { var self = this; @@ -137,29 +220,31 @@ instance.web.ActionManager = instance.web.Widget.extend({ } if (action.target === 'new') { if (this.dialog === null) { - this.dialog = new instance.web.Dialog(this, { width: '80%' }); + // These buttons will be overwrited by <footer> if any + this.dialog = new instance.web.Dialog(this, { + buttons: { "Close": function() { $(this).dialog("close"); }}, + dialogClass: 'oe_act_window' + }); if(on_close) this.dialog.on_close.add(on_close); } else { - this.dialog_viewmanager.destroy(); + this.dialog_widget.destroy(); } this.dialog.dialog_title = action.name; - this.dialog_viewmanager = new instance.web.ViewManagerAction(this.dialog, action); - this.dialog_viewmanager.appendTo(this.dialog.$element); - this.dialog_viewmanager.$element.addClass("oe_view_manager_" + (action.target || 'current')); + this.dialog_widget = new instance.web.ViewManagerAction(this, action); + this.dialog_widget.appendTo(this.dialog.$element); this.dialog.open(); } else { this.dialog_stop(); - this.content_stop(); if(action.menu_id) { return this.getParent().do_action(action, function () { instance.webclient.menu.open_menu(action.menu_id); }); } this.inner_action = action; - this.inner_viewmanager = new instance.web.ViewManagerAction(this, action); - this.inner_viewmanager.appendTo(this.$element); - this.inner_viewmanager.$element.addClass("oe_view_manager_" + (action.target || 'current')); + var inner_widget = this.inner_widget = new instance.web.ViewManagerAction(this, action); + inner_widget.add_breadcrumb(); + this.inner_widget.appendTo(this.$element); } }, ir_actions_act_window_close: function (action, on_closed) { @@ -178,10 +263,14 @@ instance.web.ActionManager = instance.web.Widget.extend({ }); }, ir_actions_client: function (action) { - this.content_stop(); this.dialog_stop(); var ClientWidget = instance.web.client_actions.get_object(action.tag); - (this.client_widget = new ClientWidget(this, action.params)).appendTo(this.$element); + this.inner_widget = new ClientWidget(this, action.params); + this.push_breadcrumb({ + widget: this.inner_widget, + title: action.name + }); + this.inner_widget.appendTo(this.$element); }, ir_actions_report_xml: function(action, on_closed) { var self = this; @@ -290,35 +379,7 @@ instance.web.ViewManager = instance.web.Widget.extend({ this.active_view = view_type; if (!view.controller) { - // Lazy loading of views - var controllerclass = this.registry.get_object(view_type); - var options = _.clone(view.options); - if (view_type === "form" && this.action) { - switch (this.action.target) { - case 'new': - case 'inline': - options.initial_mode = 'edit'; - break; - } - } - var controller = new controllerclass(this, this.dataset, view.view_id, options); - if (view.embedded_view) { - controller.set_embedded_view(view.embedded_view); - } - controller.do_switch_view.add_last(_.bind(this.switch_view, this)); - controller.do_prev_view.add_last(this.on_prev_view); - var container = this.$element.find(".oe_view_manager_view_" + view_type); - view_promise = controller.appendTo(container); - this.views[view_type].controller = controller; - this.views[view_type].deferred.resolve(view_type); - $.when(view_promise).then(function() { - self.on_controller_inited(view_type, controller); - if (self.searchview - && self.flags.auto_search - && view.controller.searchable !== false) { - self.searchview.ready.then(self.searchview.do_search); - } - }); + view_promise = this.do_create_view(view_type); } else if (this.searchview && self.flags.auto_search && view.controller.searchable !== false) { @@ -347,14 +408,90 @@ instance.web.ViewManager = instance.web.Widget.extend({ container.hide(); controller.do_hide(); } + // put the <footer> in the dialog's buttonpane + if (self.$element.parent('.ui-dialog-content') && self.$element.find('footer')) { + self.$element.parent('.ui-dialog-content').parent().find('div.ui-dialog-buttonset').hide() + self.$element.find('footer').appendTo( + self.$element.parent('.ui-dialog-content').parent().find('div.ui-dialog-buttonpane') + ); + } } }); - - self.$element.find('.oe_view_title_text:first').text( - self.display_title()); }); return view_promise; }, + do_create_view: function(view_type) { + // Lazy loading of views + var self = this; + var view = this.views[view_type]; + var controllerclass = this.registry.get_object(view_type); + var options = _.clone(view.options); + if (view_type === "form" && this.action) { + switch (this.action.target) { + case 'new': + case 'inline': + options.initial_mode = 'edit'; + break; + } + } + var controller = new controllerclass(this, this.dataset, view.view_id, options); + + controller.on("change:title", this, function() { + if (self.active_view === view_type) { + self.set_title(controller.get('title')); + } + }); + + if (view.embedded_view) { + controller.set_embedded_view(view.embedded_view); + } + controller.do_switch_view.add_last(_.bind(this.switch_view, this)); + + controller.do_prev_view.add_last(this.on_prev_view); + var container = this.$element.find(".oe_view_manager_view_" + view_type); + var view_promise = controller.appendTo(container); + this.views[view_type].controller = controller; + this.views[view_type].deferred.resolve(view_type); + return $.when(view_promise).then(function() { + self.on_controller_inited(view_type, controller); + if (self.searchview + && self.flags.auto_search + && view.controller.searchable !== false) { + self.searchview.ready.then(self.searchview.do_search); + } + }); + }, + set_title: function(title) { + this.$element.find('.oe_view_title_text:first').text(title); + }, + add_breadcrumb: function() { + var self = this; + var views = [this.active_view || this.views_src[0].view_type]; + this.on_mode_switch.add(function(mode) { + var last = views.slice(-1)[0]; + if (mode !== last) { + if (mode !== 'form') { + views.length = 0; + } + views.push(mode); + } + }); + this.getParent().push_breadcrumb({ + widget: this, + show: function(index, $e) { + var view_to_select = views[index]; + self.$element.show(); + if (self.active_view !== view_to_select) { + self.on_mode_switch(view_to_select); + } + }, + get_title: function() { + return _.map(views, function(v) { + return self.views[v].controller.get('title'); + }); + } + }); + }, /** * Method used internally when a view asks to switch view. This method is meant * to be extended by child classes to change the default behavior, which simply @@ -447,14 +584,6 @@ instance.web.ViewManager = instance.web.Widget.extend({ */ on_action_executed: function () { }, - display_title: function () { - var view = this.views[this.active_view]; - if (view) { - // ick - return view.controller.fields_view.arch.attrs.string; - } - return ''; - } }); instance.web.ViewManagerAction = instance.web.ViewManager.extend({ @@ -499,7 +628,7 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({ if (this.session.hidden_menutips) { return; } - this.session.hidden_menutips = {} + this.session.hidden_menutips = {}; }, /** * Initializes the ViewManagerAction: sets up the searchview (if the @@ -527,32 +656,7 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({ var manager_ready = $.when(searchview_loaded, main_view_loaded); this.$element.find('.oe_debug_view').change(this.on_debug_changed); - - if (this.action.help && !this.flags.low_profile) { - var Users = new instance.web.DataSet(self, 'res.users'), - $tips = this.$element.find('.oe_view_manager_menu_tips'); - $tips.delegate('blockquote button', 'click', function() { - var $this = $(this); - //noinspection FallthroughInSwitchStatementJS - switch ($this.attr('name')) { - case 'disable': - Users.write(self.session.uid, {menu_tips:false}); - case 'hide': - $this.closest('blockquote').hide(); - self.session.hidden_menutips[self.action.id] = true; - } - }); - if (!(self.action.id in self.session.hidden_menutips)) { - Users.read_ids([this.session.uid], ['menu_tips']).then(function(users) { - var user = users[0]; - if (!(user && user.id === self.session.uid)) { - return; - } - $tips.find('blockquote').toggle(user.menu_tips); - }); - } - } - + this.$element.addClass("oe_view_manager_" + (this.action.target || 'current')); return manager_ready; }, on_debug_changed: function (evt) { @@ -675,12 +779,18 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({ view: controller, view_manager: self })); - if (!self.action.name && fvg) { - self.$element.find('.oe_view_title_text').text(fvg.arch.attrs.string || fvg.name); - } - + self.set_title(); }); }, + do_create_view: function(view_type) { + var r = this._super.apply(this, arguments); + var view = this.views[view_type].controller; + view.set({ 'title': this.action.name }); + return r; + }, + set_title: function(title) { + this.$element.find('.oe_breadcrumb_title:first').html(this.getParent().get_title()); + }, do_push_state: function(state) { if (this.getParent() && this.getParent().do_push_state) { state["view_type"] = this.active_view; @@ -702,9 +812,6 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({ self.views[self.active_view].controller.do_load_state(state, warm); }); }, - display_title: function () { - return this.action.name; - } }); instance.web.Sidebar = instance.web.Widget.extend({ @@ -967,11 +1074,13 @@ instance.web.TranslateDialog = instance.web.Dialog.extend({ if (self.view.translatable_fields && self.view.translatable_fields.length) { self.do_load_fields_values(function() { sup.call(self); + // desactivated because it created an exception, plus it does not seem very useful + /* if (field) { var $field_input = self.$element.find('tr[data-field="' + field.name + '"] td:nth-child(2) *:first-child'); self.$element.scrollTo($field_input); $field_input.focus(); - } + }*/ }); } else { sup.call(self); @@ -1130,7 +1239,7 @@ instance.web.View = instance.web.Widget.extend({ args.push(context); return dataset.call_button(action_data.name, args, handler); } else if (action_data.type=="action") { - return this.rpc('/web/action/load', { action_id: parseInt(action_data.name, 10), context: context, do_not_eval: true}, handler); + return this.rpc('/web/action/load', { action_id: action_data.name, context: context, do_not_eval: true}, handler); } else { return dataset.exec_workflow(record_id, action_data.name, handler); } diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 94b76c170ea..ed63b5fbfbe 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -371,6 +371,7 @@ </t> <t t-name="WebClient"> + <div class="openerp openerp_webclient_container"> <table class="oe_webclient"> <tr> <td colspan="2" class="oe_topbar"> @@ -394,21 +395,29 @@ </td> </tr> </table> + </div> +</t> + +<t t-name="EmbedClient"> + <div class="openerp"> + <div class="oe_application"></div> + </div> </t> <t t-name="ViewManager"> <div class="oe_view_manager"> <table class="oe_view_manager_header"> - <col width="33%"/> - <col width="33%"/> - <col width="34%"/> + <col width="20%"/> + <col width="25%"/> + <col width="20%"/> + <col width="35%"/> <tr class="oe_header_row oe_header_row_top"> <td colspan="2"> <h2 class="oe_view_title" t-if="widget.flags.display_title !== false"> - <span class="oe_view_title_text"><t t-esc="widget.display_title()"/></span> + <span class="oe_view_title_text oe_breadcrumb_title"/> </h2> </td> - <td> + <td colspan="2"> <div class="oe_view_manager_view_search" t-opentag="true"/> </td> </tr> @@ -416,7 +425,7 @@ <td> <div class="oe_view_manager_buttons"/> </td> - <td> + <td colspan="2"> <div class="oe_view_manager_sidebar"/> </td> <td> @@ -535,14 +544,16 @@ </t> <t t-name="TreeView"> - <select t-if="toolbar" style="width: 30%"> - </select> - <table class="oe_tree_table"> + <div class = "tree_header"> + <select t-if="toolbar" ></select> + <button id = "tree_view_collapse">Collapse All</button> + <button id = "tree_view_expand">Expand All</button> + </div> + <table class="oe-treeview-table"> <thead> <tr> <th t-foreach="fields_view" t-as="field" - t-if="!field.attrs.modifiers.tree_invisible" - class="treeview-header"> + t-if="!field.attrs.modifiers.tree_invisible"> <t t-esc="fields[field.attrs.name].string" /> </th> </tr> @@ -554,11 +565,11 @@ <tr t-name="TreeView.rows" t-foreach="records" t-as="record" t-att-id="'treerow_' + record.id" - t-att-data-id="record.id" t-att-data-level="level + 1"> + t-att-data-id="record.id" t-att-data-level="level"> <t t-set="children" t-value="record[children_field]"/> <t t-set="class" t-value="children and children.length ? 'treeview-tr' : 'treeview-td'"/> - <t t-set="rank" t-value="'oe_tree_first'"/> - <t t-set="style" t-value="'background-position: ' + 19*level + 'px; padding-left: ' + 19*level + 'px;'"/> + <t t-set="rank" t-value="'oe-treeview-first'"/> + <t t-set="style" t-value="'background-position: ' + 19*(level-1) + 'px; padding-left: ' + 19*(level-1) + 'px;'"/> <td t-foreach="fields_view" t-as="field" t-if="!field.attrs.modifiers.tree_invisible" @@ -773,7 +784,7 @@ <table border="0" cellpadding="0" cellspacing="0" t-attf-class="oe_form_group #{classnames}"/> </t> <t t-name="FormRenderingNotebook"> - <div> + <div class="oe_clear"> <ul t-attf-class="oe_notebook #{classnames}"> <li t-foreach="pages" t-as="page" t-att-modifiers="page.modifiers"> <a t-attf-href="##{page.id}"> @@ -788,7 +799,7 @@ </div> </t> <t t-name="FormRenderingSeparator"> - <div t-attf-class="oe_horizontal_separator #{classnames}"> + <div t-attf-class="oe_horizontal_separator oe_clear #{classnames}"> <t t-esc="string"/> </div> </t> @@ -944,11 +955,12 @@ </t> <t t-name="FieldMany2One"> <span class="oe_form_field oe_form_field_many2one oe_form_field_with_button" t-att-style="widget.node.attrs.style"> - <a t-if="widget.get('effective_readonly')" href="#" class="oe_form_uri"/> + <t t-if="widget.get('effective_readonly')"> + <a href="#" class="oe_form_uri"/> + <span class="oe_form_m2o_follow"/> + </t> <t t-if="!widget.get('effective_readonly')"> - <button class="oe_button oe_m2o_cm_button" title="Open Resource"> - <img t-att-src='_s + "/web/static/src/img/icons/terp-folder-yellow.png"'/> - </button> + <a href="#" tabindex="-1" class="oe_m2o_cm_button oe_e oe_right">/</a> <div> <input type="text" t-att-id="widget.id_for_label" @@ -963,18 +975,20 @@ </t> </span> </t> +<!-- Collection of m2m tags --> <t t-name="FieldMany2ManyTags"> - <div class="oe_form_field oe_form_field_many2manytags" t-att-style="widget.node.attrs.style"> + <div class="oe_form_field oe_tags" t-att-style="widget.node.attrs.style"> <t t-if="! widget.get('effective_readonly')"> <textarea rows="1" style="width: 100%" t-att-placeholder="widget.node.attrs.placeholder"></textarea> </t> </div> </t> -<t t-name="FieldMany2ManyTags.box"> +<!-- Individual m2m tag element --> +<t t-name="FieldMany2ManyTag"> <t t-set="i" t-value="0"/> <t t-foreach="elements" t-as="el"> - <span class="oe_form_field_many2manytags_box" t-att-data-index="i"> + <span class="oe_tag" t-att-data-index="i"> <t t-esc="el[1]"/> </span> <t t-set="i" t-value="i + 1"/> @@ -1466,8 +1480,11 @@ </div> </t> <t t-name="SelectCreatePopup.search.buttons"> - <button type="button" class="oe_button oe_selectcreatepopup-search-select" disabled="disabled">Select</button> - <button type="button" class="oe_button oe_selectcreatepopup-search-close">Cancel</button> + <t t-if="! widget.options.disable_multiple_selection"> + <button type="button" class="oe_button oe_selectcreatepopup-search-select" disabled="disabled">Select</button> + or + </t> + <a class="oe_button oe_selectcreatepopup-search-close oe_bold oe_form_button_cancel" href="javascript:void(0)">Cancel</a> </t> <t t-name="AbstractFormPopup.buttons"> <t t-if="! multi_select"> @@ -1477,7 +1494,7 @@ <button type="button" class="oe_button oe_abstractformpopup-form-save-new oe_highlight">Save & New</button> <button type="button" class="oe_button oe_abstractformpopup-form-save oe_highlight">Save & Close</button> </t> - <button type="button" class="oe_button oe_abstractformpopup-form-close">Cancel</button> + or <a class="oe_button oe_abstractformpopup-form-close oe_bold oe_form_button_cancel" href="javascript:void(0)">Cancel</a> </t> <t t-extend="ListView.row"> <!-- adds back padding to row being rendered after edition, if necessary |
