From 156e69517fa6774f19c8e3093f8cfefe018bb4cd Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Fri, 10 Oct 2014 16:12:54 +0300 Subject: [PATCH 001/139] fix send invitations for calls --- frontend/client/modules/crm/src/views/call/detail.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/client/modules/crm/src/views/call/detail.js b/frontend/client/modules/crm/src/views/call/detail.js index 469981cd5b..d1adf8ae25 100644 --- a/frontend/client/modules/crm/src/views/call/detail.js +++ b/frontend/client/modules/crm/src/views/call/detail.js @@ -52,7 +52,7 @@ this.$el.find('button[data-action="sendInvitations"]').addClass('disabled'); this.notify('Sending...'); $.ajax({ - url: 'Meeting/action/sendInvitations', + url: 'Call/action/sendInvitations', type: 'POST', data: JSON.stringify({ id: this.model.id From 56ae7e5d3c49cbab534e524d716db75eb0ebc211 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Fri, 10 Oct 2014 17:08:49 +0300 Subject: [PATCH 002/139] change readme --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1afcc1ed63..0be9f3b10e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,12 @@ EspoCRM is an Open Source CRM (Customer Relationship Management) software that allows you to see, enter and evaluate all your company relationships regardless of the type. People, companies or opportunities - all in an easy and intuitive interface. -### How to get started +Download the latest release from our [website](http://www.espocrm.com). + +### How to report bug + +Create an issue [here](https://github.com/espocrm/espocrm/issues) or post bug on our [forum](http://forum.espocrm.com/bug-reports?routestring=forum/bug-reports). + +### How to get started (for developers) 1. Clone repository to your local computer. 2. Change to the project's root directory. @@ -9,9 +15,9 @@ Never update composer dependencies if you are going to contribute code back. -Now you can build. +Now you can build. -If your repository is accessible via a web server then you can run EspoCRM by url `http://PROJECT_URL/frontend` w/o making a build. You will need to have proper data/config.php and existing database. +If your repository is accessible via a web server then you can run EspoCRM by url `http://PROJECT_URL/frontend` w/o making a build. To get a proper data/config.php and data in a database you can run /install via browser. ### How to build From b8263295c2703c6570afb34767c72cd756520ae8 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Fri, 10 Oct 2014 17:23:06 +0300 Subject: [PATCH 003/139] fix readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0be9f3b10e..9d28ba1e9a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Download the latest release from our [website](http://www.espocrm.com). ### How to report bug -Create an issue [here](https://github.com/espocrm/espocrm/issues) or post bug on our [forum](http://forum.espocrm.com/bug-reports?routestring=forum/bug-reports). +Create an issue [here](https://github.com/espocrm/espocrm/issues) or post on our [forum](http://forum.espocrm.com/bug-reports?routestring=forum/bug-reports). ### How to get started (for developers) From b39aa01ac97dce634d766a41267a713b6112eeae Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Mon, 13 Oct 2014 12:01:36 +0300 Subject: [PATCH 004/139] add labels to german language --- .../Crm/Resources/i18n/de_DE/Document.json | 32 +++++++++++++++++++ .../Espo/Resources/i18n/de_DE/Global.json | 5 ++- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 application/Espo/Modules/Crm/Resources/i18n/de_DE/Document.json diff --git a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Document.json b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Document.json new file mode 100644 index 0000000000..70ebe0f6a8 --- /dev/null +++ b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Document.json @@ -0,0 +1,32 @@ +{ + "labels": { + "Create Document": "Neues Dokument", + "Details": "Details" + }, + "fields": { + "name": "Name", + "status": "Status", + "file": "Datei", + "type": "Typ", + "source": "Quelle", + "publishDate": "Veröffentlichungsdatum", + "expirationDate": "Verfallsdatum", + "description": "Beschreibung" + }, + "links": { + "accounts": "Kontakte", + "opportunities": "Verkaufsshancen" + }, + "options": { + "status": { + "Active": "Aktiv", + "Draft": "Entwurf", + "Expired": "Abgelaufen", + "Canceled": "Storniert" + } + }, + "presetFilters": { + "active": "Aktiv", + "draft": "Entwurf" + } +} diff --git a/application/Espo/Resources/i18n/de_DE/Global.json b/application/Espo/Resources/i18n/de_DE/Global.json index e473de5f0c..73bfffb607 100644 --- a/application/Espo/Resources/i18n/de_DE/Global.json +++ b/application/Espo/Resources/i18n/de_DE/Global.json @@ -116,7 +116,10 @@ "Duplicate": "Duplizieren", "Notifications": "Benachrichtigungen", "Mark all read": "Alle als gelesen markieren", - "See more": "Mehr anzeigen" + "See more": "Mehr anzeigen", + "Today": "Heute", + "Tomorrow": "Morgen", + "Yesterday": "Gestern" }, "messages": { "notModified": "Sie haben den Datensatz nicht geändert", From b561c94ad1e29560cd603d790614a99d517b80c2 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Mon, 13 Oct 2014 15:18:38 +0300 Subject: [PATCH 005/139] de_DE change --- application/Espo/Modules/Crm/Resources/i18n/de_DE/Task.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Task.json b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Task.json index 99ce7f1eb1..593540c441 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/de_DE/Task.json +++ b/application/Espo/Modules/Crm/Resources/i18n/de_DE/Task.json @@ -29,7 +29,7 @@ "Create Task": "Neue Aufgabe" }, "presetFilters": { - "active": "Aktiv", + "actual": "Tatsächlich", "completed": "Abgeschlossen", "todays": "Heutige", "overdue": "Überfällig" From c0e6d1191ca1ac7d6e5094c8930759cf0047c1bd Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Mon, 13 Oct 2014 17:30:27 +0300 Subject: [PATCH 006/139] multiEnum field --- .../Espo/Resources/i18n/en_US/Admin.json | 5 +- .../Espo/Resources/metadata/app/jsLibs.json | 8 +- .../metadata/entityDefs/Settings.json | 2 +- .../Resources/metadata/fields/multiEnum.json | 18 + frontend/client/css/select2-bootstrap.css | 501 +++++++++++++ frontend/client/css/select2.css | 700 ++++++++++++++++++ frontend/client/img/select2.png | Bin 0 -> 613 bytes frontend/client/lib/select2.min.js | 23 + .../res/templates/fields/multi-enum/edit.tpl | 5 + frontend/client/src/views/fields/array.js | 55 +- .../client/src/views/fields/multi-enum.js | 115 +++ 11 files changed, 1405 insertions(+), 27 deletions(-) create mode 100644 application/Espo/Resources/metadata/fields/multiEnum.json create mode 100644 frontend/client/css/select2-bootstrap.css create mode 100644 frontend/client/css/select2.css create mode 100644 frontend/client/img/select2.png create mode 100644 frontend/client/lib/select2.min.js create mode 100644 frontend/client/res/templates/fields/multi-enum/edit.tpl create mode 100644 frontend/client/src/views/fields/multi-enum.js diff --git a/application/Espo/Resources/i18n/en_US/Admin.json b/application/Espo/Resources/i18n/en_US/Admin.json index 29d4ad92c7..6cd5492d43 100644 --- a/application/Espo/Resources/i18n/en_US/Admin.json +++ b/application/Espo/Resources/i18n/en_US/Admin.json @@ -65,7 +65,7 @@ "bool": "Bool", "currency": "Currency", "date": "Date", - "datetime": "DateTime", + "datetime": "Date-Time", "email": "Email", "enum": "Enum", "enumInt": "Enum Integer", @@ -81,7 +81,8 @@ "url": "Url", "varchar": "Varchar", "file": "File", - "image": "Image" + "image": "Image", + "multiEnum": "Multi-Enum" }, "fields": { "type": "Type", diff --git a/application/Espo/Resources/metadata/app/jsLibs.json b/application/Espo/Resources/metadata/app/jsLibs.json index 478f6a178f..8bcd04b5d3 100644 --- a/application/Espo/Resources/metadata/app/jsLibs.json +++ b/application/Espo/Resources/metadata/app/jsLibs.json @@ -12,7 +12,11 @@ "Textcomplete": { "path": "client/lib/jquery.textcomplete.js", "exportsTo": "$", - "exportsAs": "textcomplete" - + "exportsAs": "textcomplete" + }, + "Select2": { + "path": "client/lib/select2.min.js", + "exportsTo": "$", + "exportsAs": "select2" } } diff --git a/application/Espo/Resources/metadata/entityDefs/Settings.json b/application/Espo/Resources/metadata/entityDefs/Settings.json index fd0d5747fe..42c8769a0a 100644 --- a/application/Espo/Resources/metadata/entityDefs/Settings.json +++ b/application/Espo/Resources/metadata/entityDefs/Settings.json @@ -52,7 +52,7 @@ "maxLength": 1 }, "currencyList": { - "type": "array", + "type": "multiEnum", "default": ["USD", "EUR"], "options": ["AED","ANG","ARS","AUD","BGN","BHD","BND","BOB","BRL","BWP","CAD","CHF","CLP","CNY","COP","CRC","CZK","DKK","DOP","DZD","EEK","EGP","EUR","FJD","GBP","HKD","HNL","HRK","HUF","IDR","ILS","INR","JMD","JOD","JPY","KES","KRW","KWD","KYD","KZT","LBP","LKR","LTL","LVL","MAD","MDL","MKD","MUR","MXN","MYR","NAD","NGN","NIO","NOK","NPR","NZD","OMR","PEN","PGK","PHP","PKR","PLN","PYG","QAR","RON","RSD","RUB","SAR","SCR","SEK","SGD","SKK","SLL","SVC","THB","TND","TRY","TTD","TWD","TZS","UAH","UGX","USD","UYU","UZS","VND","YER","ZAR","ZMK"], "required": true diff --git a/application/Espo/Resources/metadata/fields/multiEnum.json b/application/Espo/Resources/metadata/fields/multiEnum.json new file mode 100644 index 0000000000..f1bf6dcfdc --- /dev/null +++ b/application/Espo/Resources/metadata/fields/multiEnum.json @@ -0,0 +1,18 @@ +{ + "params":[ + { + "name": "required", + "type": "bool", + "default": false + }, + { + "name":"options", + "type":"array" + } + ], + "filter": false, + "notCreatable": false, + "fieldDefs":{ + "type":"jsonArray" + } +} diff --git a/frontend/client/css/select2-bootstrap.css b/frontend/client/css/select2-bootstrap.css new file mode 100644 index 0000000000..ecaa92c687 --- /dev/null +++ b/frontend/client/css/select2-bootstrap.css @@ -0,0 +1,501 @@ +/** + * Select2 Bootstrap 3 CSS v1.4.1 + * Tested with Bootstrap v3.2.0 and Select2 v3.3.2, v3.4.1-v3.4.5, v3.5.1, master + * in latest Chrome, Safari, Firefox, Opera (Mac) and IE8-IE11 + * MIT License + */ +/** + * Reset Bootstrap 3 .form-control styles which - if applied to the + * original element Select2 is replacing not be properly being hidden + * when used in a "Bootstrap Input Group with Addon". + **/ +.select2-offscreen, +.select2-offscreen:focus { + width: 1px !important; + height: 1px !important; + position: absolute !important; +} diff --git a/frontend/client/css/select2.css b/frontend/client/css/select2.css new file mode 100644 index 0000000000..cb4e89627e --- /dev/null +++ b/frontend/client/css/select2.css @@ -0,0 +1,700 @@ +/* +Version: 3.5.1 Timestamp: Tue Jul 22 18:58:56 EDT 2014 +*/ +.select2-container { + margin: 0; + position: relative; + display: inline-block; + /* inline-block for ie7 */ + zoom: 1; + *display: inline; + vertical-align: middle; +} + +.select2-container, +.select2-drop, +.select2-search, +.select2-search input { + /* + Force border-box so that % widths fit the parent + container without overlap because of margin/padding. + More Info : http://www.quirksmode.org/css/box.html + */ + -webkit-box-sizing: border-box; /* webkit */ + -moz-box-sizing: border-box; /* firefox */ + box-sizing: border-box; /* css3 */ +} + +.select2-container .select2-choice { + display: block; + height: 26px; + padding: 0 0 0 8px; + overflow: hidden; + position: relative; + + border: 1px solid #d1d5d6; + white-space: nowrap; + line-height: 26px; + color: #444; + text-decoration: none; + + border-radius: 4px; + + background-clip: padding-box; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + background-color: #fff; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.5, #fff)); + background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 50%); + background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#ffffff', endColorstr = '#eeeeee', GradientType = 0); + background-image: linear-gradient(to top, #eee 0%, #fff 50%); +} + +html[dir="rtl"] .select2-container .select2-choice { + padding: 0 8px 0 0; +} + +.select2-container.select2-drop-above .select2-choice { + border-bottom-color: #d1d5d6; + + border-radius: 0 0 4px 4px; + + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.9, #fff)); + background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 90%); + background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 90%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0); + background-image: linear-gradient(to bottom, #eee 0%, #fff 90%); +} + +.select2-container.select2-allowclear .select2-choice .select2-chosen { + margin-right: 42px; +} + +.select2-container .select2-choice > .select2-chosen { + margin-right: 26px; + display: block; + overflow: hidden; + + white-space: nowrap; + + text-overflow: ellipsis; + float: none; + width: auto; +} + +html[dir="rtl"] .select2-container .select2-choice > .select2-chosen { + margin-left: 26px; + margin-right: 0; +} + +.select2-container .select2-choice abbr { + display: none; + width: 12px; + height: 12px; + position: absolute; + right: 24px; + top: 8px; + + font-size: 1px; + text-decoration: none; + + border: 0; + background: url('../img/select2.png') right top no-repeat; + cursor: pointer; + outline: 0; +} + +.select2-container.select2-allowclear .select2-choice abbr { + display: inline-block; +} + +.select2-container .select2-choice abbr:hover { + background-position: right -11px; + cursor: pointer; +} + +.select2-drop-mask { + border: 0; + margin: 0; + padding: 0; + position: fixed; + left: 0; + top: 0; + min-height: 100%; + min-width: 100%; + height: auto; + width: auto; + opacity: 0; + z-index: 9998; + /* styles required for IE to work */ + background-color: #fff; + filter: alpha(opacity=0); +} + +.select2-drop { + width: 100%; + margin-top: -1px; + position: absolute; + z-index: 9999; + top: 100%; + + background: #fff; + color: #000; + border: 1px solid #d1d5d6; + border-top: 0; + + border-radius: 0 0 4px 4px; + + -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); + box-shadow: 0 4px 5px rgba(0, 0, 0, .15); +} + +.select2-drop.select2-drop-above { + margin-top: 1px; + border-top: 1px solid #d1d5d6; + border-bottom: 0; + + border-radius: 4px 4px 0 0; + + -webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); + box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); +} + +.select2-drop-active { + border: 1px solid ; + border-top: none; +} + +.select2-drop.select2-drop-above.select2-drop-active { + border-top: 1px solid ; +} + +.select2-drop-auto-width { + border-top: 1px solid #d1d5d6; + width: auto; +} + +.select2-drop-auto-width .select2-search { + padding-top: 4px; +} + +.select2-container .select2-choice .select2-arrow { + display: inline-block; + width: 18px; + height: 100%; + position: absolute; + right: 0; + top: 0; + + border-left: 1px solid #d1d5d6; + border-radius: 0 4px 4px 0; + + background-clip: padding-box; + + background: #ccc; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee)); + background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%); + background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#cccccc', GradientType = 0); + background-image: linear-gradient(to top, #ccc 0%, #eee 60%); +} + +html[dir="rtl"] .select2-container .select2-choice .select2-arrow { + left: 0; + right: auto; + + border-left: none; + border-right: 1px solid #d1d5d6; + border-radius: 4px 0 0 4px; +} + +.select2-container .select2-choice .select2-arrow b { + display: block; + width: 100%; + height: 100%; + background: url('../img/select2.png') no-repeat 0 1px; +} + +html[dir="rtl"] .select2-container .select2-choice .select2-arrow b { + background-position: 2px 1px; +} + +.select2-search { + display: inline-block; + width: 100%; + min-height: 26px; + margin: 0; + padding-left: 4px; + padding-right: 4px; + + position: relative; + z-index: 10000; + + white-space: nowrap; +} + +.select2-search input { + width: 100%; + height: auto !important; + min-height: 26px; + padding: 4px 20px 4px 5px; + margin: 0; + + outline: 0; + font-family: sans-serif; + font-size: 1em; + + border: 1px solid #d1d5d6; + border-radius: 0; + + -webkit-box-shadow: none; + box-shadow: none; + + background: #fff url('../img/select2.png') no-repeat 100% -22px; + background: url('../img/select2.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee)); + background: url('../img/select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('../img/select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('../img/select2.png') no-repeat 100% -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0; +} + +html[dir="rtl"] .select2-search input { + padding: 4px 5px 4px 20px; + + background: #fff url('../img/select2.png') no-repeat -37px -22px; + background: url('../img/select2.png') no-repeat -37px -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee)); + background: url('../img/select2.png') no-repeat -37px -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('../img/select2.png') no-repeat -37px -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('../img/select2.png') no-repeat -37px -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0; +} + +.select2-drop.select2-drop-above .select2-search input { + margin-top: 4px; +} + +.select2-search input.select2-active { + background: #fff no-repeat 100%; +} + +.select2-container-active .select2-choice, +.select2-container-active .select2-choices { + border: 1px solid ; + outline: none; + + -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3); + box-shadow: 0 0 5px rgba(0, 0, 0, .3); +} + +.select2-dropdown-open .select2-choice { + border-bottom-color: transparent; + -webkit-box-shadow: 0 1px 0 #fff inset; + box-shadow: 0 1px 0 #fff inset; + + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + + background-color: #eee; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(0.5, #eee)); + background-image: -webkit-linear-gradient(center bottom, #fff 0%, #eee 50%); + background-image: -moz-linear-gradient(center bottom, #fff 0%, #eee 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0); + background-image: linear-gradient(to top, #fff 0%, #eee 50%); +} + +.select2-dropdown-open.select2-drop-above .select2-choice, +.select2-dropdown-open.select2-drop-above .select2-choices { + border: 1px solid ; + border-top-color: transparent; + + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(0.5, #eee)); + background-image: -webkit-linear-gradient(center top, #fff 0%, #eee 50%); + background-image: -moz-linear-gradient(center top, #fff 0%, #eee 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0); + background-image: linear-gradient(to bottom, #fff 0%, #eee 50%); +} + +.select2-dropdown-open .select2-choice .select2-arrow { + background: transparent; + border-left: none; + filter: none; +} +html[dir="rtl"] .select2-dropdown-open .select2-choice .select2-arrow { + border-right: none; +} + +.select2-dropdown-open .select2-choice .select2-arrow b { + background-position: -18px 1px; +} + +html[dir="rtl"] .select2-dropdown-open .select2-choice .select2-arrow b { + background-position: -16px 1px; +} + +.select2-hidden-accessible { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +/* results */ +.select2-results { + max-height: 200px; + padding: 0 0 0 4px; + margin: 4px 4px 4px 0; + position: relative; + overflow-x: hidden; + overflow-y: auto; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +html[dir="rtl"] .select2-results { + padding: 0 4px 0 0; + margin: 4px 0 4px 4px; +} + +.select2-results ul.select2-result-sub { + margin: 0; + padding-left: 0; +} + +.select2-results li { + list-style: none; + display: list-item; + background-image: none; +} + +.select2-results li.select2-result-with-children > .select2-result-label { + font-weight: bold; +} + +.select2-results .select2-result-label { + padding: 3px 7px 4px; + margin: 0; + cursor: pointer; + + min-height: 1em; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.select2-results-dept-1 .select2-result-label { padding-left: 20px } +.select2-results-dept-2 .select2-result-label { padding-left: 40px } +.select2-results-dept-3 .select2-result-label { padding-left: 60px } +.select2-results-dept-4 .select2-result-label { padding-left: 80px } +.select2-results-dept-5 .select2-result-label { padding-left: 100px } +.select2-results-dept-6 .select2-result-label { padding-left: 110px } +.select2-results-dept-7 .select2-result-label { padding-left: 120px } + +.select2-results .select2-highlighted { + background: #3875d7; + color: #fff; +} + +.select2-results li em { + background: #feffde; + font-style: normal; +} + +.select2-results .select2-highlighted em { + background: transparent; +} + +.select2-results .select2-highlighted ul { + background: #fff; + color: #000; +} + +.select2-results .select2-no-results, +.select2-results .select2-searching, +.select2-results .select2-ajax-error, +.select2-results .select2-selection-limit { + background: #f4f4f4; + display: list-item; + padding-left: 5px; +} + +/* +disabled look for disabled choices in the results dropdown +*/ +.select2-results .select2-disabled.select2-highlighted { + color: #666; + background: #f4f4f4; + display: list-item; + cursor: default; +} +.select2-results .select2-disabled { + background: #f4f4f4; + display: list-item; + cursor: default; +} + +.select2-results .select2-selected { + display: none; +} + +.select2-more-results.select2-active { + background: #f4f4f4 no-repeat 100%; +} + +.select2-results .select2-ajax-error { + background: rgba(255, 50, 50, .2); +} + +.select2-more-results { + background: #f4f4f4; + display: list-item; +} + +/* disabled styles */ + +.select2-container.select2-container-disabled .select2-choice { + background-color: #f4f4f4; + background-image: none; + border: 1px solid #ddd; + cursor: default; +} + +.select2-container.select2-container-disabled .select2-choice .select2-arrow { + background-color: #f4f4f4; + background-image: none; + border-left: 0; +} + +.select2-container.select2-container-disabled .select2-choice abbr { + display: none; +} + + +/* multiselect */ + +.select2-container-multi .select2-choices { + height: auto !important; + height: 1%; + margin: 0; + padding: 0 5px 0 0; + position: relative; + + border: 1px solid #d1d5d6; + cursor: text; + overflow: hidden; + + background-color: #fff; + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eee), color-stop(15%, #fff)); + background-image: -webkit-linear-gradient(top, #eee 1%, #fff 15%); + background-image: -moz-linear-gradient(top, #eee 1%, #fff 15%); + background-image: linear-gradient(to bottom, #eee 1%, #fff 15%); +} + +html[dir="rtl"] .select2-container-multi .select2-choices { + padding: 0 0 0 5px; +} + +.select2-locked { + padding: 3px 5px 3px 5px !important; +} + +.select2-container-multi .select2-choices { + min-height: 26px; +} + +.select2-container-multi.select2-container-active .select2-choices { + border: 1px solid ; + outline: none; + + -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3); + box-shadow: 0 0 5px rgba(0, 0, 0, .3); +} +.select2-container-multi .select2-choices li { + float: left; + list-style: none; +} +html[dir="rtl"] .select2-container-multi .select2-choices li +{ + float: right; +} +.select2-container-multi .select2-choices .select2-search-field { + margin: 0; + padding: 0; + white-space: nowrap; +} + +.select2-container-multi .select2-choices .select2-search-field input { + padding: 5px; + margin: 1px 0; + + font-family: sans-serif; + font-size: 100%; + color: #666; + outline: 0; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + background: transparent !important; +} + +.select2-container-multi .select2-choices .select2-search-field input.select2-active { + background: #fff no-repeat 100% !important; +} + +.select2-default { + color: #999 !important; +} + +.select2-container-multi .select2-choices .select2-search-choice { + padding: 3px 5px 3px 18px; + margin: 3px 0 3px 5px; + position: relative; + + line-height: 13px; + color: #333; + cursor: default; + border: 1px solid #d1d5d6; + + border-radius: 3px; + + -webkit-box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05); + box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05); + + background-clip: padding-box; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + background-color: #e4e4e4; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#f4f4f4', GradientType=0); + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eee)); + background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); + background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); + background-image: linear-gradient(to top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); +} +html[dir="rtl"] .select2-container-multi .select2-choices .select2-search-choice +{ + margin: 3px 5px 3px 0; + padding: 3px 18px 3px 5px; +} +.select2-container-multi .select2-choices .select2-search-choice .select2-chosen { + cursor: default; +} +.select2-container-multi .select2-choices .select2-search-choice-focus { + background: #d4d4d4; +} + +.select2-search-choice-close { + display: block; + width: 12px; + height: 13px; + position: absolute; + right: 3px; + top: 4px; + + font-size: 1px; + outline: none; + background: url('../img/select2.png') right top no-repeat; +} +html[dir="rtl"] .select2-search-choice-close { + right: auto; + left: 3px; +} + +.select2-container-multi .select2-search-choice-close { + left: 3px; +} + +html[dir="rtl"] .select2-container-multi .select2-search-choice-close { + left: auto; + right: 2px; +} + +.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover { + background-position: right -11px; +} +.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close { + background-position: right -11px; +} + +/* disabled styles */ +.select2-container-multi.select2-container-disabled .select2-choices { + background-color: #f4f4f4; + background-image: none; + border: 1px solid #ddd; + cursor: default; +} + +.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice { + padding: 3px 5px 3px 5px; + border: 1px solid #ddd; + background-image: none; + background-color: #f4f4f4; +} + +.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { display: none; + background: none; +} +/* end multiselect */ + + +.select2-result-selectable .select2-match, +.select2-result-unselectable .select2-match { + text-decoration: underline; +} + +.select2-offscreen, .select2-offscreen:focus { + clip: rect(0 0 0 0) !important; + width: 1px !important; + height: 1px !important; + border: 0 !important; + margin: 0 !important; + padding: 0 !important; + overflow: hidden !important; + position: absolute !important; + outline: 0 !important; + left: 0px !important; + top: 0px !important; +} + +.select2-display-none { + display: none; +} + +.select2-measure-scrollbar { + position: absolute; + top: -10000px; + left: -10000px; + width: 100px; + height: 100px; + overflow: scroll; +} + +/* Retina-ize icons */ + +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 2dppx) { + .select2-search input, + .select2-search-choice-close, + .select2-container .select2-choice abbr, + .select2-container .select2-choice .select2-arrow b { + background-image: url('select2x2.png') !important; + background-repeat: no-repeat !important; + background-size: 60px 40px !important; + } + + .select2-search input { + background-position: 100% -21px !important; + } +} diff --git a/frontend/client/img/select2.png b/frontend/client/img/select2.png new file mode 100644 index 0000000000000000000000000000000000000000..1d804ffb99699b9e030f1010314de0970b5a000d GIT binary patch literal 613 zcmV-r0-F7aP)#WY!I$JQV$)A5aAS1BM||2XVJl=+L1^1S1H% zM-&lx?NZpUrHhn>fk<>POqf2sh40}xxGZfc+t+#Eb(qHy9_3*1(U%t9t)QDnI#YAL(|ACV(>)>6WD-t!8tutHkdb^#3`HzoJG3A2@T`% zA|K@o*b!`R#(7)PWrMFn2))Ca3MR4(zaT`Zr61*kZK5NPnZwQszxh$fyv3?&4c>$q z2m=+yc0dRXRAsPDxF6sD;@rK4JGdR_``1S~o6Xi@2&aR6hcSrEp9HVRzEqVDqBn<1%hR=D4e1f^ra^A|34Cjc=Gny{F(o#MrvPYgZuTJOz(n)-F<| zj()qR;C={)N<0RRvDZ^@6ND+W*}gh-Lip(MDt!(zMSO)!j2j+*hxgzC-e3$@(O2p* zu;+gddm(cZwXTCLx*Ky4THOa*^b^F`woveIeCK^0aR|TJ00000NkvXXu0mjfA#WC6 literal 0 HcmV?d00001 diff --git a/frontend/client/lib/select2.min.js b/frontend/client/lib/select2.min.js new file mode 100644 index 0000000000..1d3ee49f34 --- /dev/null +++ b/frontend/client/lib/select2.min.js @@ -0,0 +1,23 @@ +/* +Copyright 2014 Igor Vaynberg + +Version: 3.5.1 Timestamp: Tue Jul 22 18:58:56 EDT 2014 + +This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU +General Public License version 2 (the "GPL License"). You may choose either license to govern your +use of this software only upon the condition that you accept all of the terms of either the Apache +License or the GPL License. + +You may obtain a copy of the Apache License and the GPL License at: + +http://www.apache.org/licenses/LICENSE-2.0 +http://www.gnu.org/licenses/gpl-2.0.html + +Unless required by applicable law or agreed to in writing, software distributed under the Apache License +or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +either express or implied. See the Apache License and the GPL License for the specific language governing +permissions and limitations under the Apache License and the GPL License. +*/ +!function(a){"undefined"==typeof a.fn.each2&&a.extend(a.fn,{each2:function(b){for(var c=a([0]),d=-1,e=this.length;++dc;c+=1)if(r(a,b[c]))return c;return-1}function q(){var b=a(l);b.appendTo("body");var c={width:b.width()-b[0].clientWidth,height:b.height()-b[0].clientHeight};return b.remove(),c}function r(a,c){return a===c?!0:a===b||c===b?!1:null===a||null===c?!1:a.constructor===String?a+""==c+"":c.constructor===String?c+""==a+"":!1}function s(b,c){var d,e,f;if(null===b||b.length<1)return[];for(d=b.split(c),e=0,f=d.length;f>e;e+=1)d[e]=a.trim(d[e]);return d}function t(a){return a.outerWidth(!1)-a.width()}function u(c){var d="keyup-change-value";c.on("keydown",function(){a.data(c,d)===b&&a.data(c,d,c.val())}),c.on("keyup",function(){var e=a.data(c,d);e!==b&&c.val()!==e&&(a.removeData(c,d),c.trigger("keyup-change"))})}function v(c){c.on("mousemove",function(c){var d=i;(d===b||d.x!==c.pageX||d.y!==c.pageY)&&a(c.target).trigger("mousemove-filtered",c)})}function w(a,c,d){d=d||b;var e;return function(){var b=arguments;window.clearTimeout(e),e=window.setTimeout(function(){c.apply(d,b)},a)}}function x(a,b){var c=w(a,function(a){b.trigger("scroll-debounced",a)});b.on("scroll",function(a){p(a.target,b.get())>=0&&c(a)})}function y(a){a[0]!==document.activeElement&&window.setTimeout(function(){var d,b=a[0],c=a.val().length;a.focus();var e=b.offsetWidth>0||b.offsetHeight>0;e&&b===document.activeElement&&(b.setSelectionRange?b.setSelectionRange(c,c):b.createTextRange&&(d=b.createTextRange(),d.collapse(!1),d.select()))},0)}function z(b){b=a(b)[0];var c=0,d=0;if("selectionStart"in b)c=b.selectionStart,d=b.selectionEnd-c;else if("selection"in document){b.focus();var e=document.selection.createRange();d=document.selection.createRange().text.length,e.moveStart("character",-b.value.length),c=e.text.length-d}return{offset:c,length:d}}function A(a){a.preventDefault(),a.stopPropagation()}function B(a){a.preventDefault(),a.stopImmediatePropagation()}function C(b){if(!h){var c=b[0].currentStyle||window.getComputedStyle(b[0],null);h=a(document.createElement("div")).css({position:"absolute",left:"-10000px",top:"-10000px",display:"none",fontSize:c.fontSize,fontFamily:c.fontFamily,fontStyle:c.fontStyle,fontWeight:c.fontWeight,letterSpacing:c.letterSpacing,textTransform:c.textTransform,whiteSpace:"nowrap"}),h.attr("class","select2-sizer"),a("body").append(h)}return h.text(b.val()),h.width()}function D(b,c,d){var e,g,f=[];e=a.trim(b.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each2(function(){0===this.indexOf("select2-")&&f.push(this)})),e=a.trim(c.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each2(function(){0!==this.indexOf("select2-")&&(g=d(this),g&&f.push(g))})),b.attr("class",f.join(" "))}function E(a,b,c,d){var e=o(a.toUpperCase()).indexOf(o(b.toUpperCase())),f=b.length;return 0>e?(c.push(d(a)),void 0):(c.push(d(a.substring(0,e))),c.push(""),c.push(d(a.substring(e,e+f))),c.push(""),c.push(d(a.substring(e+f,a.length))),void 0)}function F(a){var b={"\\":"\","&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};return String(a).replace(/[&<>"'\/\\]/g,function(a){return b[a]})}function G(c){var d,e=null,f=c.quietMillis||100,g=c.url,h=this;return function(i){window.clearTimeout(d),d=window.setTimeout(function(){var d=c.data,f=g,j=c.transport||a.fn.select2.ajaxDefaults.transport,k={type:c.type||"GET",cache:c.cache||!1,jsonpCallback:c.jsonpCallback||b,dataType:c.dataType||"json"},l=a.extend({},a.fn.select2.ajaxDefaults.params,k);d=d?d.call(h,i.term,i.page,i.context):null,f="function"==typeof f?f.call(h,i.term,i.page,i.context):f,e&&"function"==typeof e.abort&&e.abort(),c.params&&(a.isFunction(c.params)?a.extend(l,c.params.call(h)):a.extend(l,c.params)),a.extend(l,{url:f,dataType:c.dataType,data:d,success:function(a){var b=c.results(a,i.page,i);i.callback(b)},error:function(a,b,c){var d={hasError:!0,jqXHR:a,textStatus:b,errorThrown:c};i.callback(d)}}),e=j.call(h,l)},f)}}function H(b){var d,e,c=b,f=function(a){return""+a.text};a.isArray(c)&&(e=c,c={results:e}),a.isFunction(c)===!1&&(e=c,c=function(){return e});var g=c();return g.text&&(f=g.text,a.isFunction(f)||(d=g.text,f=function(a){return a[d]})),function(b){var g,d=b.term,e={results:[]};return""===d?(b.callback(c()),void 0):(g=function(c,e){var h,i;if(c=c[0],c.children){h={};for(i in c)c.hasOwnProperty(i)&&(h[i]=c[i]);h.children=[],a(c.children).each2(function(a,b){g(b,h.children)}),(h.children.length||b.matcher(d,f(h),c))&&e.push(h)}else b.matcher(d,f(c),c)&&e.push(c)},a(c().results).each2(function(a,b){g(b,e.results)}),b.callback(e),void 0)}}function I(c){var d=a.isFunction(c);return function(e){var f=e.term,g={results:[]},h=d?c(e):c;a.isArray(h)&&(a(h).each(function(){var a=this.text!==b,c=a?this.text:this;(""===f||e.matcher(f,c))&&g.results.push(a?this:{id:this,text:this})}),e.callback(g))}}function J(b,c){if(a.isFunction(b))return!0;if(!b)return!1;if("string"==typeof b)return!0;throw new Error(c+" must be a string, function, or falsy value")}function K(b,c){if(a.isFunction(b)){var d=Array.prototype.slice.call(arguments,2);return b.apply(c,d)}return b}function L(b){var c=0;return a.each(b,function(a,b){b.children?c+=L(b.children):c++}),c}function M(a,c,d,e){var h,i,j,k,l,f=a,g=!1;if(!e.createSearchChoice||!e.tokenSeparators||e.tokenSeparators.length<1)return b;for(;;){for(i=-1,j=0,k=e.tokenSeparators.length;k>j&&(l=e.tokenSeparators[j],i=a.indexOf(l),!(i>=0));j++);if(0>i)break;if(h=a.substring(0,i),a=a.substring(i+l.length),h.length>0&&(h=e.createSearchChoice.call(this,h,c),h!==b&&null!==h&&e.id(h)!==b&&null!==e.id(h))){for(g=!1,j=0,k=c.length;k>j;j++)if(r(e.id(h),e.id(c[j]))){g=!0;break}g||d(h)}}return f!==a?a:void 0}function N(){var b=this;a.each(arguments,function(a,c){b[c].remove(),b[c]=null})}function O(b,c){var d=function(){};return d.prototype=new b,d.prototype.constructor=d,d.prototype.parent=b.prototype,d.prototype=a.extend(d.prototype,c),d}if(window.Select2===b){var c,d,e,f,g,h,j,k,i={x:0,y:0},c={TAB:9,ENTER:13,ESC:27,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40,SHIFT:16,CTRL:17,ALT:18,PAGE_UP:33,PAGE_DOWN:34,HOME:36,END:35,BACKSPACE:8,DELETE:46,isArrow:function(a){switch(a=a.which?a.which:a){case c.LEFT:case c.RIGHT:case c.UP:case c.DOWN:return!0}return!1},isControl:function(a){var b=a.which;switch(b){case c.SHIFT:case c.CTRL:case c.ALT:return!0}return a.metaKey?!0:!1},isFunctionKey:function(a){return a=a.which?a.which:a,a>=112&&123>=a}},l="
",m={"\u24b6":"A","\uff21":"A","\xc0":"A","\xc1":"A","\xc2":"A","\u1ea6":"A","\u1ea4":"A","\u1eaa":"A","\u1ea8":"A","\xc3":"A","\u0100":"A","\u0102":"A","\u1eb0":"A","\u1eae":"A","\u1eb4":"A","\u1eb2":"A","\u0226":"A","\u01e0":"A","\xc4":"A","\u01de":"A","\u1ea2":"A","\xc5":"A","\u01fa":"A","\u01cd":"A","\u0200":"A","\u0202":"A","\u1ea0":"A","\u1eac":"A","\u1eb6":"A","\u1e00":"A","\u0104":"A","\u023a":"A","\u2c6f":"A","\ua732":"AA","\xc6":"AE","\u01fc":"AE","\u01e2":"AE","\ua734":"AO","\ua736":"AU","\ua738":"AV","\ua73a":"AV","\ua73c":"AY","\u24b7":"B","\uff22":"B","\u1e02":"B","\u1e04":"B","\u1e06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24b8":"C","\uff23":"C","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\xc7":"C","\u1e08":"C","\u0187":"C","\u023b":"C","\ua73e":"C","\u24b9":"D","\uff24":"D","\u1e0a":"D","\u010e":"D","\u1e0c":"D","\u1e10":"D","\u1e12":"D","\u1e0e":"D","\u0110":"D","\u018b":"D","\u018a":"D","\u0189":"D","\ua779":"D","\u01f1":"DZ","\u01c4":"DZ","\u01f2":"Dz","\u01c5":"Dz","\u24ba":"E","\uff25":"E","\xc8":"E","\xc9":"E","\xca":"E","\u1ec0":"E","\u1ebe":"E","\u1ec4":"E","\u1ec2":"E","\u1ebc":"E","\u0112":"E","\u1e14":"E","\u1e16":"E","\u0114":"E","\u0116":"E","\xcb":"E","\u1eba":"E","\u011a":"E","\u0204":"E","\u0206":"E","\u1eb8":"E","\u1ec6":"E","\u0228":"E","\u1e1c":"E","\u0118":"E","\u1e18":"E","\u1e1a":"E","\u0190":"E","\u018e":"E","\u24bb":"F","\uff26":"F","\u1e1e":"F","\u0191":"F","\ua77b":"F","\u24bc":"G","\uff27":"G","\u01f4":"G","\u011c":"G","\u1e20":"G","\u011e":"G","\u0120":"G","\u01e6":"G","\u0122":"G","\u01e4":"G","\u0193":"G","\ua7a0":"G","\ua77d":"G","\ua77e":"G","\u24bd":"H","\uff28":"H","\u0124":"H","\u1e22":"H","\u1e26":"H","\u021e":"H","\u1e24":"H","\u1e28":"H","\u1e2a":"H","\u0126":"H","\u2c67":"H","\u2c75":"H","\ua78d":"H","\u24be":"I","\uff29":"I","\xcc":"I","\xcd":"I","\xce":"I","\u0128":"I","\u012a":"I","\u012c":"I","\u0130":"I","\xcf":"I","\u1e2e":"I","\u1ec8":"I","\u01cf":"I","\u0208":"I","\u020a":"I","\u1eca":"I","\u012e":"I","\u1e2c":"I","\u0197":"I","\u24bf":"J","\uff2a":"J","\u0134":"J","\u0248":"J","\u24c0":"K","\uff2b":"K","\u1e30":"K","\u01e8":"K","\u1e32":"K","\u0136":"K","\u1e34":"K","\u0198":"K","\u2c69":"K","\ua740":"K","\ua742":"K","\ua744":"K","\ua7a2":"K","\u24c1":"L","\uff2c":"L","\u013f":"L","\u0139":"L","\u013d":"L","\u1e36":"L","\u1e38":"L","\u013b":"L","\u1e3c":"L","\u1e3a":"L","\u0141":"L","\u023d":"L","\u2c62":"L","\u2c60":"L","\ua748":"L","\ua746":"L","\ua780":"L","\u01c7":"LJ","\u01c8":"Lj","\u24c2":"M","\uff2d":"M","\u1e3e":"M","\u1e40":"M","\u1e42":"M","\u2c6e":"M","\u019c":"M","\u24c3":"N","\uff2e":"N","\u01f8":"N","\u0143":"N","\xd1":"N","\u1e44":"N","\u0147":"N","\u1e46":"N","\u0145":"N","\u1e4a":"N","\u1e48":"N","\u0220":"N","\u019d":"N","\ua790":"N","\ua7a4":"N","\u01ca":"NJ","\u01cb":"Nj","\u24c4":"O","\uff2f":"O","\xd2":"O","\xd3":"O","\xd4":"O","\u1ed2":"O","\u1ed0":"O","\u1ed6":"O","\u1ed4":"O","\xd5":"O","\u1e4c":"O","\u022c":"O","\u1e4e":"O","\u014c":"O","\u1e50":"O","\u1e52":"O","\u014e":"O","\u022e":"O","\u0230":"O","\xd6":"O","\u022a":"O","\u1ece":"O","\u0150":"O","\u01d1":"O","\u020c":"O","\u020e":"O","\u01a0":"O","\u1edc":"O","\u1eda":"O","\u1ee0":"O","\u1ede":"O","\u1ee2":"O","\u1ecc":"O","\u1ed8":"O","\u01ea":"O","\u01ec":"O","\xd8":"O","\u01fe":"O","\u0186":"O","\u019f":"O","\ua74a":"O","\ua74c":"O","\u01a2":"OI","\ua74e":"OO","\u0222":"OU","\u24c5":"P","\uff30":"P","\u1e54":"P","\u1e56":"P","\u01a4":"P","\u2c63":"P","\ua750":"P","\ua752":"P","\ua754":"P","\u24c6":"Q","\uff31":"Q","\ua756":"Q","\ua758":"Q","\u024a":"Q","\u24c7":"R","\uff32":"R","\u0154":"R","\u1e58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1e5a":"R","\u1e5c":"R","\u0156":"R","\u1e5e":"R","\u024c":"R","\u2c64":"R","\ua75a":"R","\ua7a6":"R","\ua782":"R","\u24c8":"S","\uff33":"S","\u1e9e":"S","\u015a":"S","\u1e64":"S","\u015c":"S","\u1e60":"S","\u0160":"S","\u1e66":"S","\u1e62":"S","\u1e68":"S","\u0218":"S","\u015e":"S","\u2c7e":"S","\ua7a8":"S","\ua784":"S","\u24c9":"T","\uff34":"T","\u1e6a":"T","\u0164":"T","\u1e6c":"T","\u021a":"T","\u0162":"T","\u1e70":"T","\u1e6e":"T","\u0166":"T","\u01ac":"T","\u01ae":"T","\u023e":"T","\ua786":"T","\ua728":"TZ","\u24ca":"U","\uff35":"U","\xd9":"U","\xda":"U","\xdb":"U","\u0168":"U","\u1e78":"U","\u016a":"U","\u1e7a":"U","\u016c":"U","\xdc":"U","\u01db":"U","\u01d7":"U","\u01d5":"U","\u01d9":"U","\u1ee6":"U","\u016e":"U","\u0170":"U","\u01d3":"U","\u0214":"U","\u0216":"U","\u01af":"U","\u1eea":"U","\u1ee8":"U","\u1eee":"U","\u1eec":"U","\u1ef0":"U","\u1ee4":"U","\u1e72":"U","\u0172":"U","\u1e76":"U","\u1e74":"U","\u0244":"U","\u24cb":"V","\uff36":"V","\u1e7c":"V","\u1e7e":"V","\u01b2":"V","\ua75e":"V","\u0245":"V","\ua760":"VY","\u24cc":"W","\uff37":"W","\u1e80":"W","\u1e82":"W","\u0174":"W","\u1e86":"W","\u1e84":"W","\u1e88":"W","\u2c72":"W","\u24cd":"X","\uff38":"X","\u1e8a":"X","\u1e8c":"X","\u24ce":"Y","\uff39":"Y","\u1ef2":"Y","\xdd":"Y","\u0176":"Y","\u1ef8":"Y","\u0232":"Y","\u1e8e":"Y","\u0178":"Y","\u1ef6":"Y","\u1ef4":"Y","\u01b3":"Y","\u024e":"Y","\u1efe":"Y","\u24cf":"Z","\uff3a":"Z","\u0179":"Z","\u1e90":"Z","\u017b":"Z","\u017d":"Z","\u1e92":"Z","\u1e94":"Z","\u01b5":"Z","\u0224":"Z","\u2c7f":"Z","\u2c6b":"Z","\ua762":"Z","\u24d0":"a","\uff41":"a","\u1e9a":"a","\xe0":"a","\xe1":"a","\xe2":"a","\u1ea7":"a","\u1ea5":"a","\u1eab":"a","\u1ea9":"a","\xe3":"a","\u0101":"a","\u0103":"a","\u1eb1":"a","\u1eaf":"a","\u1eb5":"a","\u1eb3":"a","\u0227":"a","\u01e1":"a","\xe4":"a","\u01df":"a","\u1ea3":"a","\xe5":"a","\u01fb":"a","\u01ce":"a","\u0201":"a","\u0203":"a","\u1ea1":"a","\u1ead":"a","\u1eb7":"a","\u1e01":"a","\u0105":"a","\u2c65":"a","\u0250":"a","\ua733":"aa","\xe6":"ae","\u01fd":"ae","\u01e3":"ae","\ua735":"ao","\ua737":"au","\ua739":"av","\ua73b":"av","\ua73d":"ay","\u24d1":"b","\uff42":"b","\u1e03":"b","\u1e05":"b","\u1e07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24d2":"c","\uff43":"c","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\xe7":"c","\u1e09":"c","\u0188":"c","\u023c":"c","\ua73f":"c","\u2184":"c","\u24d3":"d","\uff44":"d","\u1e0b":"d","\u010f":"d","\u1e0d":"d","\u1e11":"d","\u1e13":"d","\u1e0f":"d","\u0111":"d","\u018c":"d","\u0256":"d","\u0257":"d","\ua77a":"d","\u01f3":"dz","\u01c6":"dz","\u24d4":"e","\uff45":"e","\xe8":"e","\xe9":"e","\xea":"e","\u1ec1":"e","\u1ebf":"e","\u1ec5":"e","\u1ec3":"e","\u1ebd":"e","\u0113":"e","\u1e15":"e","\u1e17":"e","\u0115":"e","\u0117":"e","\xeb":"e","\u1ebb":"e","\u011b":"e","\u0205":"e","\u0207":"e","\u1eb9":"e","\u1ec7":"e","\u0229":"e","\u1e1d":"e","\u0119":"e","\u1e19":"e","\u1e1b":"e","\u0247":"e","\u025b":"e","\u01dd":"e","\u24d5":"f","\uff46":"f","\u1e1f":"f","\u0192":"f","\ua77c":"f","\u24d6":"g","\uff47":"g","\u01f5":"g","\u011d":"g","\u1e21":"g","\u011f":"g","\u0121":"g","\u01e7":"g","\u0123":"g","\u01e5":"g","\u0260":"g","\ua7a1":"g","\u1d79":"g","\ua77f":"g","\u24d7":"h","\uff48":"h","\u0125":"h","\u1e23":"h","\u1e27":"h","\u021f":"h","\u1e25":"h","\u1e29":"h","\u1e2b":"h","\u1e96":"h","\u0127":"h","\u2c68":"h","\u2c76":"h","\u0265":"h","\u0195":"hv","\u24d8":"i","\uff49":"i","\xec":"i","\xed":"i","\xee":"i","\u0129":"i","\u012b":"i","\u012d":"i","\xef":"i","\u1e2f":"i","\u1ec9":"i","\u01d0":"i","\u0209":"i","\u020b":"i","\u1ecb":"i","\u012f":"i","\u1e2d":"i","\u0268":"i","\u0131":"i","\u24d9":"j","\uff4a":"j","\u0135":"j","\u01f0":"j","\u0249":"j","\u24da":"k","\uff4b":"k","\u1e31":"k","\u01e9":"k","\u1e33":"k","\u0137":"k","\u1e35":"k","\u0199":"k","\u2c6a":"k","\ua741":"k","\ua743":"k","\ua745":"k","\ua7a3":"k","\u24db":"l","\uff4c":"l","\u0140":"l","\u013a":"l","\u013e":"l","\u1e37":"l","\u1e39":"l","\u013c":"l","\u1e3d":"l","\u1e3b":"l","\u017f":"l","\u0142":"l","\u019a":"l","\u026b":"l","\u2c61":"l","\ua749":"l","\ua781":"l","\ua747":"l","\u01c9":"lj","\u24dc":"m","\uff4d":"m","\u1e3f":"m","\u1e41":"m","\u1e43":"m","\u0271":"m","\u026f":"m","\u24dd":"n","\uff4e":"n","\u01f9":"n","\u0144":"n","\xf1":"n","\u1e45":"n","\u0148":"n","\u1e47":"n","\u0146":"n","\u1e4b":"n","\u1e49":"n","\u019e":"n","\u0272":"n","\u0149":"n","\ua791":"n","\ua7a5":"n","\u01cc":"nj","\u24de":"o","\uff4f":"o","\xf2":"o","\xf3":"o","\xf4":"o","\u1ed3":"o","\u1ed1":"o","\u1ed7":"o","\u1ed5":"o","\xf5":"o","\u1e4d":"o","\u022d":"o","\u1e4f":"o","\u014d":"o","\u1e51":"o","\u1e53":"o","\u014f":"o","\u022f":"o","\u0231":"o","\xf6":"o","\u022b":"o","\u1ecf":"o","\u0151":"o","\u01d2":"o","\u020d":"o","\u020f":"o","\u01a1":"o","\u1edd":"o","\u1edb":"o","\u1ee1":"o","\u1edf":"o","\u1ee3":"o","\u1ecd":"o","\u1ed9":"o","\u01eb":"o","\u01ed":"o","\xf8":"o","\u01ff":"o","\u0254":"o","\ua74b":"o","\ua74d":"o","\u0275":"o","\u01a3":"oi","\u0223":"ou","\ua74f":"oo","\u24df":"p","\uff50":"p","\u1e55":"p","\u1e57":"p","\u01a5":"p","\u1d7d":"p","\ua751":"p","\ua753":"p","\ua755":"p","\u24e0":"q","\uff51":"q","\u024b":"q","\ua757":"q","\ua759":"q","\u24e1":"r","\uff52":"r","\u0155":"r","\u1e59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1e5b":"r","\u1e5d":"r","\u0157":"r","\u1e5f":"r","\u024d":"r","\u027d":"r","\ua75b":"r","\ua7a7":"r","\ua783":"r","\u24e2":"s","\uff53":"s","\xdf":"s","\u015b":"s","\u1e65":"s","\u015d":"s","\u1e61":"s","\u0161":"s","\u1e67":"s","\u1e63":"s","\u1e69":"s","\u0219":"s","\u015f":"s","\u023f":"s","\ua7a9":"s","\ua785":"s","\u1e9b":"s","\u24e3":"t","\uff54":"t","\u1e6b":"t","\u1e97":"t","\u0165":"t","\u1e6d":"t","\u021b":"t","\u0163":"t","\u1e71":"t","\u1e6f":"t","\u0167":"t","\u01ad":"t","\u0288":"t","\u2c66":"t","\ua787":"t","\ua729":"tz","\u24e4":"u","\uff55":"u","\xf9":"u","\xfa":"u","\xfb":"u","\u0169":"u","\u1e79":"u","\u016b":"u","\u1e7b":"u","\u016d":"u","\xfc":"u","\u01dc":"u","\u01d8":"u","\u01d6":"u","\u01da":"u","\u1ee7":"u","\u016f":"u","\u0171":"u","\u01d4":"u","\u0215":"u","\u0217":"u","\u01b0":"u","\u1eeb":"u","\u1ee9":"u","\u1eef":"u","\u1eed":"u","\u1ef1":"u","\u1ee5":"u","\u1e73":"u","\u0173":"u","\u1e77":"u","\u1e75":"u","\u0289":"u","\u24e5":"v","\uff56":"v","\u1e7d":"v","\u1e7f":"v","\u028b":"v","\ua75f":"v","\u028c":"v","\ua761":"vy","\u24e6":"w","\uff57":"w","\u1e81":"w","\u1e83":"w","\u0175":"w","\u1e87":"w","\u1e85":"w","\u1e98":"w","\u1e89":"w","\u2c73":"w","\u24e7":"x","\uff58":"x","\u1e8b":"x","\u1e8d":"x","\u24e8":"y","\uff59":"y","\u1ef3":"y","\xfd":"y","\u0177":"y","\u1ef9":"y","\u0233":"y","\u1e8f":"y","\xff":"y","\u1ef7":"y","\u1e99":"y","\u1ef5":"y","\u01b4":"y","\u024f":"y","\u1eff":"y","\u24e9":"z","\uff5a":"z","\u017a":"z","\u1e91":"z","\u017c":"z","\u017e":"z","\u1e93":"z","\u1e95":"z","\u01b6":"z","\u0225":"z","\u0240":"z","\u2c6c":"z","\ua763":"z","\u0386":"\u0391","\u0388":"\u0395","\u0389":"\u0397","\u038a":"\u0399","\u03aa":"\u0399","\u038c":"\u039f","\u038e":"\u03a5","\u03ab":"\u03a5","\u038f":"\u03a9","\u03ac":"\u03b1","\u03ad":"\u03b5","\u03ae":"\u03b7","\u03af":"\u03b9","\u03ca":"\u03b9","\u0390":"\u03b9","\u03cc":"\u03bf","\u03cd":"\u03c5","\u03cb":"\u03c5","\u03b0":"\u03c5","\u03c9":"\u03c9","\u03c2":"\u03c3"};j=a(document),g=function(){var a=1;return function(){return a++}}(),d=O(Object,{bind:function(a){var b=this;return function(){a.apply(b,arguments)}},init:function(c){var d,e,f=".select2-results";this.opts=c=this.prepareOpts(c),this.id=c.id,c.element.data("select2")!==b&&null!==c.element.data("select2")&&c.element.data("select2").destroy(),this.container=this.createContainer(),this.liveRegion=a("",{role:"status","aria-live":"polite"}).addClass("select2-hidden-accessible").appendTo(document.body),this.containerId="s2id_"+(c.element.attr("id")||"autogen"+g()),this.containerEventName=this.containerId.replace(/([.])/g,"_").replace(/([;&,\-\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g,"\\$1"),this.container.attr("id",this.containerId),this.container.attr("title",c.element.attr("title")),this.body=a("body"),D(this.container,this.opts.element,this.opts.adaptContainerCssClass),this.container.attr("style",c.element.attr("style")),this.container.css(K(c.containerCss,this.opts.element)),this.container.addClass(K(c.containerCssClass,this.opts.element)),this.elementTabIndex=this.opts.element.attr("tabindex"),this.opts.element.data("select2",this).attr("tabindex","-1").before(this.container).on("click.select2",A),this.container.data("select2",this),this.dropdown=this.container.find(".select2-drop"),D(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass),this.dropdown.addClass(K(c.dropdownCssClass,this.opts.element)),this.dropdown.data("select2",this),this.dropdown.on("click",A),this.results=d=this.container.find(f),this.search=e=this.container.find("input.select2-input"),this.queryCount=0,this.resultsPage=0,this.context=null,this.initContainer(),this.container.on("click",A),v(this.results),this.dropdown.on("mousemove-filtered",f,this.bind(this.highlightUnderEvent)),this.dropdown.on("touchstart touchmove touchend",f,this.bind(function(a){this._touchEvent=!0,this.highlightUnderEvent(a)})),this.dropdown.on("touchmove",f,this.bind(this.touchMoved)),this.dropdown.on("touchstart touchend",f,this.bind(this.clearTouchMoved)),this.dropdown.on("click",this.bind(function(){this._touchEvent&&(this._touchEvent=!1,this.selectHighlighted())})),x(80,this.results),this.dropdown.on("scroll-debounced",f,this.bind(this.loadMoreIfNeeded)),a(this.container).on("change",".select2-input",function(a){a.stopPropagation()}),a(this.dropdown).on("change",".select2-input",function(a){a.stopPropagation()}),a.fn.mousewheel&&d.mousewheel(function(a,b,c,e){var f=d.scrollTop();e>0&&0>=f-e?(d.scrollTop(0),A(a)):0>e&&d.get(0).scrollHeight-d.scrollTop()+e<=d.height()&&(d.scrollTop(d.get(0).scrollHeight-d.height()),A(a))}),u(e),e.on("keyup-change input paste",this.bind(this.updateResults)),e.on("focus",function(){e.addClass("select2-focused")}),e.on("blur",function(){e.removeClass("select2-focused")}),this.dropdown.on("mouseup",f,this.bind(function(b){a(b.target).closest(".select2-result-selectable").length>0&&(this.highlightUnderEvent(b),this.selectHighlighted(b))})),this.dropdown.on("click mouseup mousedown touchstart touchend focusin",function(a){a.stopPropagation()}),this.nextSearchTerm=b,a.isFunction(this.opts.initSelection)&&(this.initSelection(),this.monitorSource()),null!==c.maximumInputLength&&this.search.attr("maxlength",c.maximumInputLength);var h=c.element.prop("disabled");h===b&&(h=!1),this.enable(!h);var i=c.element.prop("readonly");i===b&&(i=!1),this.readonly(i),k=k||q(),this.autofocus=c.element.prop("autofocus"),c.element.prop("autofocus",!1),this.autofocus&&this.focus(),this.search.attr("placeholder",c.searchInputPlaceholder)},destroy:function(){var a=this.opts.element,c=a.data("select2"),d=this;this.close(),a.length&&a[0].detachEvent&&a.each(function(){this.detachEvent("onpropertychange",d._sync)}),this.propertyObserver&&(this.propertyObserver.disconnect(),this.propertyObserver=null),this._sync=null,c!==b&&(c.container.remove(),c.liveRegion.remove(),c.dropdown.remove(),a.removeClass("select2-offscreen").removeData("select2").off(".select2").prop("autofocus",this.autofocus||!1),this.elementTabIndex?a.attr({tabindex:this.elementTabIndex}):a.removeAttr("tabindex"),a.show()),N.call(this,"container","liveRegion","dropdown","results","search")},optionToData:function(a){return a.is("option")?{id:a.prop("value"),text:a.text(),element:a.get(),css:a.attr("class"),disabled:a.prop("disabled"),locked:r(a.attr("locked"),"locked")||r(a.data("locked"),!0)}:a.is("optgroup")?{text:a.attr("label"),children:[],element:a.get(),css:a.attr("class")}:void 0},prepareOpts:function(c){var d,e,f,h,i=this;if(d=c.element,"select"===d.get(0).tagName.toLowerCase()&&(this.select=e=c.element),e&&a.each(["id","multiple","ajax","query","createSearchChoice","initSelection","data","tags"],function(){if(this in c)throw new Error("Option '"+this+"' is not allowed for Select2 when attached to a ","
"," ","
    ","
","
"].join(""));return b},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.focusser.prop("disabled",!this.isInterfaceEnabled())},opening:function(){var c,d,e;this.opts.minimumResultsForSearch>=0&&this.showSearch(!0),this.parent.opening.apply(this,arguments),this.showSearchInput!==!1&&this.search.val(this.focusser.val()),this.opts.shouldFocusInput(this)&&(this.search.focus(),c=this.search.get(0),c.createTextRange?(d=c.createTextRange(),d.collapse(!1),d.select()):c.setSelectionRange&&(e=this.search.val().length,c.setSelectionRange(e,e))),""===this.search.val()&&this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.search.select()),this.focusser.prop("disabled",!0).val(""),this.updateResults(!0),this.opts.element.trigger(a.Event("select2-open"))},close:function(){this.opened()&&(this.parent.close.apply(this,arguments),this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus())},focus:function(){this.opened()?this.close():(this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus())},isFocused:function(){return this.container.hasClass("select2-container-active")},cancel:function(){this.parent.cancel.apply(this,arguments),this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus()},destroy:function(){a("label[for='"+this.focusser.attr("id")+"']").attr("for",this.opts.element.attr("id")),this.parent.destroy.apply(this,arguments),N.call(this,"selection","focusser")},initContainer:function(){var b,h,d=this.container,e=this.dropdown,f=g();this.opts.minimumResultsForSearch<0?this.showSearch(!1):this.showSearch(!0),this.selection=b=d.find(".select2-choice"),this.focusser=d.find(".select2-focusser"),b.find(".select2-chosen").attr("id","select2-chosen-"+f),this.focusser.attr("aria-labelledby","select2-chosen-"+f),this.results.attr("id","select2-results-"+f),this.search.attr("aria-owns","select2-results-"+f),this.focusser.attr("id","s2id_autogen"+f),h=a("label[for='"+this.opts.element.attr("id")+"']"),this.focusser.prev().text(h.text()).attr("for",this.focusser.attr("id"));var i=this.opts.element.attr("title");this.opts.element.attr("title",i||h.text()),this.focusser.attr("tabindex",this.elementTabIndex),this.search.attr("id",this.focusser.attr("id")+"_search"),this.search.prev().text(a("label[for='"+this.focusser.attr("id")+"']").text()).attr("for",this.search.attr("id")),this.search.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()&&229!=a.keyCode){if(a.which===c.PAGE_UP||a.which===c.PAGE_DOWN)return A(a),void 0;switch(a.which){case c.UP:case c.DOWN:return this.moveHighlight(a.which===c.UP?-1:1),A(a),void 0;case c.ENTER:return this.selectHighlighted(),A(a),void 0;case c.TAB:return this.selectHighlighted({noFocus:!0}),void 0;case c.ESC:return this.cancel(a),A(a),void 0}}})),this.search.on("blur",this.bind(function(){document.activeElement===this.body.get(0)&&window.setTimeout(this.bind(function(){this.opened()&&this.search.focus()}),0)})),this.focusser.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()&&a.which!==c.TAB&&!c.isControl(a)&&!c.isFunctionKey(a)&&a.which!==c.ESC){if(this.opts.openOnEnter===!1&&a.which===c.ENTER)return A(a),void 0;if(a.which==c.DOWN||a.which==c.UP||a.which==c.ENTER&&this.opts.openOnEnter){if(a.altKey||a.ctrlKey||a.shiftKey||a.metaKey)return;return this.open(),A(a),void 0}return a.which==c.DELETE||a.which==c.BACKSPACE?(this.opts.allowClear&&this.clear(),A(a),void 0):void 0}})),u(this.focusser),this.focusser.on("keyup-change input",this.bind(function(a){if(this.opts.minimumResultsForSearch>=0){if(a.stopPropagation(),this.opened())return;this.open()}})),b.on("mousedown touchstart","abbr",this.bind(function(a){this.isInterfaceEnabled()&&(this.clear(),B(a),this.close(),this.selection.focus())})),b.on("mousedown touchstart",this.bind(function(c){n(b),this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.opened()?this.close():this.isInterfaceEnabled()&&this.open(),A(c)})),e.on("mousedown touchstart",this.bind(function(){this.opts.shouldFocusInput(this)&&this.search.focus()})),b.on("focus",this.bind(function(a){A(a)})),this.focusser.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})).on("blur",this.bind(function(){this.opened()||(this.container.removeClass("select2-container-active"),this.opts.element.trigger(a.Event("select2-blur")))})),this.search.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})),this.initContainerWidth(),this.opts.element.addClass("select2-offscreen"),this.setPlaceholder()},clear:function(b){var c=this.selection.data("select2-data");if(c){var d=a.Event("select2-clearing");if(this.opts.element.trigger(d),d.isDefaultPrevented())return;var e=this.getPlaceholderOption();this.opts.element.val(e?e.val():""),this.selection.find(".select2-chosen").empty(),this.selection.removeData("select2-data"),this.setPlaceholder(),b!==!1&&(this.opts.element.trigger({type:"select2-removed",val:this.id(c),choice:c}),this.triggerChange({removed:c}))}},initSelection:function(){if(this.isPlaceholderOptionSelected())this.updateSelection(null),this.close(),this.setPlaceholder();else{var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.setPlaceholder(),c.nextSearchTerm=c.opts.nextSearchTerm(a,c.search.val()))})}},isPlaceholderOptionSelected:function(){var a;return this.getPlaceholder()===b?!1:(a=this.getPlaceholderOption())!==b&&a.prop("selected")||""===this.opts.element.val()||this.opts.element.val()===b||null===this.opts.element.val()},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=a.find("option").filter(function(){return this.selected&&!this.disabled});b(c.optionToData(d))}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=c.val(),f=null;b.query({matcher:function(a,c,d){var g=r(e,b.id(d));return g&&(f=d),g},callback:a.isFunction(d)?function(){d(f)}:a.noop})}),b},getPlaceholder:function(){return this.select&&this.getPlaceholderOption()===b?b:this.parent.getPlaceholder.apply(this,arguments)},setPlaceholder:function(){var a=this.getPlaceholder();if(this.isPlaceholderOptionSelected()&&a!==b){if(this.select&&this.getPlaceholderOption()===b)return;this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(a)),this.selection.addClass("select2-default"),this.container.removeClass("select2-allowclear")}},postprocessResults:function(a,b,c){var d=0,e=this;if(this.findHighlightableChoices().each2(function(a,b){return r(e.id(b.data("select2-data")),e.opts.element.val())?(d=a,!1):void 0}),c!==!1&&(b===!0&&d>=0?this.highlight(d):this.highlight(0)),b===!0){var g=this.opts.minimumResultsForSearch;g>=0&&this.showSearch(L(a.results)>=g)}},showSearch:function(b){this.showSearchInput!==b&&(this.showSearchInput=b,this.dropdown.find(".select2-search").toggleClass("select2-search-hidden",!b),this.dropdown.find(".select2-search").toggleClass("select2-offscreen",!b),a(this.dropdown,this.container).toggleClass("select2-with-searchbox",b))},onSelect:function(a,b){if(this.triggerSelect(a)){var c=this.opts.element.val(),d=this.data();this.opts.element.val(this.id(a)),this.updateSelection(a),this.opts.element.trigger({type:"select2-selected",val:this.id(a),choice:a}),this.nextSearchTerm=this.opts.nextSearchTerm(a,this.search.val()),this.close(),b&&b.noFocus||!this.opts.shouldFocusInput(this)||this.focusser.focus(),r(c,this.id(a))||this.triggerChange({added:a,removed:d})}},updateSelection:function(a){var d,e,c=this.selection.find(".select2-chosen");this.selection.data("select2-data",a),c.empty(),null!==a&&(d=this.opts.formatSelection(a,c,this.opts.escapeMarkup)),d!==b&&c.append(d),e=this.opts.formatSelectionCssClass(a,c),e!==b&&c.addClass(e),this.selection.removeClass("select2-default"),this.opts.allowClear&&this.getPlaceholder()!==b&&this.container.addClass("select2-allowclear")},val:function(){var a,c=!1,d=null,e=this,f=this.data();if(0===arguments.length)return this.opts.element.val();if(a=arguments[0],arguments.length>1&&(c=arguments[1]),this.select)this.select.val(a).find("option").filter(function(){return this.selected}).each2(function(a,b){return d=e.optionToData(b),!1}),this.updateSelection(d),this.setPlaceholder(),c&&this.triggerChange({added:d,removed:f});else{if(!a&&0!==a)return this.clear(c),void 0;if(this.opts.initSelection===b)throw new Error("cannot call val() if initSelection() is not defined");this.opts.element.val(a),this.opts.initSelection(this.opts.element,function(a){e.opts.element.val(a?e.id(a):""),e.updateSelection(a),e.setPlaceholder(),c&&e.triggerChange({added:a,removed:f})})}},clearSearch:function(){this.search.val(""),this.focusser.val("")},data:function(a){var c,d=!1;return 0===arguments.length?(c=this.selection.data("select2-data"),c==b&&(c=null),c):(arguments.length>1&&(d=arguments[1]),a?(c=this.data(),this.opts.element.val(a?this.id(a):""),this.updateSelection(a),d&&this.triggerChange({added:a,removed:c})):this.clear(d),void 0)}}),f=O(d,{createContainer:function(){var b=a(document.createElement("div")).attr({"class":"select2-container select2-container-multi"}).html(["
    ","
  • "," "," ","
  • ","
","
","
    ","
","
"].join(""));return b},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=[];a.find("option").filter(function(){return this.selected&&!this.disabled}).each2(function(a,b){d.push(c.optionToData(b))}),b(d)}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=s(c.val(),b.separator),f=[];b.query({matcher:function(c,d,g){var h=a.grep(e,function(a){return r(a,b.id(g))}).length;return h&&f.push(g),h},callback:a.isFunction(d)?function(){for(var a=[],c=0;c0||(this.selectChoice(null),this.clearPlaceholder(),this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.open(),this.focusSearch(),b.preventDefault()))})),this.container.on("focus",b,this.bind(function(){this.isInterfaceEnabled()&&(this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"),this.clearPlaceholder())})),this.initContainerWidth(),this.opts.element.addClass("select2-offscreen"),this.clearSearch()},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.search.prop("disabled",!this.isInterfaceEnabled())},initSelection:function(){if(""===this.opts.element.val()&&""===this.opts.element.text()&&(this.updateSelection([]),this.close(),this.clearSearch()),this.select||""!==this.opts.element.val()){var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.clearSearch())})}},clearSearch:function(){var a=this.getPlaceholder(),c=this.getMaxSearchWidth();a!==b&&0===this.getVal().length&&this.search.hasClass("select2-focused")===!1?(this.search.val(a).addClass("select2-default"),this.search.width(c>0?c:this.container.css("width"))):this.search.val("").width(10)},clearPlaceholder:function(){this.search.hasClass("select2-default")&&this.search.val("").removeClass("select2-default")},opening:function(){this.clearPlaceholder(),this.resizeSearch(),this.parent.opening.apply(this,arguments),this.focusSearch(),""===this.search.val()&&this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.search.select()),this.updateResults(!0),this.opts.shouldFocusInput(this)&&this.search.focus(),this.opts.element.trigger(a.Event("select2-open"))},close:function(){this.opened()&&this.parent.close.apply(this,arguments)},focus:function(){this.close(),this.search.focus()},isFocused:function(){return this.search.hasClass("select2-focused")},updateSelection:function(b){var c=[],d=[],e=this;a(b).each(function(){p(e.id(this),c)<0&&(c.push(e.id(this)),d.push(this))}),b=d,this.selection.find(".select2-search-choice").remove(),a(b).each(function(){e.addSelectedChoice(this)}),e.postprocessResults()},tokenize:function(){var a=this.search.val();a=this.opts.tokenizer.call(this,a,this.data(),this.bind(this.onSelect),this.opts),null!=a&&a!=b&&(this.search.val(a),a.length>0&&this.open())},onSelect:function(a,c){this.triggerSelect(a)&&""!==a.text&&(this.addSelectedChoice(a),this.opts.element.trigger({type:"selected",val:this.id(a),choice:a}),this.nextSearchTerm=this.opts.nextSearchTerm(a,this.search.val()),this.clearSearch(),this.updateResults(),(this.select||!this.opts.closeOnSelect)&&this.postprocessResults(a,!1,this.opts.closeOnSelect===!0),this.opts.closeOnSelect?(this.close(),this.search.width(10)):this.countSelectableResults()>0?(this.search.width(10),this.resizeSearch(),this.getMaximumSelectionSize()>0&&this.val().length>=this.getMaximumSelectionSize()?this.updateResults(!0):this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.updateResults(),this.search.select()),this.positionDropdown()):(this.close(),this.search.width(10)),this.triggerChange({added:a}),c&&c.noFocus||this.focusSearch())},cancel:function(){this.close(),this.focusSearch()},addSelectedChoice:function(c){var j,k,d=!c.locked,e=a("
  • "),f=a("
  • "),g=d?e:f,h=this.id(c),i=this.getVal();j=this.opts.formatSelection(c,g.find("div"),this.opts.escapeMarkup),j!=b&&g.find("div").replaceWith("
    "+j+"
    "),k=this.opts.formatSelectionCssClass(c,g.find("div")),k!=b&&g.addClass(k),d&&g.find(".select2-search-choice-close").on("mousedown",A).on("click dblclick",this.bind(function(b){this.isInterfaceEnabled()&&(this.unselect(a(b.target)),this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"),A(b),this.close(),this.focusSearch())})).on("focus",this.bind(function(){this.isInterfaceEnabled()&&(this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"))})),g.data("select2-data",c),g.insertBefore(this.searchContainer),i.push(h),this.setVal(i)},unselect:function(b){var d,e,c=this.getVal();if(b=b.closest(".select2-search-choice"),0===b.length)throw"Invalid argument: "+b+". Must be .select2-search-choice";if(d=b.data("select2-data")){var f=a.Event("select2-removing");if(f.val=this.id(d),f.choice=d,this.opts.element.trigger(f),f.isDefaultPrevented())return!1;for(;(e=p(this.id(d),c))>=0;)c.splice(e,1),this.setVal(c),this.select&&this.postprocessResults();return b.remove(),this.opts.element.trigger({type:"select2-removed",val:this.id(d),choice:d}),this.triggerChange({removed:d}),!0}},postprocessResults:function(a,b,c){var d=this.getVal(),e=this.results.find(".select2-result"),f=this.results.find(".select2-result-with-children"),g=this;e.each2(function(a,b){var c=g.id(b.data("select2-data"));p(c,d)>=0&&(b.addClass("select2-selected"),b.find(".select2-result-selectable").addClass("select2-selected"))}),f.each2(function(a,b){b.is(".select2-result-selectable")||0!==b.find(".select2-result-selectable:not(.select2-selected)").length||b.addClass("select2-selected")}),-1==this.highlight()&&c!==!1&&g.highlight(0),!this.opts.createSearchChoice&&!e.filter(".select2-result:not(.select2-selected)").length>0&&(!a||a&&!a.more&&0===this.results.find(".select2-no-results").length)&&J(g.opts.formatNoMatches,"formatNoMatches")&&this.results.append("
  • "+K(g.opts.formatNoMatches,g.opts.element,g.search.val())+"
  • ")},getMaxSearchWidth:function(){return this.selection.width()-t(this.search)},resizeSearch:function(){var a,b,c,d,e,f=t(this.search);a=C(this.search)+10,b=this.search.offset().left,c=this.selection.width(),d=this.selection.offset().left,e=c-(b-d)-f,a>e&&(e=c-f),40>e&&(e=c-f),0>=e&&(e=a),this.search.width(Math.floor(e))},getVal:function(){var a;return this.select?(a=this.select.val(),null===a?[]:a):(a=this.opts.element.val(),s(a,this.opts.separator))},setVal:function(b){var c;this.select?this.select.val(b):(c=[],a(b).each(function(){p(this,c)<0&&c.push(this)}),this.opts.element.val(0===c.length?"":c.join(this.opts.separator)))},buildChangeDetails:function(a,b){for(var b=b.slice(0),a=a.slice(0),c=0;c0&&c--,a.splice(d,1),d--);return{added:b,removed:a}},val:function(c,d){var e,f=this;if(0===arguments.length)return this.getVal();if(e=this.data(),e.length||(e=[]),!c&&0!==c)return this.opts.element.val(""),this.updateSelection([]),this.clearSearch(),d&&this.triggerChange({added:this.data(),removed:e}),void 0;if(this.setVal(c),this.select)this.opts.initSelection(this.select,this.bind(this.updateSelection)),d&&this.triggerChange(this.buildChangeDetails(e,this.data()));else{if(this.opts.initSelection===b)throw new Error("val() cannot be called if initSelection() is not defined");this.opts.initSelection(this.opts.element,function(b){var c=a.map(b,f.id);f.setVal(c),f.updateSelection(b),f.clearSearch(),d&&f.triggerChange(f.buildChangeDetails(e,f.data()))})}this.clearSearch()},onSortStart:function(){if(this.select)throw new Error("Sorting of elements is not supported when attached to instead.");this.search.width(0),this.searchContainer.hide()},onSortEnd:function(){var b=[],c=this;this.searchContainer.show(),this.searchContainer.appendTo(this.searchContainer.parent()),this.resizeSearch(),this.selection.find(".select2-search-choice").each(function(){b.push(c.opts.id(a(this).data("select2-data")))}),this.setVal(b),this.triggerChange()},data:function(b,c){var e,f,d=this;return 0===arguments.length?this.selection.children(".select2-search-choice").map(function(){return a(this).data("select2-data")}).get():(f=this.data(),b||(b=[]),e=a.map(b,function(a){return d.opts.id(a)}),this.setVal(e),this.updateSelection(b),this.clearSearch(),c&&this.triggerChange(this.buildChangeDetails(f,this.data())),void 0)}}),a.fn.select2=function(){var d,e,f,g,h,c=Array.prototype.slice.call(arguments,0),i=["val","destroy","opened","open","close","focus","isFocused","container","dropdown","onSortStart","onSortEnd","enable","disable","readonly","positionDropdown","data","search"],j=["opened","isFocused","container","dropdown"],k=["val","data"],l={search:"externalSearch"};return this.each(function(){if(0===c.length||"object"==typeof c[0])d=0===c.length?{}:a.extend({},c[0]),d.element=a(this),"select"===d.element.get(0).tagName.toLowerCase()?h=d.element.prop("multiple"):(h=d.multiple||!1,"tags"in d&&(d.multiple=h=!0)),e=h?new window.Select2["class"].multi:new window.Select2["class"].single,e.init(d);else{if("string"!=typeof c[0])throw"Invalid arguments to select2 plugin: "+c;if(p(c[0],i)<0)throw"Unknown method: "+c[0];if(g=b,e=a(this).data("select2"),e===b)return;if(f=c[0],"container"===f?g=e.container:"dropdown"===f?g=e.dropdown:(l[f]&&(f=l[f]),g=e[f].apply(e,c.slice(1))),p(c[0],j)>=0||p(c[0],k)>=0&&1==c.length)return!1}}),g===b?this:g},a.fn.select2.defaults={width:"copy",loadMorePadding:0,closeOnSelect:!0,openOnEnter:!0,containerCss:{},dropdownCss:{},containerCssClass:"",dropdownCssClass:"",formatResult:function(a,b,c,d){var e=[];return E(a.text,c.term,e,d),e.join("")},formatSelection:function(a,c,d){return a?d(a.text):b},sortResults:function(a){return a},formatResultCssClass:function(a){return a.css},formatSelectionCssClass:function(){return b},minimumResultsForSearch:0,minimumInputLength:0,maximumInputLength:null,maximumSelectionSize:0,id:function(a){return a==b?null:a.id},matcher:function(a,b){return o(""+b).toUpperCase().indexOf(o(""+a).toUpperCase())>=0},separator:",",tokenSeparators:[],tokenizer:M,escapeMarkup:F,blurOnChange:!1,selectOnBlur:!1,adaptContainerCssClass:function(a){return a},adaptDropdownCssClass:function(){return null},nextSearchTerm:function(){return b},searchInputPlaceholder:"",createSearchChoicePosition:"top",shouldFocusInput:function(a){var b="ontouchstart"in window||navigator.msMaxTouchPoints>0;return b?a.opts.minimumResultsForSearch<0?!1:!0:!0}},a.fn.select2.locales=[],a.fn.select2.locales.en={formatMatches:function(a){return 1===a?"One result is available, press enter to select it.":a+" results are available, use up and down arrow keys to navigate." +},formatNoMatches:function(){return"No matches found"},formatAjaxError:function(){return"Loading failed"},formatInputTooShort:function(a,b){var c=b-a.length;return"Please enter "+c+" or more character"+(1==c?"":"s")},formatInputTooLong:function(a,b){var c=a.length-b;return"Please delete "+c+" character"+(1==c?"":"s")},formatSelectionTooBig:function(a){return"You can only select "+a+" item"+(1==a?"":"s")},formatLoadMore:function(){return"Loading more results\u2026"},formatSearching:function(){return"Searching\u2026"}},a.extend(a.fn.select2.defaults,a.fn.select2.locales.en),a.fn.select2.ajaxDefaults={transport:a.ajax,params:{type:"GET",cache:!1,dataType:"json"}},window.Select2={query:{ajax:G,local:H,tags:I},util:{debounce:w,markMatch:E,escapeMarkup:F,stripDiacritics:o},"class":{"abstract":d,single:e,multi:f}}}}(jQuery); \ No newline at end of file diff --git a/frontend/client/res/templates/fields/multi-enum/edit.tpl b/frontend/client/res/templates/fields/multi-enum/edit.tpl new file mode 100644 index 0000000000..956027fa5e --- /dev/null +++ b/frontend/client/res/templates/fields/multi-enum/edit.tpl @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/client/src/views/fields/array.js b/frontend/client/src/views/fields/array.js index 55df3b27f3..3284bd1f8c 100644 --- a/frontend/client/src/views/fields/array.js +++ b/frontend/client/src/views/fields/array.js @@ -110,36 +110,47 @@ Espo.define('Views.Fields.Array', 'Views.Fields.Enum', function (Dep) { }, afterRender: function () { - this.$list = this.$el.find('.list-group'); - var $select = this.$select = this.$el.find('.select'); + if (this.mode == 'edit' || this.mode == 'search') { + this.$list = this.$el.find('.list-group'); + var $select = this.$select = this.$el.find('.select'); - if (!this.params.options) { - $select.on('keypress', function (e) { - if (e.keyCode == 13) { - var value = $select.val(); - this.addValue(value); - $select.val(''); + if (!this.params.options) { + $select.on('keypress', function (e) { + if (e.keyCode == 13) { + var value = $select.val(); + this.addValue(value); + $select.val(''); - } - }.bind(this)); - } + } + }.bind(this)); + } - this.$list.sortable({ - stop: function () { - this.trigger('change'); - }.bind(this) - }); + this.$list.sortable({ + stop: function () { + this.trigger('change'); + }.bind(this) + }); + } }, getValueForDisplay: function () { - return this.selected.join(', '); + return this.selected.map(function (item) { + if (this.translatedOptions != null) { + if (item in this.translatedOptions) { + return this.translatedOptions[item]; + } + } + return item; + }, this).join(', '); }, - addValue: function (value) { - for (var item in this.translatedOptions) { - if (this.translatedOptions[item] == value) { - value = item; - break; + addValue: function (value) { + if (this.translatedOptions != null) { + for (var item in this.translatedOptions) { + if (this.translatedOptions[item] == value) { + value = item; + break; + } } } diff --git a/frontend/client/src/views/fields/multi-enum.js b/frontend/client/src/views/fields/multi-enum.js new file mode 100644 index 0000000000..dd014b6988 --- /dev/null +++ b/frontend/client/src/views/fields/multi-enum.js @@ -0,0 +1,115 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko + * Website: http://www.espocrm.com + * + * EspoCRM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EspoCRM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EspoCRM. If not, see http://www.gnu.org/licenses/. + ************************************************************************/ + +Espo.define('Views.Fields.MultiEnum', ['Views.Fields.Array', 'lib!Select2'], function (Dep, Select2) { + + return Dep.extend({ + + type: 'multiEnum', + + listTemplate: 'fields.array.detail', + + detailTemplate: 'fields.array.detail', + + editTemplate: 'fields.multi-enum.edit', + + events: { + }, + + data: function () { + return _.extend({ + optionList: this.params.options || [] + }, Dep.prototype.data.call(this)); + }, + + getTranslatedOptions: function () { + return (this.params.options || []).map(function (item) { + if (this.translatedOptions != null) { + if (item in this.translatedOptions) { + return this.translatedOptions[item]; + } + } + return item; + }); + }, + + + setup: function () { + Dep.prototype.setup.call(this); + }, + + afterRender: function () { + if (this.mode == 'edit' || this.mode == 'search') { + var $element = this.$element = this.$el.find('.main-element'); + this.$element.val(this.selected.join(',')); + + this.$element.select2({ + data: (this.params.options || []).map(function (item) { + var text = item; + if (this.translatedOptions) { + if (item in this.translatedOptions) { + text = this.translatedOptions[item]; + } + } + return { + id: item, + text: text + }; + }, this), + multiple: true, + formatSearching: '', + formatNoMatches: '', + matcher: function (term, text) { + return text.toUpperCase().indexOf(term.toUpperCase()) == 0; + } + }); + + this.$element.on('change', function () { + this.trigger('change'); + }.bind(this)); + + + this.$element.select2('container').find('ul.select2-choices').sortable({ + containment: 'parent', + start: function () { + $element.select2('onSortStart'); + }, + update: function () { + $element.select2('onSortEnd'); + } + }); + } + }, + + fetch: function () { + var list = this.$element.val().split(','); + if (list.length == 1 && list[0] == '') { + list = []; + } + var data = {}; + data[this.name] = list; + return data; + }, + + }); +}); + + From b3ccabcde0214dd2c8c849e26478364d3d69cc5d Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Mon, 13 Oct 2014 17:43:11 +0300 Subject: [PATCH 007/139] fix css --- frontend/client/css/select2-bootstrap.css | 8 ++++---- frontend/client/css/select2.css | 14 ++++++-------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/frontend/client/css/select2-bootstrap.css b/frontend/client/css/select2-bootstrap.css index ecaa92c687..d71680b1af 100644 --- a/frontend/client/css/select2-bootstrap.css +++ b/frontend/client/css/select2-bootstrap.css @@ -84,7 +84,7 @@ div.select2-container { .input-group-sm .select2-container .select2-choice { height: 30px; line-height: 1.5; - border-radius: 3px; + border-radius: 0px; } .select2-container.input-lg .select2-choice, @@ -335,8 +335,8 @@ div.select2-container { .select2-dropdown-open.select2-drop-above [class^="select2-choice"] { border-top-right-radius: 0 !important; border-top-left-radius: 0 !important; - border-bottom-right-radius: 4px !important; - border-bottom-left-radius: 4px !important; + border-bottom-right-radius: 0px !important; + border-bottom-left-radius: 0px !important; } .input-group.select2-bootstrap-prepend .select2-dropdown-open.select2-drop-above [class^="select2-choice"] { border-bottom-left-radius: 0 !important; @@ -356,7 +356,7 @@ div.select2-container { border-bottom-left-radius: 3px !important; } .input-group.input-group-lg.select2-bootstrap-append .select2-dropdown-open.select2-drop-above [class^="select2-choice"] { - border-bottom-left-radius: 6px !important; + border-bottom-left-radius: 0px !important; } /** diff --git a/frontend/client/css/select2.css b/frontend/client/css/select2.css index cb4e89627e..770694c9f6 100644 --- a/frontend/client/css/select2.css +++ b/frontend/client/css/select2.css @@ -38,7 +38,7 @@ Version: 3.5.1 Timestamp: Tue Jul 22 18:58:56 EDT 2014 color: #444; text-decoration: none; - border-radius: 4px; + border-radius: 0px; background-clip: padding-box; @@ -63,7 +63,7 @@ html[dir="rtl"] .select2-container .select2-choice { .select2-container.select2-drop-above .select2-choice { border-bottom-color: #d1d5d6; - border-radius: 0 0 4px 4px; + border-radius: 0 0 0px 0px; background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.9, #fff)); background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 90%); @@ -149,10 +149,9 @@ html[dir="rtl"] .select2-container .select2-choice > .select2-chosen { border: 1px solid #d1d5d6; border-top: 0; - border-radius: 0 0 4px 4px; + border-radius: 0 0 0px 0px; + - -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); - box-shadow: 0 4px 5px rgba(0, 0, 0, .15); } .select2-drop.select2-drop-above { @@ -160,10 +159,9 @@ html[dir="rtl"] .select2-container .select2-choice > .select2-chosen { border-top: 1px solid #d1d5d6; border-bottom: 0; - border-radius: 4px 4px 0 0; + border-radius: 0px 0px 0 0; + - -webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); - box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); } .select2-drop-active { From d1fd916be0f8ade275cbf6dbb81e1ed03107c837 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Tue, 14 Oct 2014 10:50:59 +0300 Subject: [PATCH 008/139] fix select2 css --- frontend/client/css/select2-bootstrap.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/client/css/select2-bootstrap.css b/frontend/client/css/select2-bootstrap.css index d71680b1af..199a32c63c 100644 --- a/frontend/client/css/select2-bootstrap.css +++ b/frontend/client/css/select2-bootstrap.css @@ -386,7 +386,7 @@ div.select2-container { */ .select2-container-multi .select2-choices .select2-search-choice { color: #555555; - background: white; + background: #eee; border-color: #cccccc; filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); -webkit-box-shadow: none; From 4f7946fe255993a477b938ce3c991146445d7ae9 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Tue, 14 Oct 2014 10:57:22 +0300 Subject: [PATCH 009/139] notRemovable option for Search.Filter --- frontend/client/res/templates/search/filter.tpl | 2 +- frontend/client/src/views/search/filter.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/client/res/templates/search/filter.tpl b/frontend/client/res/templates/search/filter.tpl index a254b98c81..7bda850a0a 100644 --- a/frontend/client/res/templates/search/filter.tpl +++ b/frontend/client/res/templates/search/filter.tpl @@ -1,6 +1,6 @@
    - + {{#unless notRemovable}}{{/unless}}
    {{{field}}}
    diff --git a/frontend/client/src/views/search/filter.js b/frontend/client/src/views/search/filter.js index b05c20a465..98a3c766f5 100644 --- a/frontend/client/src/views/search/filter.js +++ b/frontend/client/src/views/search/filter.js @@ -28,7 +28,8 @@ Espo.define('Views.Search.Filter', 'View', function (Dep) { data: function () { return { name: this.name, - scope: this.model.name + scope: this.model.name, + notRemovable: this.options.notRemovable }; }, From 3e0eaf1fa531f0aa0f9d8a5b99801933dc043bb3 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Tue, 14 Oct 2014 11:18:09 +0300 Subject: [PATCH 010/139] avoid 403 for list dashlets --- .../Espo/Resources/i18n/en_US/Global.json | 1 + .../modules/crm/src/views/dashlets/cases.js | 17 ---------------- .../modules/crm/src/views/dashlets/leads.js | 16 --------------- .../crm/src/views/dashlets/meetings.js | 16 --------------- .../crm/src/views/dashlets/opportunities.js | 16 --------------- .../modules/crm/src/views/dashlets/tasks.js | 20 ------------------- .../views/dashlets/abstract/record-list.js | 15 ++++++++------ 7 files changed, 10 insertions(+), 91 deletions(-) diff --git a/application/Espo/Resources/i18n/en_US/Global.json b/application/Espo/Resources/i18n/en_US/Global.json index 480c6318c7..9e139a02da 100644 --- a/application/Espo/Resources/i18n/en_US/Global.json +++ b/application/Espo/Resources/i18n/en_US/Global.json @@ -98,6 +98,7 @@ "Mass Update": "Mass Update", "Export": "Export", "No Data": "No Data", + "No Access": "No Access", "All": "All", "Active": "Active", "Inactive": "Inactive", diff --git a/frontend/client/modules/crm/src/views/dashlets/cases.js b/frontend/client/modules/crm/src/views/dashlets/cases.js index 21cf241833..1a895a3ee0 100644 --- a/frontend/client/modules/crm/src/views/dashlets/cases.js +++ b/frontend/client/modules/crm/src/views/dashlets/cases.js @@ -32,23 +32,6 @@ Espo.define('Crm:Views.Dashlets.Cases', 'Views.Dashlets.Abstract.RecordList', fu sortBy: 'number', asc: false, displayRecords: 5, - columnLayout: [ - { - name: 'name', - link: true, - sortable: false, - width: 40, - }, - { - name: 'type', - }, - { - name: 'status', - }, - { - name: 'priority', - } - ], expandedLayout: { rows: [ [ diff --git a/frontend/client/modules/crm/src/views/dashlets/leads.js b/frontend/client/modules/crm/src/views/dashlets/leads.js index e6f139e680..ac68692be2 100644 --- a/frontend/client/modules/crm/src/views/dashlets/leads.js +++ b/frontend/client/modules/crm/src/views/dashlets/leads.js @@ -31,22 +31,6 @@ Espo.define('Crm:Views.Dashlets.Leads', 'Views.Dashlets.Abstract.RecordList', fu sortBy: 'createdAt', asc: false, displayRecords: 5, - columnLayout: [ - { - name: 'name', - link: true, - sortable: false, - width: 40, - }, - { - name: 'email', - sortable: false, - }, - { - name: 'phone', - sortable: false, - } - ], expandedLayout: { rows: [ [ diff --git a/frontend/client/modules/crm/src/views/dashlets/meetings.js b/frontend/client/modules/crm/src/views/dashlets/meetings.js index 811433fe2a..e91ea4128b 100644 --- a/frontend/client/modules/crm/src/views/dashlets/meetings.js +++ b/frontend/client/modules/crm/src/views/dashlets/meetings.js @@ -31,22 +31,6 @@ Espo.define('Crm:Views.Dashlets.Meetings', 'Views.Dashlets.Abstract.RecordList', sortBy: 'createdAt', asc: false, displayRecords: 5, - columnLayout: [ - { - name: 'name', - link: true, - sortable: false, - width: 40, - }, - { - name: 'status', - sortable: false, - }, - { - name: 'dateStart', - sortable: false, - } - ], expandedLayout: { rows: [ [ diff --git a/frontend/client/modules/crm/src/views/dashlets/opportunities.js b/frontend/client/modules/crm/src/views/dashlets/opportunities.js index b1ff1099c4..bd57dda1d3 100644 --- a/frontend/client/modules/crm/src/views/dashlets/opportunities.js +++ b/frontend/client/modules/crm/src/views/dashlets/opportunities.js @@ -31,22 +31,6 @@ Espo.define('Crm:Views.Dashlets.Opportunities', 'Views.Dashlets.Abstract.RecordL sortBy: 'createdAt', asc: false, displayRecords: 5, - columnLayout: [ - { - name: 'name', - link: true, - sortable: false, - width: 40, - }, - { - name: 'stage', - sortable: false, - }, - { - name: 'amount', - sortable: false, - } - ], expandedLayout: { rows: [ [ diff --git a/frontend/client/modules/crm/src/views/dashlets/tasks.js b/frontend/client/modules/crm/src/views/dashlets/tasks.js index abc03443af..d8495b4bea 100644 --- a/frontend/client/modules/crm/src/views/dashlets/tasks.js +++ b/frontend/client/modules/crm/src/views/dashlets/tasks.js @@ -31,26 +31,6 @@ Espo.define('Crm:Views.Dashlets.Tasks', 'Views.Dashlets.Abstract.RecordList', fu sortBy: 'createdAt', asc: false, displayRecords: 5, - columnLayout: [ - { - name: 'name', - link: true, - sortable: false, - width: 40, - }, - { - name: 'status', - sortable: false, - }, - { - name: 'priority', - sortable: false, - }, - { - name: 'dateEnd', - sortable: false, - } - ], expandedLayout: { rows: [ [ diff --git a/frontend/client/src/views/dashlets/abstract/record-list.js b/frontend/client/src/views/dashlets/abstract/record-list.js index 67f4993c17..48a6636a4b 100644 --- a/frontend/client/src/views/dashlets/abstract/record-list.js +++ b/frontend/client/src/views/dashlets/abstract/record-list.js @@ -46,16 +46,19 @@ Espo.define('Views.Dashlets.Abstract.RecordList', 'Views.Dashlets.Abstract.Base' }), afterRender: function () { - this.getCollectionFactory().create(this.scope, function (collection) { - + this.getCollectionFactory().create(this.scope, function (collection) { var searchManager = new Espo.SearchManager(collection, 'list', null, this.getDateTime(), this.getOption('searchData')); + + if (!this.getAcl().check(this.scope, 'read')) { + this.$el.find('.list-container').html(this.translate('No Access')); + return; + } this.collection = collection; collection.sortBy = this.getOption('sortBy') || this.collection.sortBy; collection.asc = this.getOption('asc') || this.collection.asc; collection.maxSize = this.getOption('displayRecords'); - collection.where = searchManager.getWhere(); - + collection.where = searchManager.getWhere(); var viewName = (this.layoutType == 'expanded') ? this.listViewExpanded : this.listViewColumn; @@ -72,11 +75,11 @@ Espo.define('Views.Dashlets.Abstract.RecordList', 'Views.Dashlets.Abstract.Base' }, function (view) { view.render(); }); - }.bind(this)); + }, this); collection.fetch(); - }.bind(this)); + }, this); }, actionRefresh: function () { From 6f22452cd9ad69590faa66b8b7052e7adfe1f7e5 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Tue, 14 Oct 2014 12:04:31 +0300 Subject: [PATCH 011/139] change default dashboard layout --- .../Espo/Resources/metadata/app/defaultDashboardLayout.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/application/Espo/Resources/metadata/app/defaultDashboardLayout.json b/application/Espo/Resources/metadata/app/defaultDashboardLayout.json index cb7e1d91fe..9f52712790 100644 --- a/application/Espo/Resources/metadata/app/defaultDashboardLayout.json +++ b/application/Espo/Resources/metadata/app/defaultDashboardLayout.json @@ -13,6 +13,10 @@ { "name": "Tasks", "id": "d3" + }, + { + "name": "Meetings", + "id": "d2" } ] ] From b12cf2e21be8b082b61463a62fd83ae49966d59f Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Tue, 14 Oct 2014 15:15:43 +0300 Subject: [PATCH 012/139] probabilityMap move to metadata --- .../metadata/entityDefs/Opportunity.json | 14 +++++++++++++- .../crm/src/views/opportunity/fields/stage.js | 16 +++------------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Opportunity.json b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Opportunity.json index ec966bc7fd..c3fee5a021 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Opportunity.json +++ b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/Opportunity.json @@ -151,5 +151,17 @@ "collection": { "sortBy": "createdAt", "asc": false - } + }, + "probabilityMap": { + "Prospecting": 10, + "Qualification": 10, + "Needs Analysis": 20, + "Value Proposition": 50, + "Id. Decision Makers": 60, + "Perception Analysis": 70, + "Proposal/Price Quote": 75, + "Negotiation/Review": 90, + "Closed Won": 100, + "Closed Lost": 0 + } } diff --git a/frontend/client/modules/crm/src/views/opportunity/fields/stage.js b/frontend/client/modules/crm/src/views/opportunity/fields/stage.js index 9cc509e2fb..4fdc109df3 100644 --- a/frontend/client/modules/crm/src/views/opportunity/fields/stage.js +++ b/frontend/client/modules/crm/src/views/opportunity/fields/stage.js @@ -40,21 +40,11 @@ Espo.define('Crm:Views.Opportunity.Fields.Stage', 'Views.Fields.Enum', function }, Dep.prototype.data.call(this)); }, - probabilityMap: { - 'Prospecting': 10, - 'Qualification': 10, - 'Needs Analysis': 20, - 'Value Proposition': 50, - 'Id. Decision Makers': 60, - 'Perception Analysis': 70, - 'Proposal/Price Quote': 75, - 'Negotiation/Review': 90, - 'Closed Won': 100, - 'Closed Lost': 0, - }, - setup: function () { Dep.prototype.setup.call(this); + + this.probabilityMap = this.getMetadata().get('entityDefs.Opportunity.probabilityMap') || {}; + if (this.mode != 'list') { if (!this.model.has('probability') && this.model.has('stage')) { this.model.set('probability', this.probabilityMap[this.model.get('stage')]); From 8fafe2c47fb34c643a7b500edcaedf265a222b5b Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Tue, 14 Oct 2014 15:23:39 +0300 Subject: [PATCH 013/139] add User variable to Email Template --- application/Espo/Services/EmailTemplate.php | 6 +++++- .../client/src/views/email-template/fields/insert-field.js | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/application/Espo/Services/EmailTemplate.php b/application/Espo/Services/EmailTemplate.php index 1acfe1a153..d2a6ddc9e6 100644 --- a/application/Espo/Services/EmailTemplate.php +++ b/application/Espo/Services/EmailTemplate.php @@ -53,10 +53,14 @@ class EmailTemplate extends Record throw new NotFound(); } + + $entityList = array(); if (!empty($params['entityHash']) && is_array($params['entityHash'])) { $entityList = $params['entityHash']; - } + } + + $entityList['User'] = $this->getUser(); if (!empty($params['emailAddress'])) { $emailAddress = $this->getEntityManager()->getRepository('EmailAddress')->where(array( diff --git a/frontend/client/src/views/email-template/fields/insert-field.js b/frontend/client/src/views/email-template/fields/insert-field.js index 0d9291f616..7b93f75ca9 100644 --- a/frontend/client/src/views/email-template/fields/insert-field.js +++ b/frontend/client/src/views/email-template/fields/insert-field.js @@ -47,7 +47,8 @@ Espo.define('Views.EmailTemplate.Fields.InsertField', 'Views.Fields.Base', funct var defs = this.getMetadata().get('scopes'); entityList = Object.keys(defs).filter(function (scope) { return defs[scope].entity && defs[scope].tab; - }); + }); + entityList.push('User'); var entityFields = {}; entityList.forEach(function (scope) { From 3cd9d49b4ce8bd9f321372271238fcdb551f6c90 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Tue, 14 Oct 2014 17:50:33 +0300 Subject: [PATCH 014/139] crypt passwords --- application/Espo/Controllers/Preferences.php | 9 +++ application/Espo/Core/Container.php | 7 +++ application/Espo/Core/Utils/Crypt.php | 62 +++++++++++++++++++ .../Modules/Crm/Services/InboundEmail.php | 20 +++++- application/Espo/Services/Email.php | 10 +++ application/Espo/Services/EmailAccount.php | 18 +++++- application/Espo/Services/Record.php | 13 +++- 7 files changed, 132 insertions(+), 7 deletions(-) create mode 100644 application/Espo/Core/Utils/Crypt.php diff --git a/application/Espo/Controllers/Preferences.php b/application/Espo/Controllers/Preferences.php index eb9a3ffedc..4a95b0daba 100644 --- a/application/Espo/Controllers/Preferences.php +++ b/application/Espo/Controllers/Preferences.php @@ -38,6 +38,11 @@ class Preferences extends \Espo\Core\Controllers\Base return $this->getContainer()->get('entityManager'); } + protected function getCrypt() + { + return $this->getContainer()->get('crypt'); + } + protected function handleUserAccess($userId) { if (!$this->getUser()->isAdmin()) { @@ -57,6 +62,10 @@ class Preferences extends \Espo\Core\Controllers\Base $userId = $params['id']; $this->handleUserAccess($userId); + if (array_key_exists('smtpPassword', $data)) { + $data['smtpPassword'] = $this->getCrypt()->encrypt($data['smtpPassword']); + } + $user = $this->getEntityManager()->getEntity('User', $userId); $entity = $this->getEntityManager()->getEntity('Preferences', $userId); diff --git a/application/Espo/Core/Container.php b/application/Espo/Core/Container.php index 0fd76577bf..022ff4259b 100644 --- a/application/Espo/Core/Container.php +++ b/application/Espo/Core/Container.php @@ -199,6 +199,13 @@ class Container $this->get('preferences') ); } + + private function loadCrypt() + { + return new \Espo\Core\Utils\Crypt( + $this->get('config') + ); + } private function loadScheduledJob() { diff --git a/application/Espo/Core/Utils/Crypt.php b/application/Espo/Core/Utils/Crypt.php new file mode 100644 index 0000000000..f6e070666b --- /dev/null +++ b/application/Espo/Core/Utils/Crypt.php @@ -0,0 +1,62 @@ +config = $config; + $this->cryptKey = $config->get('cryptKey', ''); + } + + protected function getKey() + { + if (empty($this->key)) { + $this->key = hash('sha256', $this->cryptKey, true); + } + return $this->key; + } + + public function encrypt($string) + { + return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->getKey(), $string, MCRYPT_MODE_CBC)); + } + + public function decrypt($encryptedString) + { + return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->getKey(), base64_decode($encryptedString), MCRYPT_MODE_CBC)); + } + + public function generateKey() + { + return md5(uniqid()); + } +} + diff --git a/application/Espo/Modules/Crm/Services/InboundEmail.php b/application/Espo/Modules/Crm/Services/InboundEmail.php index ba0decf886..725f0f3cae 100644 --- a/application/Espo/Modules/Crm/Services/InboundEmail.php +++ b/application/Espo/Modules/Crm/Services/InboundEmail.php @@ -62,6 +62,7 @@ class InboundEmail extends \Espo\Services\Record { $this->dependencies[] = 'fileManager'; $this->dependencies[] = 'mailSender'; + $this->dependencies[] = 'crypt'; } protected function getFileManager() @@ -72,6 +73,19 @@ class InboundEmail extends \Espo\Services\Record protected function getMailSender() { return $this->injections['mailSender']; + } + + protected function getCrypt() + { + return $this->injections['crypt']; + } + + protected function handleInput(&$data) + { + parent::handleInput($data); + if (array_key_exists('password', $data)) { + $data['password'] = $this->getCrypt()->encrypt($data['password']); + } } public function getFolders($params) @@ -81,9 +95,9 @@ class InboundEmail extends \Espo\Services\Record if (!empty($params['id'])) { $entity = $this->getEntityManager()->getEntity('InboundEmail', $params['id']); if ($entity) { - $password = $entity->get('password'); + $password = $this->getCrypt()->decrypt($entity->get('password')); } - } + } $imapParams = array( 'host' => $params['host'], @@ -138,7 +152,7 @@ class InboundEmail extends \Espo\Services\Record 'host' => $inboundEmail->get('host'), 'port' => $inboundEmail->get('port'), 'user' => $inboundEmail->get('username'), - 'password' => $inboundEmail->get('password'), + 'password' => $this->getCrypt()->decrypt($inboundEmail->get('password')), ); if ($inboundEmail->get('ssl')) { diff --git a/application/Espo/Services/Email.php b/application/Espo/Services/Email.php index 0b8895fa0d..2416c50486 100644 --- a/application/Espo/Services/Email.php +++ b/application/Espo/Services/Email.php @@ -34,6 +34,7 @@ class Email extends Record $this->dependencies[] = 'mailSender'; $this->dependencies[] = 'preferences'; $this->dependencies[] = 'fileManager'; + $this->dependencies[] = 'crypt'; } protected function getFileManager() @@ -49,6 +50,11 @@ class Email extends Record protected function getPreferences() { return $this->injections['preferences']; + } + + protected function getCrypt() + { + return $this->injections['crypt']; } public function createEntity($data) @@ -60,6 +66,10 @@ class Email extends Record if (strtolower($this->getUser()->get('emailAddress')) == strtolower($entity->get('from'))) { $smtpParams = $this->getPreferences()->getSmtpParams(); + if (array_key_exists('password', $smtpParams)) { + $smtpParams['password'] = $this->getCrypt()->decrypt($smtpParams['password']); + } + if ($smtpParams) { $smtpParams['fromName'] = $this->getUser()->get('name'); $emailSender->useSmtp($smtpParams); diff --git a/application/Espo/Services/EmailAccount.php b/application/Espo/Services/EmailAccount.php index aa8ceffef8..2d08db3f45 100644 --- a/application/Espo/Services/EmailAccount.php +++ b/application/Espo/Services/EmailAccount.php @@ -38,6 +38,7 @@ class EmailAccount extends Record protected function init() { $this->dependencies[] = 'fileManager'; + $this->dependencies[] = 'crypt'; } protected function getFileManager() @@ -45,6 +46,19 @@ class EmailAccount extends Record return $this->injections['fileManager']; } + protected function getCrypt() + { + return $this->injections['crypt']; + } + + protected function handleInput(&$data) + { + parent::handleInput($data); + if (array_key_exists('password', $data)) { + $data['password'] = $this->getCrypt()->encrypt($data['password']); + } + } + public function getFolders($params) { $password = $params['password']; @@ -52,7 +66,7 @@ class EmailAccount extends Record if (!empty($params['id'])) { $entity = $this->getEntityManager()->getEntity('EmailAccount', $params['id']); if ($entity) { - $password = $entity->get('password'); + $password = $this->getCrypt()->decrypt($entity->get('password')); } } @@ -122,7 +136,7 @@ class EmailAccount extends Record 'host' => $emailAccount->get('host'), 'port' => $emailAccount->get('port'), 'user' => $emailAccount->get('username'), - 'password' => $emailAccount->get('password'), + 'password' => $this->getCrypt()->decrypt($emailAccount->get('password')), ); if ($emailAccount->get('ssl')) { diff --git a/application/Espo/Services/Record.php b/application/Espo/Services/Record.php index 66786ad659..98005f4afd 100644 --- a/application/Espo/Services/Record.php +++ b/application/Espo/Services/Record.php @@ -282,12 +282,18 @@ class Record extends \Espo\Core\Services\Base } } } + + protected function handleInput(&$data) + { + + } public function createEntity($data) { $entity = $this->getEntity(); $this->filterInput($data); + $this->handleInput($data); $entity->set($data); @@ -307,6 +313,7 @@ class Record extends \Espo\Core\Services\Base } if ($this->storeEntity($entity)) { + $this->prepareEntityForOutput($entity); return $entity; } @@ -319,6 +326,7 @@ class Record extends \Espo\Core\Services\Base unset($data['deleted']); $this->filterInput($data); + $this->handleInput($data); $entity = $this->getEntity($id); @@ -333,6 +341,7 @@ class Record extends \Espo\Core\Services\Base } if ($this->storeEntity($entity)) { + $this->prepareEntityForOutput($entity); return $entity; } @@ -613,8 +622,8 @@ class Record extends \Espo\Core\Services\Base throw new Error(); } - public function prepareEntityForOutput($entity) - { + public function prepareEntityForOutput(Entity $entity) + { foreach ($this->internalFields as $field) { $entity->clear($field); } From c70ab7c127d9ea70fbc543c12abea224ea5a07dd Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Wed, 15 Oct 2014 11:17:44 +0300 Subject: [PATCH 015/139] convert lead layout in manager --- .../Crm/Resources/i18n/en_US/Admin.json | 5 ++++ .../res/templates/admin/layouts/index.tpl | 10 +++---- .../src/views/admin/layouts/detail-convert.js | 29 +++++++++++++++++++ .../client/src/views/admin/layouts/index.js | 20 +++++++++++++ 4 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 application/Espo/Modules/Crm/Resources/i18n/en_US/Admin.json create mode 100644 frontend/client/src/views/admin/layouts/detail-convert.js diff --git a/application/Espo/Modules/Crm/Resources/i18n/en_US/Admin.json b/application/Espo/Modules/Crm/Resources/i18n/en_US/Admin.json new file mode 100644 index 0000000000..711b65939c --- /dev/null +++ b/application/Espo/Modules/Crm/Resources/i18n/en_US/Admin.json @@ -0,0 +1,5 @@ +{ + "layouts": { + "detailConvert": "Convert Lead" + } +} diff --git a/frontend/client/res/templates/admin/layouts/index.tpl b/frontend/client/res/templates/admin/layouts/index.tpl index 18d51f3367..fa76cc9a33 100644 --- a/frontend/client/res/templates/admin/layouts/index.tpl +++ b/frontend/client/res/templates/admin/layouts/index.tpl @@ -3,17 +3,17 @@
    - {{#each scopeList}} + {{#each layoutScopeDataList}}
    -
    +
      - {{#each ../typeList}} + {{#each typeList}}
    • - +
    • {{/each}}
    diff --git a/frontend/client/src/views/admin/layouts/detail-convert.js b/frontend/client/src/views/admin/layouts/detail-convert.js new file mode 100644 index 0000000000..266295abd6 --- /dev/null +++ b/frontend/client/src/views/admin/layouts/detail-convert.js @@ -0,0 +1,29 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko + * Website: http://www.espocrm.com + * + * EspoCRM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EspoCRM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EspoCRM. If not, see http://www.gnu.org/licenses/. + ************************************************************************/ + +Espo.define('Views.Admin.Layouts.DetailConvert', 'Views.Admin.Layouts.Detail', function (Dep) { + + return Dep.extend({ + + + }); +}); + diff --git a/frontend/client/src/views/admin/layouts/index.js b/frontend/client/src/views/admin/layouts/index.js index a46b8051ee..4fc346baa7 100644 --- a/frontend/client/src/views/admin/layouts/index.js +++ b/frontend/client/src/views/admin/layouts/index.js @@ -28,6 +28,12 @@ Espo.define('Views.Admin.Layouts.Index', 'View', function (Dep) { scopeList: null, typeList: ['list', 'detail', 'listSmall', 'detailSmall', 'filters', 'massUpdate', 'relationships'], + + additionalLayouts: { + 'Opportunity': ['detailConvert'], + 'Contact': ['detailConvert'], + 'Account': ['detailConvert'], + }, scope: null, @@ -38,6 +44,20 @@ Espo.define('Views.Admin.Layouts.Index', 'View', function (Dep) { scopeList: this.scopeList, typeList: this.typeList, scope: this.scope, + layoutScopeDataList: (function () { + var dataList = []; + this.scopeList.forEach(function (scope) { + var d = {}; + d.scope = scope; + d.typeList = _.clone(this.typeList); + (this.additionalLayouts[scope] || []).forEach(function (item) { + d.typeList.push(item); + }); + + dataList.push(d); + }, this); + return dataList; + }).call(this) }; }, From 3fd23827417d35838678552da69960bc019a8668 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Wed, 15 Oct 2014 11:46:44 +0300 Subject: [PATCH 016/139] unlink method --- application/Espo/Core/Utils/File/Manager.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/application/Espo/Core/Utils/File/Manager.php b/application/Espo/Core/Utils/File/Manager.php index 2dbe3cf034..7865cc2f22 100644 --- a/application/Espo/Core/Utils/File/Manager.php +++ b/application/Espo/Core/Utils/File/Manager.php @@ -459,6 +459,17 @@ class Manager return false; } + + /** + * Remove file/files by given path + * + * @param array $filePaths - File paths list + * @return bool + */ + public function unlink($filePaths) + { + return $this->removeFile($filePaths); + } /** * Remove file/files by given path From 675975f7633ab17627e2e5b64cd3d5c956ab2fdd Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Wed, 15 Oct 2014 11:55:40 +0300 Subject: [PATCH 017/139] reset preferences to defaults --- application/Espo/Controllers/Preferences.php | 12 ++++++++++ application/Espo/Repositories/Preferences.php | 9 ++++++++ .../Espo/Resources/i18n/en_US/Global.json | 2 ++ .../src/views/preferences/record/edit.js | 22 ++++++++++++++++++- 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/application/Espo/Controllers/Preferences.php b/application/Espo/Controllers/Preferences.php index 4a95b0daba..0b7ceaf955 100644 --- a/application/Espo/Controllers/Preferences.php +++ b/application/Espo/Controllers/Preferences.php @@ -24,6 +24,7 @@ namespace Espo\Controllers; use \Espo\Core\Exceptions\Error; use \Espo\Core\Exceptions\Forbidden; +use \Espo\Core\Exceptions\BadRequest; use \Espo\Core\Exceptions\NotFound; class Preferences extends \Espo\Core\Controllers\Base @@ -52,6 +53,17 @@ class Preferences extends \Espo\Core\Controllers\Base } } + public function actionDelete($params, $data) + { + $userId = $params['id']; + if (empty($userId)) { + throw new BadRequest(); + } + $this->handleUserAccess($userId); + + return $this->getEntityManager()->getRepository('Preferences')->resetToDefaults($userId); + } + public function actionPatch($params, $data) { return $this->actionUpdate($params, $data); diff --git a/application/Espo/Repositories/Preferences.php b/application/Espo/Repositories/Preferences.php index 086c8f7be7..20386da253 100644 --- a/application/Espo/Repositories/Preferences.php +++ b/application/Espo/Repositories/Preferences.php @@ -120,6 +120,15 @@ class Preferences extends \Espo\Core\ORM\Repository return true; } } + + public function resetToDefaults($userId) + { + $fileName = $this->getFilePath($userId); + $this->getFileManager()->unlink($fileName); + if ($entity = $this->get($userId)) { + return $entity->toArray(); + } + } public function find(array $params) { diff --git a/application/Espo/Resources/i18n/en_US/Global.json b/application/Espo/Resources/i18n/en_US/Global.json index 9e139a02da..1bd60423a7 100644 --- a/application/Espo/Resources/i18n/en_US/Global.json +++ b/application/Espo/Resources/i18n/en_US/Global.json @@ -143,9 +143,11 @@ "fieldShouldBeLess": "{field} should be less then {value}", "fieldShouldBeGreater": "{field} should be greater then {value}", "fieldBadPasswordConfirm": "{field} confirmed improperly", + "resetPreferencesDone": "Preferences has been reset to defaults", "assignmentEmailNotificationSubject": "EspoCRM {entityType}: {Entity.name}", "assignmentEmailNotificationBody": "{assignerUserName} has assigned {entityType} '{Entity.name}' to you\n\n{recordUrl}", "confirmation": "Are you sure?", + "resetPreferencesConfirmation": "Are you sure you want to reset preferences to defaults?", "removeRecordConfirmation": "Are you sure you want to remove the record?", "unlinkRecordConfirmation": "Are you sure you want to unlink relationship?", "removeSelectedRecordsConfirmation": "Are you sure you want to remove selected records?" diff --git a/frontend/client/src/views/preferences/record/edit.js b/frontend/client/src/views/preferences/record/edit.js index 83d7f8abaf..04f22dc3ef 100644 --- a/frontend/client/src/views/preferences/record/edit.js +++ b/frontend/client/src/views/preferences/record/edit.js @@ -34,7 +34,12 @@ Espo.define('Views.Preferences.Record.Edit', 'Views.Record.Edit', function (Dep) { name: 'cancel', label: 'Cancel', - } + }, + { + name: 'reset', + label: 'Reset', + style: 'danger' + } ], dependencyDefs: { @@ -68,6 +73,21 @@ Espo.define('Views.Preferences.Record.Edit', 'Views.Record.Edit', function (Dep) }, + actionReset: function () { + if (confirm(this.translate('resetPreferencesConfirmation', 'messages'))) { + $.ajax({ + url: 'Preferences/' + this.model.id, + type: 'DELETE', + + }).done(function (data) { + Espo.Ui.success(this.translate('resetPreferencesDone', 'messages')); + this.model.set(data); + this.getPreferences().set(this.model.toJSON()); + this.getPreferences().trigger('update'); + }.bind(this)); + } + }, + afterRender: function () { Dep.prototype.afterRender.call(this); From ceef8268939d0ac574cb2aaa4949d84cbc97922c Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Wed, 15 Oct 2014 12:06:03 +0300 Subject: [PATCH 018/139] translate bool as boolean --- application/Espo/Resources/i18n/en_US/Admin.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/Espo/Resources/i18n/en_US/Admin.json b/application/Espo/Resources/i18n/en_US/Admin.json index 6cd5492d43..30eea5e1b4 100644 --- a/application/Espo/Resources/i18n/en_US/Admin.json +++ b/application/Espo/Resources/i18n/en_US/Admin.json @@ -62,10 +62,10 @@ "password": "Password", "parsonName": "Person Name", "autoincrement": "Auto-increment", - "bool": "Bool", + "bool": "Boolean", "currency": "Currency", "date": "Date", - "datetime": "Date-Time", + "datetime": "DateTime", "email": "Email", "enum": "Enum", "enumInt": "Enum Integer", From 8330bb12f1adf8cdd7bb0e1a6a8559056d9e4f58 Mon Sep 17 00:00:00 2001 From: Taras Machyshyn Date: Wed, 15 Oct 2014 14:59:34 +0300 Subject: [PATCH 019/139] changed hash algorithm of user's password --- .../Espo/Core/Utils/Authentication/Base.php | 11 ++ .../Espo/Core/Utils/Authentication/Espo.php | 11 +- .../Espo/Core/Utils/Authentication/LDAP.php | 2 +- application/Espo/Core/Utils/PasswordHash.php | 105 ++++++++++++++++++ .../Espo/Core/defaults/systemConfig.php | 1 + .../metadata/entityDefs/AuthToken.json | 2 +- .../Resources/metadata/entityDefs/User.json | 1 + application/Espo/Services/User.php | 89 ++++++++------- install/core/Installer.php | 15 ++- tests/Espo/Core/Utils/PasswordHashTest.php | 96 ++++++++++++++++ 10 files changed, 281 insertions(+), 52 deletions(-) create mode 100644 application/Espo/Core/Utils/PasswordHash.php create mode 100644 tests/Espo/Core/Utils/PasswordHashTest.php diff --git a/application/Espo/Core/Utils/Authentication/Base.php b/application/Espo/Core/Utils/Authentication/Base.php index 17905e09f7..144d108686 100644 --- a/application/Espo/Core/Utils/Authentication/Base.php +++ b/application/Espo/Core/Utils/Authentication/Base.php @@ -34,6 +34,8 @@ abstract class Base private $auth; + private $passwordHash; + public function __construct(Config $config, EntityManager $entityManager, Auth $auth) { $this->config = $config; @@ -56,5 +58,14 @@ abstract class Base return $this->auth; } + protected function getPasswordHash() + { + if (!isset($this->passwordHash)) { + $this->passwordHash = new \Espo\Core\Utils\PasswordHash($this->config); + } + + return $this->passwordHash; + } + } diff --git a/application/Espo/Core/Utils/Authentication/Espo.php b/application/Espo/Core/Utils/Authentication/Espo.php index 1adebac4dc..905d9f2056 100644 --- a/application/Espo/Core/Utils/Authentication/Espo.php +++ b/application/Espo/Core/Utils/Authentication/Espo.php @@ -18,30 +18,29 @@ * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. - ************************************************************************/ + ************************************************************************/ namespace Espo\Core\Utils\Authentication; use \Espo\Core\Exceptions\Error; class Espo extends Base -{ - +{ public function login($username, $password, \Espo\Entities\AuthToken $authToken = null) { if ($authToken) { $hash = $authToken->get('hash'); } else { - $hash = md5($password); + $hash = $this->getPasswordHash()->getHash($password); } - + $user = $this->getEntityManager()->getRepository('User')->findOne(array( 'whereClause' => array( 'userName' => $username, 'password' => $hash ), )); - + return $user; } } diff --git a/application/Espo/Core/Utils/Authentication/LDAP.php b/application/Espo/Core/Utils/Authentication/LDAP.php index abb4cf5d96..c76e7fae14 100644 --- a/application/Espo/Core/Utils/Authentication/LDAP.php +++ b/application/Espo/Core/Utils/Authentication/LDAP.php @@ -159,7 +159,7 @@ class LDAP extends Base */ protected function adminLogin($username, $password) { - $hash = md5($password); + $hash = $this->getPasswordHash()->getHash($password); $user = $this->getEntityManager()->getRepository('User')->findOne(array( 'whereClause' => array( diff --git a/application/Espo/Core/Utils/PasswordHash.php b/application/Espo/Core/Utils/PasswordHash.php new file mode 100644 index 0000000000..885794da00 --- /dev/null +++ b/application/Espo/Core/Utils/PasswordHash.php @@ -0,0 +1,105 @@ +config = $config; + } + + protected function getConfig() + { + return $this->config; + } + + /** + * Get hash of a pawword + * + * @param string $password + * @return string + */ + public function getHash($password, $useMd5 = true) + { + $salt = $this->getSalt(); + + if ($useMd5) { + $password = md5($password); + } + + $hash = crypt($password, $salt); + $hash = str_replace($salt, '', $hash); + + return $hash; + } + + /** + * Get a salt from config and normalize it + * + * @return string + */ + protected function getSalt() + { + $salt = $this->getConfig()->get('passwordSalt'); + if (!isset($salt)) { + throw new Error('Option "passwordSalt" does not exist in config.php'); + } + + $salt = $this->normalizeSalt($salt); + + return $salt; + } + + /** + * Convert salt in format in accordance to $saltFormat + * + * @param string $salt + * @return string + */ + protected function normalizeSalt($salt) + { + return str_replace("{0}", $salt, $this->saltFormat); + } + + /** + * Generate a new salt + * + * @return string + */ + public function generateSalt() + { + return substr(md5(uniqid()), 0, 16); + } +} \ No newline at end of file diff --git a/application/Espo/Core/defaults/systemConfig.php b/application/Espo/Core/defaults/systemConfig.php index 94d79e5005..5c7943193d 100644 --- a/application/Espo/Core/defaults/systemConfig.php +++ b/application/Espo/Core/defaults/systemConfig.php @@ -82,6 +82,7 @@ return array ( 'systemUser', 'permissionMap', 'permissionRules', + 'passwordSalt', ), 'adminItems' => array ( diff --git a/application/Espo/Resources/metadata/entityDefs/AuthToken.json b/application/Espo/Resources/metadata/entityDefs/AuthToken.json index 21e8f1a2e8..c314ce3a3f 100644 --- a/application/Espo/Resources/metadata/entityDefs/AuthToken.json +++ b/application/Espo/Resources/metadata/entityDefs/AuthToken.json @@ -6,7 +6,7 @@ }, "hash": { "type": "varchar", - "maxLength": "36", + "maxLength": 150, "index": true }, "userId": { diff --git a/application/Espo/Resources/metadata/entityDefs/User.json b/application/Espo/Resources/metadata/entityDefs/User.json index 0c746f061e..9f4672bcac 100644 --- a/application/Espo/Resources/metadata/entityDefs/User.json +++ b/application/Espo/Resources/metadata/entityDefs/User.json @@ -15,6 +15,7 @@ }, "password": { "type": "password", + "maxLength": 150, "internal": true }, "salutationName": { diff --git a/application/Espo/Services/User.php b/application/Espo/Services/User.php index 5556e6551c..5898568abf 100644 --- a/application/Espo/Services/User.php +++ b/application/Espo/Services/User.php @@ -18,7 +18,7 @@ * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. - ************************************************************************/ + ************************************************************************/ namespace Espo\Services; @@ -29,37 +29,37 @@ use \Espo\Core\Exceptions\NotFound; use \Espo\ORM\Entity; class User extends Record -{ +{ protected function init() { $this->dependencies[] = 'mailSender'; $this->dependencies[] = 'language'; } - + protected $internalFields = array('password'); - + protected function getMailSender() { return $this->injections['mailSender']; } - + protected function getLanguage() { return $this->injections['language']; } - + public function getEntity($id) - { + { if ($id == 'system') { throw new Forbidden(); } - + $entity = parent::getEntity($id); - return $entity; + return $entity; } - + public function findEntities($params) - { + { if (empty($params['where'])) { $params['where'] = array(); } @@ -68,50 +68,53 @@ class User extends Record 'field' => 'id', 'value' => 'system' ); - + $result = parent::findEntities($params); - return $result; - } - + return $result; + } + public function changePassword($userId, $password) { $user = $this->getEntityManager()->getEntity('User', $userId); if (!$user) { throw new NotFound(); } - + if (empty($password)) { throw new Error('Password can\'t be empty.'); } - + $user->set('password', $this->hashPassword($password)); - + $this->getEntityManager()->saveEntity($user); - + return true; } - + protected function hashPassword($password) { - return md5($password); + $config = $this->getConfig(); + $passwordHash = new \Espo\Core\Utils\PasswordHash($config); + + return $passwordHash->getHash($password); } - + public function createEntity($data) { - $newPassword = null; + $newPassword = null; if (array_key_exists('password', $data)) { $newPassword = $data['password']; $data['password'] = $this->hashPassword($data['password']); } - $user = parent::createEntity($data); - + $user = parent::createEntity($data); + if (!is_null($newPassword)) { $this->sendPassword($user, $newPassword); } - - return $user; + + return $user; } - + public function updateEntity($id, $data) { if ($id == 'system') { @@ -123,54 +126,54 @@ class User extends Record $data['password'] = $this->hashPassword($data['password']); } $user = parent::updateEntity($id, $data); - + if (!is_null($newPassword)) { try { $this->sendPassword($user, $newPassword); } catch (\Exception $e) {} } - + return $user; } - + protected function sendPassword(Entity $user, $password) - { + { $emailAddress = $user->get('emailAddress'); - + if (empty($emailAddress)) { return; } - + $email = $this->getEntityManager()->getEntity('Email'); - + if (!$this->getConfig()->get('smtpServer')) { return; } - - + + $subject = $this->getLanguage()->translate('accountInfoEmailSubject', 'messages', 'User'); $body = $this->getLanguage()->translate('accountInfoEmailBody', 'messages', 'User'); - + $body = str_replace('{userName}', $user->get('userName'), $body); $body = str_replace('{password}', $password, $body); $body = str_replace('{siteUrl}', $this->getConfig()->get('siteUrl'), $body); - + $email->set(array( 'subject' => $subject, 'body' => $body, 'isHtml' => false, 'to' => $emailAddress )); - + $this->getMailSender()->send($email); } - + public function deleteEntity($id) { if ($id == 'system') { throw new Forbidden(); } - return parent::deleteEntity($id); - } + return parent::deleteEntity($id); + } } diff --git a/install/core/Installer.php b/install/core/Installer.php index cd3a454a85..0d5b0468d3 100644 --- a/install/core/Installer.php +++ b/install/core/Installer.php @@ -35,6 +35,8 @@ class Installer protected $permissionError; + private $passwordHash; + protected $settingList = array( 'dateFormat', 'timeFormat', @@ -94,6 +96,16 @@ class Installer return $this->app->getContainer()->get('fileManager'); } + protected function getPasswordHash() + { + if (!isset($this->passwordHash)) { + $config = $this->getConfig(); + $this->passwordHash = new \Espo\Core\Utils\PasswordHash($config); + } + + return $this->passwordHash; + } + public function getVersion() { return $this->getConfig()->get('version'); @@ -160,6 +172,7 @@ class Installer 'database' => $database, 'language' => $language, 'siteUrl' => $siteUrl, + 'passwordSalt' => $this->getPasswordHash()->generateSalt(), ); $data = array_merge($data, $initData); @@ -266,7 +279,7 @@ class Installer $user = array( 'id' => '1', 'userName' => $userName, - 'password' => md5($password), + 'password' => $this->getPasswordHash()->getHash($password), 'lastName' => 'Admin', 'isAdmin' => '1', ); diff --git a/tests/Espo/Core/Utils/PasswordHashTest.php b/tests/Espo/Core/Utils/PasswordHashTest.php new file mode 100644 index 0000000000..af567034a9 --- /dev/null +++ b/tests/Espo/Core/Utils/PasswordHashTest.php @@ -0,0 +1,96 @@ +objects['config'] = $this->getMockBuilder('\Espo\Core\Utils\Config')->disableOriginalConstructor()->getMock(); + + $this->object = new \Espo\Core\Utils\PasswordHash($this->objects['config']); + + $this->reflection = new ReflectionHelper($this->object); + } + + protected function tearDown() + { + $this->object = NULL; + } + + public function testGenerateSalt() + { + $salt = $this->object->generateSalt(); + + $this->assertEquals(16, strlen($salt)); + } + + public function testNormalizeSalt() + { + $salt = $this->object->generateSalt(); + + $result = '$6$' . $salt . '$'; + $this->assertEquals($result, $this->reflection->invokeMethod('normalizeSalt', array($salt))); + } + + public function testGetSalt() + { + $this->objects['config'] + ->expects($this->once()) + ->method('get') + ->will($this->returnValue($this->salt)); + + $result = '$6$' . $this->salt . '$'; + $this->assertEquals($result, $this->reflection->invokeMethod('getSalt')); + } + + public function testGetSaltException() + { + $this->setExpectedException('\Espo\Core\Exceptions\Error'); + + $this->reflection->invokeMethod('getSalt'); + } + + public function testGetHash() + { + $password = 'test-password'; + + $this->objects['config'] + ->expects($this->once()) + ->method('get') + ->will($this->returnValue($this->salt)); + + $result = '4gDlJKdkj/MMo2axSwvvWUv0ktSUeGpis/wLcpL8aEBUxXTVa.rxFb1cfKzTiSE4ookBdNpLMheJmtZqzDSRA0'; + $this->assertEquals($result, $this->object->getHash($password)); + } +} From c67f2b20d4408df2da42b948503b28eed3bb74af Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Wed, 15 Oct 2014 15:01:17 +0300 Subject: [PATCH 020/139] layout manager: ability to make call full width wide --- .../res/templates/admin/layouts/grid.tpl | 26 ++++--- .../res/templates/admin/layouts/rows.tpl | 4 +- .../client/src/views/admin/layouts/detail.js | 6 +- .../client/src/views/admin/layouts/grid.js | 78 +++++++++++++++---- .../client/src/views/admin/layouts/rows.js | 11 ++- 5 files changed, 94 insertions(+), 31 deletions(-) diff --git a/frontend/client/res/templates/admin/layouts/grid.tpl b/frontend/client/res/templates/admin/layouts/grid.tpl index c2a9c7829c..1f8e49b725 100644 --- a/frontend/client/res/templates/admin/layouts/grid.tpl +++ b/frontend/client/res/templates/admin/layouts/grid.tpl @@ -55,6 +55,10 @@ float: left; } + #layout ul.panels ul.cells > li[data-full-width="true"] { + width: 94%; + } + #layout ul.cells > li { list-style: none; border: 1px solid #CCC; @@ -138,7 +142,7 @@ @@ -148,7 +152,7 @@
      {{#each disabledFields}}
    • {{translate this scope=../scope category='fields'}} -   +  
    • {{/each}}
    @@ -161,7 +165,7 @@
      - +
      <% @@ -169,7 +173,7 @@ var row = rows[i]; %>
    • -
      +
        <% for (var j in row) { @@ -179,13 +183,15 @@ var cell = row[j]; if (cell !== false) { %> -
      • <%= cell.label %> - +
      • <%= cell.label %> +
      • <% } else { %> -
      • +
      • + +
      • <% } } @@ -197,17 +203,17 @@ %>
      - +
    - - + + - +
    diff --git a/frontend/client/res/templates/fields/link-parent/edit.tpl b/frontend/client/res/templates/fields/link-parent/edit.tpl index 98433bf847..85e55c8bf9 100644 --- a/frontend/client/res/templates/fields/link-parent/edit.tpl +++ b/frontend/client/res/templates/fields/link-parent/edit.tpl @@ -1,13 +1,13 @@
    - - - - - - - - + + + + + + + +
    diff --git a/frontend/client/res/templates/fields/link-parent/search.tpl b/frontend/client/res/templates/fields/link-parent/search.tpl index 34c54270d7..f327c24e6e 100644 --- a/frontend/client/res/templates/fields/link-parent/search.tpl +++ b/frontend/client/res/templates/fields/link-parent/search.tpl @@ -1,12 +1,12 @@
    - - - - - + + + + +
    diff --git a/frontend/client/res/templates/fields/link/detail.tpl b/frontend/client/res/templates/fields/link/detail.tpl index 32622b4744..d0d4bd6cd1 100644 --- a/frontend/client/res/templates/fields/link/detail.tpl +++ b/frontend/client/res/templates/fields/link/detail.tpl @@ -1,5 +1,5 @@ {{#if idValue}} {{nameValue}} {{else}} - {{translate 'None'}} + {{translate 'None'}} {{/if}} diff --git a/frontend/client/res/templates/fields/link/edit.tpl b/frontend/client/res/templates/fields/link/edit.tpl index c1699d527c..8956a960aa 100644 --- a/frontend/client/res/templates/fields/link/edit.tpl +++ b/frontend/client/res/templates/fields/link/edit.tpl @@ -1,9 +1,9 @@
    - - + + - +
    diff --git a/frontend/client/res/templates/fields/link/search.tpl b/frontend/client/res/templates/fields/link/search.tpl index 4bf2d2905b..2d87612807 100644 --- a/frontend/client/res/templates/fields/link/search.tpl +++ b/frontend/client/res/templates/fields/link/search.tpl @@ -1,9 +1,9 @@
    - - - - - + + + + +
    diff --git a/frontend/client/res/templates/fields/person-name/edit.tpl b/frontend/client/res/templates/fields/person-name/edit.tpl index efea56371e..487c95cd69 100644 --- a/frontend/client/res/templates/fields/person-name/edit.tpl +++ b/frontend/client/res/templates/fields/person-name/edit.tpl @@ -1,13 +1,13 @@
    -
    - -
    -
    - -
    -
    - -
    +
    + +
    +
    + +
    +
    + +
    diff --git a/frontend/client/res/templates/fields/phone/detail.tpl b/frontend/client/res/templates/fields/phone/detail.tpl index dbe678dc1e..a0ad912ba5 100644 --- a/frontend/client/res/templates/fields/phone/detail.tpl +++ b/frontend/client/res/templates/fields/phone/detail.tpl @@ -1,10 +1,10 @@ {{#if phoneNumberData}} - {{#each phoneNumberData}} -
    - {{phoneNumber}} - ({{translateOption type scope=../../scope field=../../name}}) -
    - {{/each}} + {{#each phoneNumberData}} +
    + {{phoneNumber}} + ({{translateOption type scope=../../scope field=../../name}}) +
    + {{/each}} {{else}} - {{value}} + {{value}} {{/if}} diff --git a/frontend/client/res/templates/fields/phone/edit.tpl b/frontend/client/res/templates/fields/phone/edit.tpl index 7196f63a95..5a4498f5a4 100644 --- a/frontend/client/res/templates/fields/phone/edit.tpl +++ b/frontend/client/res/templates/fields/phone/edit.tpl @@ -1,20 +1,20 @@
    {{#each phoneNumberData}} -
    - - - - - - - - -
    +
    + + + + + + + + +
    {{/each}}
    diff --git a/frontend/client/res/templates/global-search/panel.tpl b/frontend/client/res/templates/global-search/panel.tpl index 25f0c66c14..623a399a1b 100644 --- a/frontend/client/res/templates/global-search/panel.tpl +++ b/frontend/client/res/templates/global-search/panel.tpl @@ -1,8 +1,8 @@
    -
    {{translate 'Global Search'}}
    -
    -
    - {{translate 'Loading...'}} -
    -
    +
    {{translate 'Global Search'}}
    +
    +
    + {{translate 'Loading...'}} +
    +
    diff --git a/frontend/client/res/templates/header.tpl b/frontend/client/res/templates/header.tpl index f6a782a18d..210f0e6153 100644 --- a/frontend/client/res/templates/header.tpl +++ b/frontend/client/res/templates/header.tpl @@ -1,31 +1,31 @@
    -
    -

    {{{header}}}

    -
    -
    -
    - {{#each items.buttons}} - {{#if link}} - {{translate label scope=../../scope}} - {{else}} - - {{/if}} - {{/each}} - - {{#if items.dropdown}} - - - {{/if}} -
    -
    +
    +

    {{{header}}}

    +
    +
    +
    + {{#each items.buttons}} + {{#if link}} + {{translate label scope=../../scope}} + {{else}} + + {{/if}} + {{/each}} + + {{#if items.dropdown}} + + + {{/if}} +
    +
    diff --git a/frontend/client/res/templates/import/index.tpl b/frontend/client/res/templates/import/index.tpl index 20f7471468..8ce14a7965 100644 --- a/frontend/client/res/templates/import/index.tpl +++ b/frontend/client/res/templates/import/index.tpl @@ -1,7 +1,7 @@
    - {{{step}}} + {{{step}}}
    diff --git a/frontend/client/res/templates/import/step-1.tpl b/frontend/client/res/templates/import/step-1.tpl index 7d1d0c5eb3..da69906b52 100644 --- a/frontend/client/res/templates/import/step-1.tpl +++ b/frontend/client/res/templates/import/step-1.tpl @@ -1,126 +1,126 @@

    {{translate 'Step 1' scope='Import'}}

    -
    -
    {{translate 'What to Import?' scope='Import'}}
    -
    -
    -
    - - -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    -
    +
    +
    {{translate 'What to Import?' scope='Import'}}
    +
    +
    +
    + + +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    +
    -
    -
    {{translate 'Properties' scope='Import'}}
    -
    -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    -
    -
    -
    +
    +
    {{translate 'Properties' scope='Import'}}
    +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    +
    -
    -
    {{translate 'Preview' scope='Import'}}
    -
    -
    -
    -
    -
    - -
    - -
    +
    +
    {{translate 'Preview' scope='Import'}}
    +
    +
    +
    +
    +
    + +
    + +
    diff --git a/frontend/client/res/templates/import/step-2.tpl b/frontend/client/res/templates/import/step-2.tpl index 71e05e7d77..4afd5b8d29 100644 --- a/frontend/client/res/templates/import/step-2.tpl +++ b/frontend/client/res/templates/import/step-2.tpl @@ -1,35 +1,35 @@

    {{translate 'Step 2' scope='Import'}}

    -
    -
    {{translate 'Field Mapping' scope='Import'}}
    -
    -
    -
    -
    -
    - -
    -
    {{translate 'Default Values' scope='Import'}}
    -
    -
    -
    - - -
    -
    -
    -
    -
    -
    - -
    - - -
    +
    +
    {{translate 'Field Mapping' scope='Import'}}
    +
    +
    +
    +
    +
    + +
    +
    {{translate 'Default Values' scope='Import'}}
    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    + +
    + + +
    diff --git a/frontend/client/res/templates/import/step-3.tpl b/frontend/client/res/templates/import/step-3.tpl index 68e261e7d4..14e46f4b9d 100644 --- a/frontend/client/res/templates/import/step-3.tpl +++ b/frontend/client/res/templates/import/step-3.tpl @@ -1,20 +1,20 @@ -
    -
    {{translate 'Result' scope='Import'}}
    -
    -

    {{translate scope category='scopeNamesPlural'}}

    -
    - {{translate 'Created' scope='Import'}}: {{result.countCreated}} -
    - {{translate 'Updated' scope='Import'}}: {{result.countUpdated}} -
    - -
    - {{translate 'Return to Import' scope='Import'}} - {{translate 'Show records' scope='Import'}} - {{#if result.countCreated}} - - {{/if}} -
    -
    -
    +
    +
    {{translate 'Result' scope='Import'}}
    +
    +

    {{translate scope category='scopeNamesPlural'}}

    +
    + {{translate 'Created' scope='Import'}}: {{result.countCreated}} +
    + {{translate 'Updated' scope='Import'}}: {{result.countUpdated}} +
    + +
    + {{translate 'Return to Import' scope='Import'}} + {{translate 'Show records' scope='Import'}} + {{#if result.countCreated}} + + {{/if}} +
    +
    +
    diff --git a/frontend/client/res/templates/login.tpl b/frontend/client/res/templates/login.tpl index 3e3b699396..d01d426bee 100644 --- a/frontend/client/res/templates/login.tpl +++ b/frontend/client/res/templates/login.tpl @@ -1,27 +1,27 @@
    -
    -
    -
    - -
    -
    -
    -
    -
    - - -
    -
    - - -
    -
    - -
    -
    -
    -
    -
    -
    +
    +
    +
    + +
    +
    +
    +
    +
    + + +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    +
    {{{footer}}}
    diff --git a/frontend/client/res/templates/modals/add-dashlet.tpl b/frontend/client/res/templates/modals/add-dashlet.tpl index bee90af5d9..d6e1df1569 100644 --- a/frontend/client/res/templates/modals/add-dashlet.tpl +++ b/frontend/client/res/templates/modals/add-dashlet.tpl @@ -1,8 +1,8 @@
      {{#each dashletList}} -
    • - {{translate this category="dashlets"}} - -
    • +
    • + {{translate this category="dashlets"}} + +
    • {{/each}}
    diff --git a/frontend/client/res/templates/modals/array-field-add.tpl b/frontend/client/res/templates/modals/array-field-add.tpl index 1b5ecafdc2..1d610df0c5 100644 --- a/frontend/client/res/templates/modals/array-field-add.tpl +++ b/frontend/client/res/templates/modals/array-field-add.tpl @@ -1,11 +1,11 @@ {{#unless optionList}} - {{translate 'No Data'}} + {{translate 'No Data'}} {{/unless}}
      {{#each optionList}} -
    • - {{#if ../translatedOptions}}{{prop ../../translatedOptions this}}{{else}}{{./this}}{{/if}} - -
    • +
    • + {{#if ../translatedOptions}}{{prop ../../translatedOptions this}}{{else}}{{./this}}{{/if}} + +
    • {{/each}}
    diff --git a/frontend/client/res/templates/modals/change-password.tpl b/frontend/client/res/templates/modals/change-password.tpl index 1d122a7525..561c9d1c8a 100644 --- a/frontend/client/res/templates/modals/change-password.tpl +++ b/frontend/client/res/templates/modals/change-password.tpl @@ -1,9 +1,9 @@
    - -
    {{{password}}}
    + +
    {{{password}}}
    - -
    {{{passwordConfirm}}}
    + +
    {{{passwordConfirm}}}
    diff --git a/frontend/client/res/templates/modals/duplicate.tpl b/frontend/client/res/templates/modals/duplicate.tpl index fe9b7f0374..95056eee48 100644 --- a/frontend/client/res/templates/modals/duplicate.tpl +++ b/frontend/client/res/templates/modals/duplicate.tpl @@ -1,13 +1,13 @@

    {{translate 'duplicate' category="messages"}}

    - - {{#each duplicates}} - - - - {{/each}} -
    - {{./this}} -
    + + {{#each duplicates}} + + + + {{/each}} +
    + {{./this}} +
    diff --git a/frontend/client/res/templates/modals/image-preview.tpl b/frontend/client/res/templates/modals/image-preview.tpl index b97e949165..fed2b20abf 100644 --- a/frontend/client/res/templates/modals/image-preview.tpl +++ b/frontend/client/res/templates/modals/image-preview.tpl @@ -1,5 +1,5 @@
    - +
    diff --git a/frontend/client/res/templates/modals/mass-update.tpl b/frontend/client/res/templates/modals/mass-update.tpl index f39ef40948..2fc2b08197 100644 --- a/frontend/client/res/templates/modals/mass-update.tpl +++ b/frontend/client/res/templates/modals/mass-update.tpl @@ -1,17 +1,17 @@ {{#unless fields}} - {{translate 'No fields available for Mass Update'}} -{{else}} + {{translate 'No fields available for Mass Update'}} +{{else}}
    -
    - - -
    +
    + + +
    {{/unless}}
    -
    +
    diff --git a/frontend/client/res/templates/modals/save-filters.tpl b/frontend/client/res/templates/modals/save-filters.tpl index 86fc4e38d2..34831d5b14 100644 --- a/frontend/client/res/templates/modals/save-filters.tpl +++ b/frontend/client/res/templates/modals/save-filters.tpl @@ -1,6 +1,6 @@
    - -
    - {{{name}}} -
    + +
    + {{{name}}} +
    diff --git a/frontend/client/res/templates/modals/select-records.tpl b/frontend/client/res/templates/modals/select-records.tpl index 904d85ff2b..9a3e2a053d 100644 --- a/frontend/client/res/templates/modals/select-records.tpl +++ b/frontend/client/res/templates/modals/select-records.tpl @@ -2,6 +2,6 @@
    {{{list}}}
    {{#if createButton}}
    - +
    {{/if}} diff --git a/frontend/client/res/templates/notifications/badge.tpl b/frontend/client/res/templates/notifications/badge.tpl index 8987b88ce4..1f5ececc0e 100644 --- a/frontend/client/res/templates/notifications/badge.tpl +++ b/frontend/client/res/templates/notifications/badge.tpl @@ -1,4 +1,4 @@ - +
    diff --git a/frontend/client/res/templates/notifications/panel.tpl b/frontend/client/res/templates/notifications/panel.tpl index 3e8c537a30..e573279890 100644 --- a/frontend/client/res/templates/notifications/panel.tpl +++ b/frontend/client/res/templates/notifications/panel.tpl @@ -1,8 +1,8 @@
    -
    {{translate 'Mark all read'}}{{translate 'Notifications'}}
    -
    -
    - {{translate 'Loading...'}} -
    -
    +
    {{translate 'Mark all read'}}{{translate 'Notifications'}}
    +
    +
    + {{translate 'Loading...'}} +
    +
    diff --git a/frontend/client/res/templates/notifications/read.tpl b/frontend/client/res/templates/notifications/read.tpl index 3574b35a75..5a97f6a50e 100644 --- a/frontend/client/res/templates/notifications/read.tpl +++ b/frontend/client/res/templates/notifications/read.tpl @@ -1,3 +1,3 @@ {{#unless isRead}} - + {{/unless}} diff --git a/frontend/client/res/templates/preferences/fields/smtp-email-address/detail.tpl b/frontend/client/res/templates/preferences/fields/smtp-email-address/detail.tpl index d3f7d0cf93..323dd2f2f8 100644 --- a/frontend/client/res/templates/preferences/fields/smtp-email-address/detail.tpl +++ b/frontend/client/res/templates/preferences/fields/smtp-email-address/detail.tpl @@ -1,8 +1,8 @@ {{#if value}} - {{value}} + {{value}} {{else}} - {{translate 'userHasNoEmailAddress' category='messages' scope='Admin'}} - {{#if isAdmin}} - {{translate 'Edit'}} - {{/if}} + {{translate 'userHasNoEmailAddress' category='messages' scope='Admin'}} + {{#if isAdmin}} + {{translate 'Edit'}} + {{/if}} {{/if}} diff --git a/frontend/client/res/templates/record/bottom.tpl b/frontend/client/res/templates/record/bottom.tpl index 1d1949fe75..bad11a3e76 100644 --- a/frontend/client/res/templates/record/bottom.tpl +++ b/frontend/client/res/templates/record/bottom.tpl @@ -1,28 +1,28 @@ {{#each panels}} -
    -
    -
    - {{#if buttons}} - {{#each buttons}} - - {{/each}} - {{/if}} - {{#if actions}} - - - {{/if}} -
    -

    {{title}}

    -
    -
    - {{{var name ../this}}} -
    -
    +
    +
    +
    + {{#if buttons}} + {{#each buttons}} + + {{/each}} + {{/if}} + {{#if actions}} + + + {{/if}} +
    +

    {{title}}

    +
    +
    + {{{var name ../this}}} +
    +
    {{/each}} diff --git a/frontend/client/res/templates/record/detail.tpl b/frontend/client/res/templates/record/detail.tpl index d19c87698b..fe7b9d5642 100644 --- a/frontend/client/res/templates/record/detail.tpl +++ b/frontend/client/res/templates/record/detail.tpl @@ -1,33 +1,33 @@
    - {{#if buttonsTop}} -
    - {{#each buttons}} - {{button name scope=../../scope label=label style=style}} - {{/each}} -
    - {{/if}} - + {{#if buttonsTop}} +
    + {{#each buttons}} + {{button name scope=../../scope label=label style=style}} + {{/each}} +
    + {{/if}} + -
    -
    -
    {{{record}}}
    -
    {{{extra}}}
    -
    {{{bottom}}}
    -
    -
    - {{{side}}} -
    -
    +
    +
    +
    {{{record}}}
    +
    {{{extra}}}
    +
    {{{bottom}}}
    +
    +
    + {{{side}}} +
    +
    - {{#if buttonsBottom}} -
    - {{#each buttons}} - {{button name scope=../../scope label=label style=style}} - {{/each}} -
    - {{/if}} + {{#if buttonsBottom}} +
    + {{#each buttons}} + {{button name scope=../../scope label=label style=style}} + {{/each}} +
    + {{/if}}
    diff --git a/frontend/client/res/templates/record/edit.tpl b/frontend/client/res/templates/record/edit.tpl index 14e5b1b484..fb4761f814 100644 --- a/frontend/client/res/templates/record/edit.tpl +++ b/frontend/client/res/templates/record/edit.tpl @@ -1,36 +1,36 @@
    - {{#if buttonsTop}} -
    - {{#each buttons}} - {{button name scope=../../scope label=label style=style}} - {{/each}} -
    - {{/if}} + {{#if buttonsTop}} +
    + {{#each buttons}} + {{button name scope=../../scope label=label style=style}} + {{/each}} +
    + {{/if}} -
    - {{#if isWide}} -
    - {{else}} -
    - {{/if}} -
    {{{record}}}
    -
    {{{extra}}}
    -
    {{{bottom}}}
    -
    -
    - {{{side}}} -
    -
    +
    + {{#if isWide}} +
    + {{else}} +
    + {{/if}} +
    {{{record}}}
    +
    {{{extra}}}
    +
    {{{bottom}}}
    +
    +
    + {{{side}}} +
    +
    - - {{#if buttonsBottom}} -
    - {{#each buttons}} - {{button name scope=../../scope label=label style=style}} - {{/each}} -
    - {{/if}} + + {{#if buttonsBottom}} +
    + {{#each buttons}} + {{button name scope=../../scope label=label style=style}} + {{/each}} +
    + {{/if}}
    diff --git a/frontend/client/res/templates/record/list-expanded.tpl b/frontend/client/res/templates/record/list-expanded.tpl index 76b1241e2c..bcf854981b 100644 --- a/frontend/client/res/templates/record/list-expanded.tpl +++ b/frontend/client/res/templates/record/list-expanded.tpl @@ -1,45 +1,45 @@ {{#if collection.models.length}} {{#if topBar}}
    - {{#if paginationTop}} -
    - {{{pagination}}} -
    - {{/if}} - - {{#if checkboxes}} -
    - - -
    - {{/if}} + {{#if paginationTop}} +
    + {{{pagination}}} +
    + {{/if}} + + {{#if checkboxes}} +
    + + +
    + {{/if}}
    {{/if}}
    -
      - {{#each rows}} - {{{var this ../this}}} - {{/each}} -
    - {{#unless paginationEnabled}} - {{#if showMoreEnabled}} - - {{/if}} - {{/unless}} +
      + {{#each rows}} + {{{var this ../this}}} + {{/each}} +
    + {{#unless paginationEnabled}} + {{#if showMoreEnabled}} + + {{/if}} + {{/unless}}
    {{#if bottomBar}} @@ -49,5 +49,5 @@ {{/if}} {{else}} - {{translate 'No Data'}} + {{translate 'No Data'}} {{/if}} diff --git a/frontend/client/res/templates/record/list-pagination.tpl b/frontend/client/res/templates/record/list-pagination.tpl index 670411435a..be5fd7f953 100644 --- a/frontend/client/res/templates/record/list-pagination.tpl +++ b/frontend/client/res/templates/record/list-pagination.tpl @@ -1,20 +1,20 @@ diff --git a/frontend/client/res/templates/record/list.tpl b/frontend/client/res/templates/record/list.tpl index 421870a2b1..d8a75eb1e8 100644 --- a/frontend/client/res/templates/record/list.tpl +++ b/frontend/client/res/templates/record/list.tpl @@ -2,69 +2,69 @@ {{#if topBar}}
    - {{#if paginationTop}} -
    - {{{pagination}}} -
    - {{/if}} - - {{#if checkboxes}} - {{#if actions}} -
    - - -
    - {{/if}} - {{/if}} + {{#if paginationTop}} +
    + {{{pagination}}} +
    + {{/if}} + + {{#if checkboxes}} + {{#if actions}} +
    + + +
    + {{/if}} + {{/if}}
    {{/if}}
    - - {{#if header}} - - - {{#if checkboxes}} - - {{/if}} - {{#each headerDefs}} - - {{/each}} - - - {{/if}} - - {{#each rows}} - {{{var this ../this}}} - {{/each}} - -
    - {{#if this.sortable}} - {{translate this.name scope=../../../collection.name category='fields'}} - {{#if this.sorted}}{{#if this.asc}}{{else}}{{/if}}{{/if}} - {{else}} - {{translate this.name scope=../../../collection.name category='fields'}} - {{/if}} -
    - {{#unless paginationEnabled}} - {{#if showMoreEnabled}} - - {{/if}} - {{/unless}} + + {{#if header}} + + + {{#if checkboxes}} + + {{/if}} + {{#each headerDefs}} + + {{/each}} + + + {{/if}} + + {{#each rows}} + {{{var this ../this}}} + {{/each}} + +
    + {{#if this.sortable}} + {{translate this.name scope=../../../collection.name category='fields'}} + {{#if this.sorted}}{{#if this.asc}}{{else}}{{/if}}{{/if}} + {{else}} + {{translate this.name scope=../../../collection.name category='fields'}} + {{/if}} +
    + {{#unless paginationEnabled}} + {{#if showMoreEnabled}} + + {{/if}} + {{/unless}}
    {{#if bottomBar}} @@ -74,5 +74,5 @@ {{/if}} {{else}} - {{translate 'No Data'}} + {{translate 'No Data'}} {{/if}} diff --git a/frontend/client/res/templates/record/merge.tpl b/frontend/client/res/templates/record/merge.tpl index 5530d0d61a..986706054f 100644 --- a/frontend/client/res/templates/record/merge.tpl +++ b/frontend/client/res/templates/record/merge.tpl @@ -1,42 +1,42 @@
    - - - - - {{#each models}} - - - {{/each}} - - - - {{#each rows}} - - - {{#each columns}} - - - {{/each}} - - {{/each}} - -
    - - - {{get this 'name'}} -
    - {{translate name scope=../scope category='fields'}} - - - -
    - {{{var fieldVariable ../../this}}} -
    -
    -
    - - -
    + + + + + {{#each models}} + + + {{/each}} + + + + {{#each rows}} + + + {{#each columns}} + + + {{/each}} + + {{/each}} + +
    + + + {{get this 'name'}} +
    + {{translate name scope=../scope category='fields'}} + + + +
    + {{{var fieldVariable ../../this}}} +
    +
    +
    + + +
    diff --git a/frontend/client/res/templates/record/panels/default-side.tpl b/frontend/client/res/templates/record/panels/default-side.tpl index 50df439077..5832cc6871 100644 --- a/frontend/client/res/templates/record/panels/default-side.tpl +++ b/frontend/client/res/templates/record/panels/default-side.tpl @@ -1,34 +1,34 @@
    {{#each fields}}
    - -
    - {{{var this ../this}}} -
    + +
    + {{{var this ../this}}} +
    {{/each}} -
    - - +
    + +
    - {{#ifAttrNotEmpty model 'createdById'}} -
    - -
    - - {{{createdAt}}} » {{{createdBy}}} -
    -
    - {{/ifAttrNotEmpty}} - - {{#ifAttrNotEmpty model 'modifiedById'}} -
    - -
    - {{{modifiedAt}}} » {{{modifiedBy}}} -
    -
    - {{/ifAttrNotEmpty}} + {{#ifAttrNotEmpty model 'createdById'}} +
    + +
    + + {{{createdAt}}} » {{{createdBy}}} +
    +
    + {{/ifAttrNotEmpty}} + + {{#ifAttrNotEmpty model 'modifiedById'}} +
    + +
    + {{{modifiedAt}}} » {{{modifiedBy}}} +
    +
    + {{/ifAttrNotEmpty}}
    diff --git a/frontend/client/res/templates/record/panels/side.tpl b/frontend/client/res/templates/record/panels/side.tpl index e3d455fedc..a20cbfeeed 100644 --- a/frontend/client/res/templates/record/panels/side.tpl +++ b/frontend/client/res/templates/record/panels/side.tpl @@ -1,12 +1,12 @@
    {{#each fields}}
    - -
    - {{{var this ../this}}} -
    + +
    + {{{var this ../this}}} +
    {{/each}}
    diff --git a/frontend/client/res/templates/record/row-actions/default.tpl b/frontend/client/res/templates/record/row-actions/default.tpl index 16c5dd1236..8f1bd56445 100644 --- a/frontend/client/res/templates/record/row-actions/default.tpl +++ b/frontend/client/res/templates/record/row-actions/default.tpl @@ -1,13 +1,13 @@ {{#if actions.length}}
    - - + +
    {{/if}} diff --git a/frontend/client/res/templates/record/search.tpl b/frontend/client/res/templates/record/search.tpl index e792198ae7..f5dd29d66f 100644 --- a/frontend/client/res/templates/record/search.tpl +++ b/frontend/client/res/templates/record/search.tpl @@ -1,58 +1,58 @@
    -
    -
    - {{#if leftDropdown}} -
    - - -
    - {{/if}} - -
    - -
    -
    -
    -
    -
    - - - -
    -
    +
    +
    + {{#if leftDropdown}} +
    + + +
    + {{/if}} + +
    + +
    +
    +
    +
    +
    + + + +
    +
    diff --git a/frontend/client/res/templates/record/side.tpl b/frontend/client/res/templates/record/side.tpl index 859d732fa4..582e051206 100644 --- a/frontend/client/res/templates/record/side.tpl +++ b/frontend/client/res/templates/record/side.tpl @@ -1,24 +1,24 @@ {{#each panels}}
    - {{#if label}} -
    -
    - {{#if actions}} - - - {{/if}} -
    -

    {{translate label scope=../../scope}}

    -
    - {{/if}} -
    - {{{var name ../this}}} -
    + {{#if label}} +
    +
    + {{#if actions}} + + + {{/if}} +
    +

    {{translate label scope=../../scope}}

    +
    + {{/if}} +
    + {{{var name ../this}}} +
    {{/each}} diff --git a/frontend/client/res/templates/role/table.tpl b/frontend/client/res/templates/role/table.tpl index 534d5bc8a1..5cd386883a 100644 --- a/frontend/client/res/templates/role/table.tpl +++ b/frontend/client/res/templates/role/table.tpl @@ -1,39 +1,39 @@ - - - - - {{#each actionList}} - - {{/each}} - - {{#each aclTable}} - - - - - - {{#each acl}} - - {{/each}} - - {{/each}} -
    {{translate 'Access' scope='Role'}}{{translate this scope='Role' category='actions'}}
    {{translate @key category='scopeNamesPlural'}} - {{#if ../editMode}} - - {{else}} - {{translateOption access scope='Role' field='accessList'}} - {{/if}} - - {{#if ../../editMode}} - - {{else}} - {{#ifNotEqual ../../access 'not-set'}} - {{translateOption ../level field='levelList' scope='Role'}} - {{/ifNotEqual}} - {{/if}} -
    + + + + + {{#each actionList}} + + {{/each}} + + {{#each aclTable}} + + + + + + {{#each acl}} + + {{/each}} + + {{/each}} +
    {{translate 'Access' scope='Role'}}{{translate this scope='Role' category='actions'}}
    {{translate @key category='scopeNamesPlural'}} + {{#if ../editMode}} + + {{else}} + {{translateOption access scope='Role' field='accessList'}} + {{/if}} + + {{#if ../../editMode}} + + {{else}} + {{#ifNotEqual ../../access 'not-set'}} + {{translateOption ../level field='levelList' scope='Role'}} + {{/ifNotEqual}} + {{/if}} +
    diff --git a/frontend/client/res/templates/scheduled-job/cronjob.tpl b/frontend/client/res/templates/scheduled-job/cronjob.tpl index dbfb1f986c..9641456f80 100644 --- a/frontend/client/res/templates/scheduled-job/cronjob.tpl +++ b/frontend/client/res/templates/scheduled-job/cronjob.tpl @@ -1,4 +1,4 @@
    -
     
    -
     
    +
     
    +
     
    diff --git a/frontend/client/res/templates/search/filter.tpl b/frontend/client/res/templates/search/filter.tpl index 7bda850a0a..d08d351690 100644 --- a/frontend/client/res/templates/search/filter.tpl +++ b/frontend/client/res/templates/search/filter.tpl @@ -1,8 +1,8 @@
    - {{#unless notRemovable}}{{/unless}} - -
    {{{field}}}
    + {{#unless notRemovable}}{{/unless}} + +
    {{{field}}}
    diff --git a/frontend/client/res/templates/settings/fields/currency-rates/edit.tpl b/frontend/client/res/templates/settings/fields/currency-rates/edit.tpl index ed5d04b387..f3df11ffc6 100644 --- a/frontend/client/res/templates/settings/fields/currency-rates/edit.tpl +++ b/frontend/client/res/templates/settings/fields/currency-rates/edit.tpl @@ -1,6 +1,6 @@ -{{#each rateValues}} -
    - {{@key}} - -
    +{{#each rateValues}} +
    + {{@key}} + +
    {{/each}} diff --git a/frontend/client/res/templates/site/master.tpl b/frontend/client/res/templates/site/master.tpl index 89c54e3d67..47209c59a0 100644 --- a/frontend/client/res/templates/site/master.tpl +++ b/frontend/client/res/templates/site/master.tpl @@ -1,5 +1,5 @@
    -
    {{{main}}}
    +
    {{{main}}}
    {{{footer}}}
    diff --git a/frontend/client/res/templates/site/navbar.tpl b/frontend/client/res/templates/site/navbar.tpl index 945e95b988..cb4d6c792a 100644 --- a/frontend/client/res/templates/site/navbar.tpl +++ b/frontend/client/res/templates/site/navbar.tpl @@ -1,57 +1,57 @@ diff --git a/frontend/client/res/templates/stream/notes/assign.tpl b/frontend/client/res/templates/stream/notes/assign.tpl index 004986a07e..966f3e02b2 100644 --- a/frontend/client/res/templates/stream/notes/assign.tpl +++ b/frontend/client/res/templates/stream/notes/assign.tpl @@ -1,14 +1,14 @@ {{#unless onlyContent}}
  • {{/unless}} - -
    - {{{message}}} -
    -
    - {{{createdAt}}} -
    - + +
    + {{{message}}} +
    +
    + {{{createdAt}}} +
    + {{#unless onlyContent}}
  • {{/unless}} diff --git a/frontend/client/res/templates/stream/notes/create-related.tpl b/frontend/client/res/templates/stream/notes/create-related.tpl index b32cdacb39..9fc090c528 100644 --- a/frontend/client/res/templates/stream/notes/create-related.tpl +++ b/frontend/client/res/templates/stream/notes/create-related.tpl @@ -2,14 +2,14 @@
  • {{/unless}} -
    - {{{message}}} -
    - -
    - {{{createdAt}}} -
    - +
    + {{{message}}} +
    + +
    + {{{createdAt}}} +
    + {{#unless onlyContent}}
  • {{/unless}} diff --git a/frontend/client/res/templates/stream/notes/create.tpl b/frontend/client/res/templates/stream/notes/create.tpl index bdeb0847b9..3427f64d37 100644 --- a/frontend/client/res/templates/stream/notes/create.tpl +++ b/frontend/client/res/templates/stream/notes/create.tpl @@ -2,17 +2,17 @@
  • {{/unless}} -
    - {{#if statusText}} - {{statusText}} - {{/if}} - {{{message}}} -
    - -
    - {{{createdAt}}} -
    - +
    + {{#if statusText}} + {{statusText}} + {{/if}} + {{{message}}} +
    + +
    + {{{createdAt}}} +
    + {{#unless onlyContent}}
  • {{/unless}} diff --git a/frontend/client/res/templates/stream/notes/email-received.tpl b/frontend/client/res/templates/stream/notes/email-received.tpl index 98cd5486c4..53d4ef83e5 100644 --- a/frontend/client/res/templates/stream/notes/email-received.tpl +++ b/frontend/client/res/templates/stream/notes/email-received.tpl @@ -1,19 +1,19 @@ {{#unless onlyContent}}
  • -{{/unless}} - -
    - {{translate 'Email'}} {{emailName}} - {{translate 'has been received' category='stream'}} - {{#if isUserStream}} {{translate 'for' category='stream'}} {{parentTypeString}} {{{parent}}} {{/if}} - -
    - - -
    - {{{createdAt}}} -
    - +{{/unless}} + +
    + {{translate 'Email'}} {{emailName}} + {{translate 'has been received' category='stream'}} + {{#if isUserStream}} {{translate 'for' category='stream'}} {{parentTypeString}} {{{parent}}} {{/if}} + +
    + + +
    + {{{createdAt}}} +
    + {{#unless onlyContent}}
  • {{/unless}} diff --git a/frontend/client/res/templates/stream/notes/post.tpl b/frontend/client/res/templates/stream/notes/post.tpl index 9b7c97ff2f..5851c71a72 100644 --- a/frontend/client/res/templates/stream/notes/post.tpl +++ b/frontend/client/res/templates/stream/notes/post.tpl @@ -1,44 +1,44 @@ {{#unless onlyContent}}
  • {{/unless}} - - {{#unless isUserStream}} -
    - {{#if acl.edit}} - - {{/if}} -
    - {{/unless}} - - -
    - {{{message}}} -
    - - {{#if post}} -
    - {{{post}}} -
    - {{/if}} - - {{#if attachments}} -
    - {{{attachments}}} -
    - {{/if}} - -
    - {{{createdAt}}} -
    - + + {{#unless isUserStream}} +
    + {{#if acl.edit}} + + {{/if}} +
    + {{/unless}} + + +
    + {{{message}}} +
    + + {{#if post}} +
    + {{{post}}} +
    + {{/if}} + + {{#if attachments}} +
    + {{{attachments}}} +
    + {{/if}} + +
    + {{{createdAt}}} +
    + {{#unless onlyContent}}
  • {{/unless}} diff --git a/frontend/client/res/templates/stream/notes/status.tpl b/frontend/client/res/templates/stream/notes/status.tpl index c1fda37110..f823fb8586 100644 --- a/frontend/client/res/templates/stream/notes/status.tpl +++ b/frontend/client/res/templates/stream/notes/status.tpl @@ -1,15 +1,15 @@ {{#unless onlyContent}}
  • {{/unless}} - -
    - {{statusText}} - {{{message}}} -
    - -
    - {{{createdAt}}} -
    + +
    + {{statusText}} + {{{message}}} +
    + +
    + {{{createdAt}}} +
    {{#unless onlyContent}}
  • diff --git a/frontend/client/res/templates/stream/notes/update.tpl b/frontend/client/res/templates/stream/notes/update.tpl index a65afe87d2..43b98c10cd 100644 --- a/frontend/client/res/templates/stream/notes/update.tpl +++ b/frontend/client/res/templates/stream/notes/update.tpl @@ -1,23 +1,23 @@ {{#unless onlyContent}}
  • {{/unless}} - -
    - {{{message}}} -
    - - - -
    - {{{createdAt}}} -
    + +
    + {{{message}}} +
    + + + +
    + {{{createdAt}}} +
    {{#unless onlyContent}}
  • diff --git a/frontend/client/res/templates/stream/panel.tpl b/frontend/client/res/templates/stream/panel.tpl index cb5be8b26e..cc87cbc3dc 100644 --- a/frontend/client/res/templates/stream/panel.tpl +++ b/frontend/client/res/templates/stream/panel.tpl @@ -1,15 +1,15 @@
    - -
    -
    - -
    -
    - {{{attachments}}} -
    -
    + +
    +
    + +
    +
    + {{{attachments}}} +
    +
    - {{{list}}} + {{{list}}}
    diff --git a/frontend/client/src/acl.js b/frontend/client/src/acl.js index 5718286b88..8bd9f2df1c 100644 --- a/frontend/client/src/acl.js +++ b/frontend/client/src/acl.js @@ -30,84 +30,84 @@ */ Espo.Acl = function (user) { - this.data = {}; - this.user = user || null; + this.data = {}; + this.user = user || null; } _.extend(Espo.Acl.prototype, { - data: null, - - user: null, - - set: function (data) { - data = data || {}; - this.data = data; - }, - - check: function (controller, action, isOwner, inTeam) { - if (this.user.isAdmin()) { - return true; - } - - if (controller in this.data) { - if (this.data[controller] === false) { - return false; - } - if (this.data[controller] === true) { - return true; - } - if (typeof action !== 'undefined') { - if (action in this.data[controller]) { - var value = this.data[controller][action]; - - if (value === 'all' || value === true) { - return true; - } - - if (!value || value === 'no') { - return false; - } - - if (typeof isOwner === 'undefined') { - return true; - } - - if (isOwner) { - if (value === 'own' || value === 'team') { - return true; - } - } - - //if (inTeam) { - if (value === 'team') { - return true; - } - //} - - return false; - } - } - return true; - } - return true; - }, - - checkModel: function (model, action) { - if (action == 'edit') { - if (!model.isEditable()) { - return false; - } - } - if (this.user.isAdmin()) { - return true; - } - return this.check(model.name, action, this.user.isOwner(model), this.user.inTeam(model)); - }, - - clear: function () { - this.data = {}; - } + data: null, + + user: null, + + set: function (data) { + data = data || {}; + this.data = data; + }, + + check: function (controller, action, isOwner, inTeam) { + if (this.user.isAdmin()) { + return true; + } + + if (controller in this.data) { + if (this.data[controller] === false) { + return false; + } + if (this.data[controller] === true) { + return true; + } + if (typeof action !== 'undefined') { + if (action in this.data[controller]) { + var value = this.data[controller][action]; + + if (value === 'all' || value === true) { + return true; + } + + if (!value || value === 'no') { + return false; + } + + if (typeof isOwner === 'undefined') { + return true; + } + + if (isOwner) { + if (value === 'own' || value === 'team') { + return true; + } + } + + //if (inTeam) { + if (value === 'team') { + return true; + } + //} + + return false; + } + } + return true; + } + return true; + }, + + checkModel: function (model, action) { + if (action == 'edit') { + if (!model.isEditable()) { + return false; + } + } + if (this.user.isAdmin()) { + return true; + } + return this.check(model.name, action, this.user.isOwner(model), this.user.inTeam(model)); + }, + + clear: function () { + this.data = {}; + } }); diff --git a/frontend/client/src/app.js b/frontend/client/src/app.js index ad1cbb283b..cb9f1b0d1f 100644 --- a/frontend/client/src/app.js +++ b/frontend/client/src/app.js @@ -21,448 +21,448 @@ var Espo = Espo || {}; Espo.App = function (options, callback) { - var options = options || {}; + var options = options || {}; - this.useCache = options.useCache || this.useCache; - this.url = options.url || this.url; + this.useCache = options.useCache || this.useCache; + this.url = options.url || this.url; - this.controllers = {}; + this.controllers = {}; - if (this.useCache) { - this.cache = new Espo.Cache(); - if (options.cacheTimestamp) { - this.cache.handleActuality(options.cacheTimestamp); - } - } + if (this.useCache) { + this.cache = new Espo.Cache(); + if (options.cacheTimestamp) { + this.cache.handleActuality(options.cacheTimestamp); + } + } - this.storage = new Espo.Storage(); + this.storage = new Espo.Storage(); - this.loader = Espo.loader; - this.loader.cache = this.cache; + this.loader = Espo.loader; + this.loader.cache = this.cache; - this._setupAjax(); + this._setupAjax(); - this.settings = new Espo['Models.Settings'](null, {cache: this.cache}); - if (!this.settings.loadFromCache()) { - this.settings.load(true); - } + this.settings = new Espo['Models.Settings'](null, {cache: this.cache}); + if (!this.settings.loadFromCache()) { + this.settings.load(true); + } - this.metadata = new Espo.Metadata(this.cache); - - this.language = new Espo.Language(this.cache); + this.metadata = new Espo.Metadata(this.cache); + + this.language = new Espo.Language(this.cache); - this.fieldManager = new Espo.FieldManager(); + this.fieldManager = new Espo.FieldManager(); - this.user = new Espo['Models.User'](); - this.preferences = new Espo['Models.Preferences'](); - this.preferences.settings = this.settings; - this.acl = new Espo.Acl(this.user); - - this.preferences.on('update', function (model) { - this.storage.set('user', 'preferences', this.preferences.toJSON()); - }, this); + this.user = new Espo['Models.User'](); + this.preferences = new Espo['Models.Preferences'](); + this.preferences.settings = this.settings; + this.acl = new Espo.Acl(this.user); + + this.preferences.on('update', function (model) { + this.storage.set('user', 'preferences', this.preferences.toJSON()); + }, this); - this._modelFactory = new Espo.ModelFactory(this.loader, this.metadata, this.user); - this._collectionFactory = new Espo.CollectionFactory(this.loader, this._modelFactory); + this._modelFactory = new Espo.ModelFactory(this.loader, this.metadata, this.user); + this._collectionFactory = new Espo.CollectionFactory(this.loader, this._modelFactory); - this._initDateTime(); - this._initView(); - this._initBaseController(); + this._initDateTime(); + this._initView(); + this._initBaseController(); - this._preLoader = new Espo.PreLoader(this.cache, this._viewFactory); - - var countLoaded = 0; - var manageCallback = function () { - countLoaded++; - if (countLoaded == 1) { - callback.call(this, this); - } - }.bind(this); - - this._preLoad(manageCallback); + this._preLoader = new Espo.PreLoader(this.cache, this._viewFactory); + + var countLoaded = 0; + var manageCallback = function () { + countLoaded++; + if (countLoaded == 1) { + callback.call(this, this); + } + }.bind(this); + + this._preLoad(manageCallback); } _.extend(Espo.App.prototype, { - useCache: false, + useCache: false, - user: null, + user: null, - preferences: null, + preferences: null, - settings: null, + settings: null, - metadata: null, + metadata: null, - language: null, + language: null, - fieldManager: null, + fieldManager: null, - cache: null, + cache: null, - loader: null, + loader: null, - url: 'api/v1', + url: 'api/v1', - auth: null, + auth: null, - baseController: null, + baseController: null, - controllers: null, + controllers: null, - router: null, + router: null, - _modelFactory: null, - _collectionFactory: null, - _viewFactory: null, - _viewLoader: null, - _viewHelper: null, + _modelFactory: null, + _collectionFactory: null, + _viewFactory: null, + _viewLoader: null, + _viewHelper: null, - start: function () { - this._initAuth(); - var onAuth = function () { - this.metadata.load(function () { - this.fieldManager.defs = this.metadata.get('fields'); - this.fieldManager.metadata = this.metadata; - - this.settings.defs = this.metadata.get('entityDefs.Settings'); - this.user.defs = this.metadata.get('entityDefs.User'); - this.preferences.defs = this.metadata.get('entityDefs.Preferences'); - + start: function () { + this._initAuth(); + var onAuth = function () { + this.metadata.load(function () { + this.fieldManager.defs = this.metadata.get('fields'); + this.fieldManager.metadata = this.metadata; + + this.settings.defs = this.metadata.get('entityDefs.Settings'); + this.user.defs = this.metadata.get('entityDefs.User'); + this.preferences.defs = this.metadata.get('entityDefs.Preferences'); + - this.loader.addLibsConfig(this.metadata.get('app.jsLibs') || {}); - - this._initRouter(); - }.bind(this)); - }.bind(this); + this.loader.addLibsConfig(this.metadata.get('app.jsLibs') || {}); + + this._initRouter(); + }.bind(this)); + }.bind(this); - if (!this.auth) { - this.baseController.login(); - } else { - this._initUserData(); - onAuth(); - } + if (!this.auth) { + this.baseController.login(); + } else { + this._initUserData(); + onAuth(); + } - this.on('auth', onAuth); - }, + this.on('auth', onAuth); + }, - _initRouter: function () { - this.router = new Espo.Router(); - this._viewHelper.router = this.router; - this.baseController._router = this.router; - this.router.on('routed', function (params) { - this.doAction(params); - }.bind(this)); - try { - Backbone.history.start(); - } catch (e) { - Backbone.history.loadUrl(); - } - }, + _initRouter: function () { + this.router = new Espo.Router(); + this._viewHelper.router = this.router; + this.baseController._router = this.router; + this.router.on('routed', function (params) { + this.doAction(params); + }.bind(this)); + try { + Backbone.history.start(); + } catch (e) { + Backbone.history.loadUrl(); + } + }, - doAction: function (params) { - this.trigger('action', params); + doAction: function (params) { + this.trigger('action', params); - this._getController(params.controller, function (controller) { - try { - controller.doAction(params.action, params.options); - this.trigger('action:done'); - } catch (e) { - switch (e.name) { - case 'AccessDenied': - this.baseController.error403(); - break; - case 'NotFound': - this.baseController.error404(); - break; - default: - throw e; - } - } - }.bind(this)); - }, + this._getController(params.controller, function (controller) { + try { + controller.doAction(params.action, params.options); + this.trigger('action:done'); + } catch (e) { + switch (e.name) { + case 'AccessDenied': + this.baseController.error403(); + break; + case 'NotFound': + this.baseController.error404(); + break; + default: + throw e; + } + } + }.bind(this)); + }, - _initBaseController: function () { - this.baseController = new Espo['Controllers.Base']({}, this._getControllerInjection()); - this._viewHelper.baseController = this.baseController; - }, + _initBaseController: function () { + this.baseController = new Espo['Controllers.Base']({}, this._getControllerInjection()); + this._viewHelper.baseController = this.baseController; + }, - _getControllerInjection: function () { - return { - viewFactory: this._viewFactory, - modelFactory: this._modelFactory, - collectionFactory: this._collectionFactory, - settings: this.settings, - user: this.user, - preferences: this.preferences, - acl: this.acl, - cache: this.cache, - router: this.router, - storage: this.storage, - metadata: this.metadata, - dateTime: this.dateTime, - }; - }, + _getControllerInjection: function () { + return { + viewFactory: this._viewFactory, + modelFactory: this._modelFactory, + collectionFactory: this._collectionFactory, + settings: this.settings, + user: this.user, + preferences: this.preferences, + acl: this.acl, + cache: this.cache, + router: this.router, + storage: this.storage, + metadata: this.metadata, + dateTime: this.dateTime, + }; + }, - _getController: function (name, callback) { - if (!(name || false)) { - callback(this.baseController); - return; - } - if (!(name in this.controllers)) { - try { - var className = this.metadata.get('clientDefs.' + name + '.controller'); - if (!className) { - var module = this.metadata.get('scopes.' + name + '.module'); - className = Espo.Utils.composeClassName(module, name, 'Controllers'); - } - - this.loader.load(className, function (controllerClass) { - this.controllers[name] = new controllerClass(this.baseController.params, this._getControllerInjection()); - this.controllers[name].name = name; - callback(this.controllers[name]); - }.bind(this), - function () { - this.baseController.error404(); - }.bind(this)); - return; - } catch (e) { - this.baseController.error404(); - } - } - callback(this.controllers[name]); - }, + _getController: function (name, callback) { + if (!(name || false)) { + callback(this.baseController); + return; + } + if (!(name in this.controllers)) { + try { + var className = this.metadata.get('clientDefs.' + name + '.controller'); + if (!className) { + var module = this.metadata.get('scopes.' + name + '.module'); + className = Espo.Utils.composeClassName(module, name, 'Controllers'); + } + + this.loader.load(className, function (controllerClass) { + this.controllers[name] = new controllerClass(this.baseController.params, this._getControllerInjection()); + this.controllers[name].name = name; + callback(this.controllers[name]); + }.bind(this), + function () { + this.baseController.error404(); + }.bind(this)); + return; + } catch (e) { + this.baseController.error404(); + } + } + callback(this.controllers[name]); + }, - _preLoad: function (callback) { - this._preLoader.load(callback, this); - }, + _preLoad: function (callback) { + this._preLoader.load(callback, this); + }, - _initDateTime: function () { - this.dateTime = new Espo.DateTime(); - this._modelFactory.dateTime = this.dateTime; - this.dateTime.setSettingsAndPreferences(this.settings, this.preferences); - }, + _initDateTime: function () { + this.dateTime = new Espo.DateTime(); + this._modelFactory.dateTime = this.dateTime; + this.dateTime.setSettingsAndPreferences(this.settings, this.preferences); + }, - _initView: function () { + _initView: function () { - var helper = this._viewHelper = new Espo.ViewHelper(); - helper.layoutManager = new Espo.LayoutManager({cache: this.cache}); - helper.settings = this.settings; - helper.user = this.user; - helper.preferences = this.preferences; - helper.acl = this.acl; - helper.modelFactory = this._modelFactory; - helper.collectionFactory = this._collectionFactory; - helper.storage = this.storage; - helper.dateTime = this.dateTime; - helper.language = this.language; - helper.metadata = this.metadata; - helper.fieldManager = this.fieldManager; - helper.cache = this.cache; - helper.storage = this.storage; + var helper = this._viewHelper = new Espo.ViewHelper(); + helper.layoutManager = new Espo.LayoutManager({cache: this.cache}); + helper.settings = this.settings; + helper.user = this.user; + helper.preferences = this.preferences; + helper.acl = this.acl; + helper.modelFactory = this._modelFactory; + helper.collectionFactory = this._collectionFactory; + helper.storage = this.storage; + helper.dateTime = this.dateTime; + helper.language = this.language; + helper.metadata = this.metadata; + helper.fieldManager = this.fieldManager; + helper.cache = this.cache; + helper.storage = this.storage; - this._viewLoader = function (viewName, callback) { - this.loader.load(Espo.Utils.composeViewClassName(viewName), callback); - }.bind(this); - - var self = this; - - - var getResourceInnerPath = function (type, name) { - switch (type) { - case 'template': - return 'res/templates/' + name.split('.').join('/') + '.tpl'; - case 'layoutTemplate': - return 'res/layout-types/' + name + '.tpl'; - case 'layout': - return 'res/layouts/' + name + '.json'; - } - }; - - var getResourcePath = function (type, name) { - var path; - if (name.indexOf(':') != -1) { - var arr = name.split(':'); - name = arr[1]; - var mod = arr[0]; - if (mod == 'custom') { - path = 'client/custom/' + getResourceInnerPath(type, name); - } else { - path = 'client/modules/' + mod + '/' + getResourceInnerPath(type, name); - } - } else { - path = 'client/' + getResourceInnerPath(type, name); - } - return path; - }; + this._viewLoader = function (viewName, callback) { + this.loader.load(Espo.Utils.composeViewClassName(viewName), callback); + }.bind(this); + + var self = this; + + + var getResourceInnerPath = function (type, name) { + switch (type) { + case 'template': + return 'res/templates/' + name.split('.').join('/') + '.tpl'; + case 'layoutTemplate': + return 'res/layout-types/' + name + '.tpl'; + case 'layout': + return 'res/layouts/' + name + '.json'; + } + }; + + var getResourcePath = function (type, name) { + var path; + if (name.indexOf(':') != -1) { + var arr = name.split(':'); + name = arr[1]; + var mod = arr[0]; + if (mod == 'custom') { + path = 'client/custom/' + getResourceInnerPath(type, name); + } else { + path = 'client/modules/' + mod + '/' + getResourceInnerPath(type, name); + } + } else { + path = 'client/' + getResourceInnerPath(type, name); + } + return path; + }; - this._viewFactory = new Bull.Factory({ - useCache: false, - defaultViewName: 'Base', - helper: helper, - viewLoader: this._viewLoader, - resources: { - loaders: { - 'template': function (name, callback) { - var path = getResourcePath('template', name); - self.loader.load('res!' + path, callback); - }, - 'layoutTemplate': function (name, callback) { - var path = getResourcePath('layoutTemplate', name); - self.loader.load('res!' + path, callback); - } - } - } - }); - }, + this._viewFactory = new Bull.Factory({ + useCache: false, + defaultViewName: 'Base', + helper: helper, + viewLoader: this._viewLoader, + resources: { + loaders: { + 'template': function (name, callback) { + var path = getResourcePath('template', name); + self.loader.load('res!' + path, callback); + }, + 'layoutTemplate': function (name, callback) { + var path = getResourcePath('layoutTemplate', name); + self.loader.load('res!' + path, callback); + } + } + } + }); + }, - _initAuth: function () { - this.auth = this.storage.get('user', 'auth') || null; + _initAuth: function () { + this.auth = this.storage.get('user', 'auth') || null; - this.baseController.on('login', function (data) { - this.auth = Base64.encode(data.auth.userName + ':' + data.auth.token); - this.storage.set('user', 'auth', this.auth); - this.storage.set('user', 'user', data.user); - this.storage.set('user', 'preferences', data.preferences); - this.storage.set('user', 'acl', data.acl || {}); - - this._initUserData(data); + this.baseController.on('login', function (data) { + this.auth = Base64.encode(data.auth.userName + ':' + data.auth.token); + this.storage.set('user', 'auth', this.auth); + this.storage.set('user', 'user', data.user); + this.storage.set('user', 'preferences', data.preferences); + this.storage.set('user', 'acl', data.acl || {}); + + this._initUserData(data); - this.trigger('auth'); + this.trigger('auth'); - }.bind(this)); + }.bind(this)); - this.baseController.on('logout', function () { - this.logout(); - }.bind(this)); - }, - - logout: function () { - - if (this.auth) { - var arr = Base64.decode(this.auth).split(':'); - if (arr.length > 1) { - $.ajax({ - url: 'App/action/destroyAuthToken', - type: 'POST', - data: JSON.stringify({ - token: arr[1] - }) - }); - } - } - - this.auth = null; - this.user.clear(); - this.preferences.clear(); - this.acl.clear(); - this.storage.clear('user', 'auth'); - this.storage.clear('user', 'user'); - this.storage.clear('user', 'preferences'); - this.storage.clear('user', 'acl'); - this.doAction({action: 'login'}); - this.language.clearCache(); + this.baseController.on('logout', function () { + this.logout(); + }.bind(this)); + }, + + logout: function () { + + if (this.auth) { + var arr = Base64.decode(this.auth).split(':'); + if (arr.length > 1) { + $.ajax({ + url: 'App/action/destroyAuthToken', + type: 'POST', + data: JSON.stringify({ + token: arr[1] + }) + }); + } + } + + this.auth = null; + this.user.clear(); + this.preferences.clear(); + this.acl.clear(); + this.storage.clear('user', 'auth'); + this.storage.clear('user', 'user'); + this.storage.clear('user', 'preferences'); + this.storage.clear('user', 'acl'); + this.doAction({action: 'login'}); + this.language.clearCache(); xhr = new XMLHttpRequest; xhr.open('GET', this.url + '/', !1, 'logout', 'logout'); xhr.send(''); xhr.abort(); - }, + }, - _initUserData: function (options) { - options = options || {}; - - if (this.auth !== null) { - - this.language.load(null, true); - this.dateTime.setLanguage(this.language); - - var userData = options.user || this.storage.get('user', 'user') || null; - var preferencesData = options.preferences || this.storage.get('user', 'preferences') || null; - var aclData = options.acl || this.storage.get('user', 'acl') || null; - - this.user.set(userData); - this.preferences.set(preferencesData); - this.acl.set(aclData); - - this.user.on('change', function () { - this.storage.set('user', 'user', this.user.toJSON()); - }, this); - - if (!this.auth) { - return; - } + _initUserData: function (options) { + options = options || {}; + + if (this.auth !== null) { + + this.language.load(null, true); + this.dateTime.setLanguage(this.language); + + var userData = options.user || this.storage.get('user', 'user') || null; + var preferencesData = options.preferences || this.storage.get('user', 'preferences') || null; + var aclData = options.acl || this.storage.get('user', 'acl') || null; + + this.user.set(userData); + this.preferences.set(preferencesData); + this.acl.set(aclData); + + this.user.on('change', function () { + this.storage.set('user', 'user', this.user.toJSON()); + }, this); + + if (!this.auth) { + return; + } - var arr = Base64.decode(this.auth).split(':'); - var xhr = new XMLHttpRequest(); - xhr.open('GET', this.url + '/', false, arr[0], arr[1]); - xhr.send(''); - } - }, + var arr = Base64.decode(this.auth).split(':'); + var xhr = new XMLHttpRequest(); + xhr.open('GET', this.url + '/', false, arr[0], arr[1]); + xhr.send(''); + } + }, - _setupAjax: function () { - var self = this; - $.ajaxSetup({ - beforeSend: function (xhr, options) { - if (!options.local && self.url) { - this.url = Espo.Utils.trimSlash(self.url) + '/' + this.url; - } - if (self.auth !== null) { - xhr.setRequestHeader('Authorization', 'Basic ' + self.auth); - xhr.setRequestHeader('Espo-Authorization', self.auth); - } - }, - dataType: 'json', - timeout: 60000, - contentType: 'application/json' - }); - - $(document).ajaxError(function (event, xhr, options) { - if (xhr.errorIsHandled) { - return; - } - switch (xhr.status) { - case 0: - if (xhr.statusText == 'timeout') { - Espo.Ui.error(self.language.translate('Timeout')); - } - break; - case 200: - Espo.Ui.error(self.language.translate('Bad server response')); - console.error('Bad server response: ' + xhr.responseText); - break; - case 401: - if (!options.login) { - Espo.Ui.error(self.language.translate('Auth error')); - if (self.auth) { - self.logout(); - } - } - break; - case 403: - if (options.main) { - self.baseController.error403(); - } else { - Espo.Ui.error(self.language.translate('Error') + ' ' + xhr.status); - } - break; - case 404: - if (options.main) { - self.baseController.error404(); - } else { - Espo.Ui.error(self.language.translate('Error') + ' ' + xhr.status); - } - break; - default: - Espo.Ui.error(self.language.translate('Error') + ' ' + xhr.status); - } - - var statusReason = xhr.getResponseHeader('X-Status-Reason'); - if (statusReason) { - console.error('Server side error: ' + statusReason); - } - }); - }, + _setupAjax: function () { + var self = this; + $.ajaxSetup({ + beforeSend: function (xhr, options) { + if (!options.local && self.url) { + this.url = Espo.Utils.trimSlash(self.url) + '/' + this.url; + } + if (self.auth !== null) { + xhr.setRequestHeader('Authorization', 'Basic ' + self.auth); + xhr.setRequestHeader('Espo-Authorization', self.auth); + } + }, + dataType: 'json', + timeout: 60000, + contentType: 'application/json' + }); + + $(document).ajaxError(function (event, xhr, options) { + if (xhr.errorIsHandled) { + return; + } + switch (xhr.status) { + case 0: + if (xhr.statusText == 'timeout') { + Espo.Ui.error(self.language.translate('Timeout')); + } + break; + case 200: + Espo.Ui.error(self.language.translate('Bad server response')); + console.error('Bad server response: ' + xhr.responseText); + break; + case 401: + if (!options.login) { + Espo.Ui.error(self.language.translate('Auth error')); + if (self.auth) { + self.logout(); + } + } + break; + case 403: + if (options.main) { + self.baseController.error403(); + } else { + Espo.Ui.error(self.language.translate('Error') + ' ' + xhr.status); + } + break; + case 404: + if (options.main) { + self.baseController.error404(); + } else { + Espo.Ui.error(self.language.translate('Error') + ' ' + xhr.status); + } + break; + default: + Espo.Ui.error(self.language.translate('Error') + ' ' + xhr.status); + } + + var statusReason = xhr.getResponseHeader('X-Status-Reason'); + if (statusReason) { + console.error('Server side error: ' + statusReason); + } + }); + }, }, Backbone.Events); diff --git a/frontend/client/src/cache.js b/frontend/client/src/cache.js index f59dfb34c0..d941cf45ef 100644 --- a/frontend/client/src/cache.js +++ b/frontend/client/src/cache.js @@ -24,83 +24,83 @@ Espo.Cache = function () { }; _.extend(Espo.Cache.prototype, { - - _prefix: 'cache', - - handleActuality: function (cacheTimestamp) { - var stored = parseInt(this.get('app', 'cacheTimestamp')); - if (stored) { - if (stored !== cacheTimestamp) { - this.clear(); - } - } else { - this.clear(); - this.set('app', 'cacheTimestamp', cacheTimestamp); - } - }, - - _composeFullPrefix: function (type) { - return this._prefix + '-' + type; - }, + + _prefix: 'cache', + + handleActuality: function (cacheTimestamp) { + var stored = parseInt(this.get('app', 'cacheTimestamp')); + if (stored) { + if (stored !== cacheTimestamp) { + this.clear(); + } + } else { + this.clear(); + this.set('app', 'cacheTimestamp', cacheTimestamp); + } + }, + + _composeFullPrefix: function (type) { + return this._prefix + '-' + type; + }, - _composeKey: function (type, name) { - return this._composeFullPrefix(type) + '-' + name; - }, + _composeKey: function (type, name) { + return this._composeFullPrefix(type) + '-' + name; + }, - _checkType: function (type) { - if (typeof type === 'undefined' && toString.call(type) != '[object String]') { - throw new TypeError("Bad type \"" + type + "\" passed to Bull.Cacher()."); - } - }, + _checkType: function (type) { + if (typeof type === 'undefined' && toString.call(type) != '[object String]') { + throw new TypeError("Bad type \"" + type + "\" passed to Bull.Cacher()."); + } + }, - get: function (type, name) { - this._checkType(type); + get: function (type, name) { + this._checkType(type); - var key = this._composeKey(type, name); - var stored = localStorage.getItem(key); - if (stored) { - var str = stored; - if (stored[0] == "{" || stored[0] == "[") { - try { - str = JSON.parse(stored); - } catch (error) { - str = stored; - } - stored = str; - } - return stored; - } - return null; - }, + var key = this._composeKey(type, name); + var stored = localStorage.getItem(key); + if (stored) { + var str = stored; + if (stored[0] == "{" || stored[0] == "[") { + try { + str = JSON.parse(stored); + } catch (error) { + str = stored; + } + stored = str; + } + return stored; + } + return null; + }, - set: function (type, name, value) { - this._checkType(type); - var key = this._composeKey(type, name); - if (value instanceof Object) { - value = JSON.stringify(value); - } - localStorage.setItem(key, value); - }, + set: function (type, name, value) { + this._checkType(type); + var key = this._composeKey(type, name); + if (value instanceof Object) { + value = JSON.stringify(value); + } + localStorage.setItem(key, value); + }, - clear: function (type, name) { - var reText; - if (typeof type !== 'undefined') { - if (typeof name === 'undefined') { - reText = '^' + this._composeFullPrefix(type); - } else { - reText = '^' + this._composeKey(type, name); - } - } else { - reText = '^' + this._prefix + '-'; - } - var re = new RegExp(reText); - for (var i in localStorage) { - if (re.test(i)) { - delete localStorage[i]; - } - } - }, + clear: function (type, name) { + var reText; + if (typeof type !== 'undefined') { + if (typeof name === 'undefined') { + reText = '^' + this._composeFullPrefix(type); + } else { + reText = '^' + this._composeKey(type, name); + } + } else { + reText = '^' + this._prefix + '-'; + } + var re = new RegExp(reText); + for (var i in localStorage) { + if (re.test(i)) { + delete localStorage[i]; + } + } + }, }); - + diff --git a/frontend/client/src/collection-factory.js b/frontend/client/src/collection-factory.js index 25e551abc8..d6517418a1 100644 --- a/frontend/client/src/collection-factory.js +++ b/frontend/client/src/collection-factory.js @@ -20,37 +20,37 @@ ************************************************************************/ Espo.CollectionFactory = function (loader, modelFactory) { - this.loader = loader; - this.modelFactory = modelFactory; + this.loader = loader; + this.modelFactory = modelFactory; }; _.extend(Espo.CollectionFactory.prototype, { - loader: null, + loader: null, - modelFactory: null, + modelFactory: null, - create: function (name, callback, context) { - context = context || this; - - this.modelFactory.getSeed(name, function (seed) { - - var asc = this.modelFactory.metadata.get('entityDefs.' + name + '.collection.asc'); - var sortBy = this.modelFactory.metadata.get('entityDefs.' + name + '.collection.sortBy'); - - var className = this.modelFactory.metadata.get('clientDefs.' + name + '.collection') || 'Collection'; + create: function (name, callback, context) { + context = context || this; + + this.modelFactory.getSeed(name, function (seed) { + + var asc = this.modelFactory.metadata.get('entityDefs.' + name + '.collection.asc'); + var sortBy = this.modelFactory.metadata.get('entityDefs.' + name + '.collection.sortBy'); + + var className = this.modelFactory.metadata.get('clientDefs.' + name + '.collection') || 'Collection'; - Espo.loader.load(className, function (collectionClass) { - var collection = new collectionClass(null, { - name: name, - asc: asc, - sortBy: sortBy - }); - collection.model = seed; - collection._user = this.modelFactory.user; - callback.call(context, collection); - }.bind(this)); - }.bind(this)); - } + Espo.loader.load(className, function (collectionClass) { + var collection = new collectionClass(null, { + name: name, + asc: asc, + sortBy: sortBy + }); + collection.model = seed; + collection._user = this.modelFactory.user; + callback.call(context, collection); + }.bind(this)); + }.bind(this)); + } }); diff --git a/frontend/client/src/collection.js b/frontend/client/src/collection.js index 950434e550..80899a3eb9 100644 --- a/frontend/client/src/collection.js +++ b/frontend/client/src/collection.js @@ -21,101 +21,101 @@ Espo.Collection = Backbone.Collection.extend({ - name: null, + name: null, - total: 0, + total: 0, - offset: 0, + offset: 0, - maxSize: 20, + maxSize: 20, - sortBy: 'id', + sortBy: 'id', - asc: false, + asc: false, - where: null, + where: null, - _user: null, + _user: null, - initialize: function (models, options) { - options = options || {}; - this.name = options.name || this.name; - this.urlRoot = this.urlRoot || this.name; - this.url = this.url || this.urlRoot; - - this.sortBy = options.sortBy || this.sortBy; - this.asc = ('asc' in options) ? options.asc : this.asc; + initialize: function (models, options) { + options = options || {}; + this.name = options.name || this.name; + this.urlRoot = this.urlRoot || this.name; + this.url = this.url || this.urlRoot; + + this.sortBy = options.sortBy || this.sortBy; + this.asc = ('asc' in options) ? options.asc : this.asc; - Backbone.Collection.prototype.initialize.call(this); - }, + Backbone.Collection.prototype.initialize.call(this); + }, - sort: function (field, asc) { - this.sortBy = field; - this.asc = asc; - this.fetch(); - }, + sort: function (field, asc) { + this.sortBy = field; + this.asc = asc; + this.fetch(); + }, - nextPage: function () { - var offset = this.offset + this.maxSize; - this.setOffset(offset); - }, + nextPage: function () { + var offset = this.offset + this.maxSize; + this.setOffset(offset); + }, - previousPage: function () { - var offset = this.offset - this.maxSize; - this.setOffset(offset); - }, + previousPage: function () { + var offset = this.offset - this.maxSize; + this.setOffset(offset); + }, - firstPage: function () { - this.setOffset(0); - }, + firstPage: function () { + this.setOffset(0); + }, - lastPage: function () { - var offset = this.total - this.total % this.maxSize; - this.setOffset(offset); - }, + lastPage: function () { + var offset = this.total - this.total % this.maxSize; + this.setOffset(offset); + }, - setOffset: function (offset) { - if (offset < 0) { - throw new RangeError('offset can not be less than 0'); - } - if (offset > this.total) { - throw new RangeError('offset can not be larger than total count'); - } - this.offset = offset; - this.fetch(); - }, + setOffset: function (offset) { + if (offset < 0) { + throw new RangeError('offset can not be less than 0'); + } + if (offset > this.total) { + throw new RangeError('offset can not be larger than total count'); + } + this.offset = offset; + this.fetch(); + }, - parse: function (response) { - this.total = response.total; - return response.list; - }, + parse: function (response) { + this.total = response.total; + return response.list; + }, - fetch: function (options) { - var options = options || {}; - options.data = options.data || {}; + fetch: function (options) { + var options = options || {}; + options.data = options.data || {}; - this.offset = options.offset || this.offset; - this.sortBy = options.sortBy || this.sortBy; - this.asc = options.asc || this.asc; - this.where = options.where || this.where; + this.offset = options.offset || this.offset; + this.sortBy = options.sortBy || this.sortBy; + this.asc = options.asc || this.asc; + this.where = options.where || this.where; - if (!('maxSize' in options)) { - options.data.maxSize = options.more ? this.maxSize : ((this.length > this.maxSize) ? this.length : this.maxSize); - } else { - options.data.maxSize = options.maxSize; - } - - options.data.offset = options.more ? this.length : this.offset; - options.data.sortBy = this.sortBy; - options.data.asc = this.asc; - options.data.where = this.where; - - return Backbone.Collection.prototype.fetch.call(this, options); - }, + if (!('maxSize' in options)) { + options.data.maxSize = options.more ? this.maxSize : ((this.length > this.maxSize) ? this.length : this.maxSize); + } else { + options.data.maxSize = options.maxSize; + } + + options.data.offset = options.more ? this.length : this.offset; + options.data.sortBy = this.sortBy; + options.data.asc = this.asc; + options.data.where = this.where; + + return Backbone.Collection.prototype.fetch.call(this, options); + }, - getUser: function () { - return this._user; - }, + getUser: function () { + return this._user; + }, }); diff --git a/frontend/client/src/collections/note.js b/frontend/client/src/collections/note.js index 77abcaac31..d0d2122858 100644 --- a/frontend/client/src/collections/note.js +++ b/frontend/client/src/collections/note.js @@ -19,23 +19,23 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ Espo.define('Collections.Note', 'Collection', function (Dep) { - - return Dep.extend({ - - fetchNew: function (options) { - var options = options || {}; - options.data = options.data || {}; - - if (this.length) { - options.data.after = this.models[0].get('createdAt'); - options.remove = false; - options.at = 0; - options.maxSize = null; - } - - this.fetch(options); - }, - - }); - + + return Dep.extend({ + + fetchNew: function (options) { + var options = options || {}; + options.data = options.data || {}; + + if (this.length) { + options.data.after = this.models[0].get('createdAt'); + options.remove = false; + options.at = 0; + options.maxSize = null; + } + + this.fetch(options); + }, + + }); + }); diff --git a/frontend/client/src/controller.js b/frontend/client/src/controller.js index 5185092bad..ba3f47724b 100644 --- a/frontend/client/src/controller.js +++ b/frontend/client/src/controller.js @@ -21,238 +21,238 @@ /** * Controller. Views, Models and Collections are created here. -*/ +*/ Espo.Controller = function (params, injections) { - this.initialize(); - this.params = params || {}; - this.viewFactory = injections.viewFactory; - this.modelFactory = injections.modelFactory; - this.collectionFactory = injections.collectionFactory; - - this._settings = injections.settings || null; - this._user = injections.user || null; - this._preferences = injections.preferences || null; - this._acl = injections.acl || null; - this._cache = injections.cache || null; - this._router = injections.router || null; - this._storage = injections.storage || null; - this._metadata = injections.metadata || null; - this._dateTime = injections.dateTime || null; - - this.set('masterRendered', false); + this.initialize(); + this.params = params || {}; + this.viewFactory = injections.viewFactory; + this.modelFactory = injections.modelFactory; + this.collectionFactory = injections.collectionFactory; + + this._settings = injections.settings || null; + this._user = injections.user || null; + this._preferences = injections.preferences || null; + this._acl = injections.acl || null; + this._cache = injections.cache || null; + this._router = injections.router || null; + this._storage = injections.storage || null; + this._metadata = injections.metadata || null; + this._dateTime = injections.dateTime || null; + + this.set('masterRendered', false); }; _.extend(Espo.Controller.prototype, { - - defaultAction: 'index', - - name: false, - - params: null, - - viewFactory: null, - - modelFactory: null, - - controllerFactory: null, - - initialize: function () {}, - - getConfig: function () { - return this._settings; - }, - - getUser: function () { - return this._user; - }, - - getPreferences: function () { - return this._preferences; - }, - - getAcl: function () { - return this._acl; - }, - - getCache: function () { - return this._cache; - }, - - getRouter: function () { - return this._router; - }, - - getStorage: function () { - return this._storage; - }, - - getMetadata: function () { - return this._metadata; - }, - - getDateTime: function () { - return this._dateTime; - }, - - /** - * Get parameter of all controllers. - * @param key - * @return null if doesn't exist. - */ - get: function (key) { - if (key in this.params) { - return this.params[key]; - } - return null; - }, - - /** - * Set paramer for all controllers. - * @param key Name of view. - * @param value. - */ - set: function (key, value) { - this.params[key] = value; - }, - - checkAccess: function (action) { - return true; - }, - - handleAccessGlobal: function () { - if (!this.checkAccessGlobal()) { - throw new Espo.Exceptions.AccessDenied("Denied access to action '" + this.name + "#" + action + "'"); - } - }, - - checkAccessGlobal: function () { - return true; - }, - - handleCheckAccess: function (action) { - if (!this.checkAccess(action)) { - throw new Espo.Exceptions.AccessDenied("Denied access to action '" + this.name + "#" + action + "'"); - } - }, - - doAction: function (action, options) { - this.handleAccessGlobal(); - - action = action || this.defaultAction; - var method = action; - if (!(method in this)) { - throw new Espo.Exceptions.NotFound("Action '" + this.name + "#" + action + "' is not found"); - } - - var preMethod = 'before' + Espo.Utils.upperCaseFirst(method); - var postMethod = 'after' + Espo.Utils.upperCaseFirst(method); - - if (preMethod in this) { - this[preMethod].call(this, options || {}); - } - this[method].call(this, options || {}); - if (postMethod in this) { - this[postMethod].call(this, options || {}); - } - }, - - /** - * Create master view, render it if not rendered and return it. - * @param {Function} callback Master view will be argument for this. - */ - master: function (callback) { - var entire = this.get('entire'); - if (entire) { - entire.remove(); - this.set('entire', null); - } - var master = this.get('master'); - if (!master) { - this.viewFactory.create('Site.Master', null, function (master) { - this.set('master', master); - if (!this.get('masterRendered')) { - master.render(function () { - this.set('masterRendered', true); - callback.call(this, master); - }.bind(this)); - return; - } - callback.call(this, master); - }.bind(this)); - } else { - callback.call(this, master); - } - }, - - /** - * Create main view in master and return it. - * @param {String} view Name of view. - * @param {Object} options Options for view. - * @return {Espo.View} - */ - main: function (view, options, callback) { - var view = view || 'Base'; - var master = this.master(function (master) { - master.showLoadingNotification(); - options = options || {}; - options.el = '#main'; - this.viewFactory.create(view, options, function (main) { - main.once('render', function () { - main.updatePageTitle(); - master.hideLoadingNotification(); - }); - master.setView('main', main); - - main.once('after:render', function () { - $(window).scrollTop(0) - }); - - if (callback) { - callback.call(this, main); - } else { - main.render(); - } - }); - }.bind(this)); - }, - - showLoadingNotification: function () { - var master = this.get('master'); - if (master) { - master.showLoadingNotification(); - } - }, - - hideLoadingNotification: function () { - var master = this.get('master'); - if (master) { - master.hideLoadingNotification(); - } - }, - - /** - * Create view in the body tag. - * @param {String} view Name of view. - * @param {Object} options Options for view. - * @return {Espo.View} - */ - entire: function (view, options, callback) { - var master = this.get('master'); - if (master) { - master.remove(); - } - this.set('master', null); - this.set('masterRendered', false); - options = options || {}; - options.el = 'body'; - this.viewFactory.create(view, options, function (view) { - this.set('entire', view); - callback(view); - }.bind(this)); - } + + defaultAction: 'index', + + name: false, + + params: null, + + viewFactory: null, + + modelFactory: null, + + controllerFactory: null, + + initialize: function () {}, + + getConfig: function () { + return this._settings; + }, + + getUser: function () { + return this._user; + }, + + getPreferences: function () { + return this._preferences; + }, + + getAcl: function () { + return this._acl; + }, + + getCache: function () { + return this._cache; + }, + + getRouter: function () { + return this._router; + }, + + getStorage: function () { + return this._storage; + }, + + getMetadata: function () { + return this._metadata; + }, + + getDateTime: function () { + return this._dateTime; + }, + + /** + * Get parameter of all controllers. + * @param key + * @return null if doesn't exist. + */ + get: function (key) { + if (key in this.params) { + return this.params[key]; + } + return null; + }, + + /** + * Set paramer for all controllers. + * @param key Name of view. + * @param value. + */ + set: function (key, value) { + this.params[key] = value; + }, + + checkAccess: function (action) { + return true; + }, + + handleAccessGlobal: function () { + if (!this.checkAccessGlobal()) { + throw new Espo.Exceptions.AccessDenied("Denied access to action '" + this.name + "#" + action + "'"); + } + }, + + checkAccessGlobal: function () { + return true; + }, + + handleCheckAccess: function (action) { + if (!this.checkAccess(action)) { + throw new Espo.Exceptions.AccessDenied("Denied access to action '" + this.name + "#" + action + "'"); + } + }, + + doAction: function (action, options) { + this.handleAccessGlobal(); + + action = action || this.defaultAction; + var method = action; + if (!(method in this)) { + throw new Espo.Exceptions.NotFound("Action '" + this.name + "#" + action + "' is not found"); + } + + var preMethod = 'before' + Espo.Utils.upperCaseFirst(method); + var postMethod = 'after' + Espo.Utils.upperCaseFirst(method); + + if (preMethod in this) { + this[preMethod].call(this, options || {}); + } + this[method].call(this, options || {}); + if (postMethod in this) { + this[postMethod].call(this, options || {}); + } + }, + + /** + * Create master view, render it if not rendered and return it. + * @param {Function} callback Master view will be argument for this. + */ + master: function (callback) { + var entire = this.get('entire'); + if (entire) { + entire.remove(); + this.set('entire', null); + } + var master = this.get('master'); + if (!master) { + this.viewFactory.create('Site.Master', null, function (master) { + this.set('master', master); + if (!this.get('masterRendered')) { + master.render(function () { + this.set('masterRendered', true); + callback.call(this, master); + }.bind(this)); + return; + } + callback.call(this, master); + }.bind(this)); + } else { + callback.call(this, master); + } + }, + + /** + * Create main view in master and return it. + * @param {String} view Name of view. + * @param {Object} options Options for view. + * @return {Espo.View} + */ + main: function (view, options, callback) { + var view = view || 'Base'; + var master = this.master(function (master) { + master.showLoadingNotification(); + options = options || {}; + options.el = '#main'; + this.viewFactory.create(view, options, function (main) { + main.once('render', function () { + main.updatePageTitle(); + master.hideLoadingNotification(); + }); + master.setView('main', main); + + main.once('after:render', function () { + $(window).scrollTop(0) + }); + + if (callback) { + callback.call(this, main); + } else { + main.render(); + } + }); + }.bind(this)); + }, + + showLoadingNotification: function () { + var master = this.get('master'); + if (master) { + master.showLoadingNotification(); + } + }, + + hideLoadingNotification: function () { + var master = this.get('master'); + if (master) { + master.hideLoadingNotification(); + } + }, + + /** + * Create view in the body tag. + * @param {String} view Name of view. + * @param {Object} options Options for view. + * @return {Espo.View} + */ + entire: function (view, options, callback) { + var master = this.get('master'); + if (master) { + master.remove(); + } + this.set('master', null); + this.set('masterRendered', false); + options = options || {}; + options.el = 'body'; + this.viewFactory.create(view, options, function (view) { + this.set('entire', view); + callback(view); + }.bind(this)); + } }, Backbone.Events); -Espo.Controller.extend = Backbone.Router.extend; +Espo.Controller.extend = Backbone.Router.extend; diff --git a/frontend/client/src/controllers/about.js b/frontend/client/src/controllers/about.js index 0bf8926452..ca25ba5e3a 100644 --- a/frontend/client/src/controllers/about.js +++ b/frontend/client/src/controllers/about.js @@ -19,16 +19,16 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ Espo.define('Controllers.About', 'Controller', function (Dep) { - - return Dep.extend({ - - defaultAction: 'about', - - about: function () { - this.main('About', {}, function (view) { - view.render(); - }); - }, - }); - + + return Dep.extend({ + + defaultAction: 'about', + + about: function () { + this.main('About', {}, function (view) { + view.render(); + }); + }, + }); + }); diff --git a/frontend/client/src/controllers/admin.js b/frontend/client/src/controllers/admin.js index 960443dd6e..cd9b0a89ce 100644 --- a/frontend/client/src/controllers/admin.js +++ b/frontend/client/src/controllers/admin.js @@ -19,175 +19,175 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ Espo.define('Controllers.Admin', 'Controller', function (Dep) { - - return Dep.extend({ - - checkAccessGlobal: function () { - if (this.getUser().isAdmin()) { - return true; - } - return false; - }, - - index: function () { - this.main('Admin.Index', null); - }, - - layouts: function (options) { - var scope = options.scope || null; - var type = options.type || null; - - this.main('Admin.Layouts.Index', {scope: scope, type: type}); - }, - - fieldManager: function (options) { - var scope = options.scope || null; - var field = options.field || null; + + return Dep.extend({ + + checkAccessGlobal: function () { + if (this.getUser().isAdmin()) { + return true; + } + return false; + }, + + index: function () { + this.main('Admin.Index', null); + }, + + layouts: function (options) { + var scope = options.scope || null; + var type = options.type || null; + + this.main('Admin.Layouts.Index', {scope: scope, type: type}); + }, + + fieldManager: function (options) { + var scope = options.scope || null; + var field = options.field || null; - this.main('Admin.FieldManager.Index', {scope: scope, field: field}); - }, - - upgrade: function (options) { - this.main('Admin.Upgrade.Index'); - }, - - getSettingsModel: function () { - var model = this.getConfig().clone(); - model.defs = this.getConfig().defs; - - return model; - }, - - settings: function () { - var model = this.getSettingsModel(); - - model.once('sync', function () { - model.id = '1'; - this.main('Edit', { - model: model, - views: { - header: {template: 'admin.settings.header'}, - body: {view: 'Admin.Settings'}, - }, - }); - }, this); - model.fetch(); - }, - - outboundEmail: function () { - var model = this.getSettingsModel(); - - model.once('sync', function () { - model.id = '1'; - this.main('Edit', { - model: model, - views: { - header: {template: 'admin.settings.header-outbound-email'}, - body: {view: 'Admin.OutboundEmail'}, - }, - }); - }, this); - model.fetch(); - }, - - currency: function () { - var model = this.getSettingsModel(); - - model.once('sync', function () { - model.id = '1'; - this.main('Edit', { - model: model, - views: { - header: {template: 'admin.settings.header-currency'}, - body: {view: 'Admin.Currency'}, - }, - }); - }, this); - model.fetch(); - }, - - authTokens: function () { - this.collectionFactory.create('AuthToken', function (collection) { - var searchManager = new Espo.SearchManager(collection, 'list', this.getStorage(), this.getDateTime()); - searchManager.loadStored(); - collection.where = searchManager.getWhere(); - collection.maxSize = this.getConfig().get('recordsPerPage') || collection.maxSize; + this.main('Admin.FieldManager.Index', {scope: scope, field: field}); + }, + + upgrade: function (options) { + this.main('Admin.Upgrade.Index'); + }, + + getSettingsModel: function () { + var model = this.getConfig().clone(); + model.defs = this.getConfig().defs; + + return model; + }, + + settings: function () { + var model = this.getSettingsModel(); + + model.once('sync', function () { + model.id = '1'; + this.main('Edit', { + model: model, + views: { + header: {template: 'admin.settings.header'}, + body: {view: 'Admin.Settings'}, + }, + }); + }, this); + model.fetch(); + }, + + outboundEmail: function () { + var model = this.getSettingsModel(); + + model.once('sync', function () { + model.id = '1'; + this.main('Edit', { + model: model, + views: { + header: {template: 'admin.settings.header-outbound-email'}, + body: {view: 'Admin.OutboundEmail'}, + }, + }); + }, this); + model.fetch(); + }, + + currency: function () { + var model = this.getSettingsModel(); + + model.once('sync', function () { + model.id = '1'; + this.main('Edit', { + model: model, + views: { + header: {template: 'admin.settings.header-currency'}, + body: {view: 'Admin.Currency'}, + }, + }); + }, this); + model.fetch(); + }, + + authTokens: function () { + this.collectionFactory.create('AuthToken', function (collection) { + var searchManager = new Espo.SearchManager(collection, 'list', this.getStorage(), this.getDateTime()); + searchManager.loadStored(); + collection.where = searchManager.getWhere(); + collection.maxSize = this.getConfig().get('recordsPerPage') || collection.maxSize; - this.main('Admin.AuthToken.List', { - scope: 'AuthToken', - collection: collection, - searchManager: searchManager, - }); - }, this); - }, - - userInterface: function () { - var model = this.getSettingsModel(); - - model.once('sync', function () { - model.id = '1'; - this.main('Edit', { - model: model, - views: { - header: {template: 'admin.settings.header-user-interface'}, - body: {view: 'Admin.UserInterface'}, - }, - }); - }, this); - model.fetch(); - }, - - authentication: function () { - var model = this.getSettingsModel(); - - model.once('sync', function () { - model.id = '1'; - this.main('Edit', { - model: model, - views: { - header: {template: 'admin.settings.header-authentication'}, - body: {view: 'Admin.Authentication'}, - }, - }); - }, this); - model.fetch(); - }, - - integrations: function (options) { - var integration = options.name || null; - - this.main('Admin.Integrations.Index', {integration: integration}); - }, - - extensions: function (options) { - this.main('Admin.Extensions.Index'); - }, - - rebuild: function (options) { - var master = this.get('master'); - Espo.Ui.notify(master.translate('Please wait...')); - this.getRouter().navigate('#Admin'); - $.ajax({ - url: 'Admin/rebuild', - success: function () { - var msg = master.translate('Rebuild has been done', 'labels', 'Admin'); - Espo.Ui.success(msg); - }.bind(this) - }); - }, - - clearCache: function (options) { - var master = this.get('master'); - Espo.Ui.notify(master.translate('Please wait...')); - this.getRouter().navigate('#Admin'); - $.ajax({ - url: 'Admin/clearCache', - success: function () { - var msg = master.translate('Cache has been cleared', 'labels', 'Admin'); - Espo.Ui.success(msg); - }.bind(this) - }); - }, - }); - + this.main('Admin.AuthToken.List', { + scope: 'AuthToken', + collection: collection, + searchManager: searchManager, + }); + }, this); + }, + + userInterface: function () { + var model = this.getSettingsModel(); + + model.once('sync', function () { + model.id = '1'; + this.main('Edit', { + model: model, + views: { + header: {template: 'admin.settings.header-user-interface'}, + body: {view: 'Admin.UserInterface'}, + }, + }); + }, this); + model.fetch(); + }, + + authentication: function () { + var model = this.getSettingsModel(); + + model.once('sync', function () { + model.id = '1'; + this.main('Edit', { + model: model, + views: { + header: {template: 'admin.settings.header-authentication'}, + body: {view: 'Admin.Authentication'}, + }, + }); + }, this); + model.fetch(); + }, + + integrations: function (options) { + var integration = options.name || null; + + this.main('Admin.Integrations.Index', {integration: integration}); + }, + + extensions: function (options) { + this.main('Admin.Extensions.Index'); + }, + + rebuild: function (options) { + var master = this.get('master'); + Espo.Ui.notify(master.translate('Please wait...')); + this.getRouter().navigate('#Admin'); + $.ajax({ + url: 'Admin/rebuild', + success: function () { + var msg = master.translate('Rebuild has been done', 'labels', 'Admin'); + Espo.Ui.success(msg); + }.bind(this) + }); + }, + + clearCache: function (options) { + var master = this.get('master'); + Espo.Ui.notify(master.translate('Please wait...')); + this.getRouter().navigate('#Admin'); + $.ajax({ + url: 'Admin/clearCache', + success: function () { + var msg = master.translate('Cache has been cleared', 'labels', 'Admin'); + Espo.Ui.success(msg); + }.bind(this) + }); + }, + }); + }); diff --git a/frontend/client/src/controllers/base.js b/frontend/client/src/controllers/base.js index 20368c9222..9e19c509ef 100644 --- a/frontend/client/src/controllers/base.js +++ b/frontend/client/src/controllers/base.js @@ -20,46 +20,46 @@ ************************************************************************/ Espo.define('Controllers.Base', 'Controller', function (Dep) { - return Dep.extend({ + return Dep.extend({ - login: function () { - this.entire('Login', {}, function (login) { - login.render(); - login.on('login', function (data) { - this.trigger('login', data); - }.bind(this)); - }.bind(this)); - }, + login: function () { + this.entire('Login', {}, function (login) { + login.render(); + login.on('login', function (data) { + this.trigger('login', data); + }.bind(this)); + }.bind(this)); + }, - logout: function () { - this.trigger('logout'); - }, - - clearCache: function (options) { - var cache = this.getCache(); - if (cache) { - cache.clear(); - this.getRouter().navigateBack(); - window.location.reload(); - } else { - Espo.Ui.notify('Cache is not enabled', 'error', 3000); - this.getRouter().navigateBack(); - } - }, + logout: function () { + this.trigger('logout'); + }, + + clearCache: function (options) { + var cache = this.getCache(); + if (cache) { + cache.clear(); + this.getRouter().navigateBack(); + window.location.reload(); + } else { + Espo.Ui.notify('Cache is not enabled', 'error', 3000); + this.getRouter().navigateBack(); + } + }, - error404: function () { - this.entire('Base', {template: 'errors.404'}, function (view) { - view.render(); - }); - }, + error404: function () { + this.entire('Base', {template: 'errors.404'}, function (view) { + view.render(); + }); + }, - error403: function () { - this.entire('Base', {template: 'errors.403'}, function (view) { - view.render(); - }); - }, - + error403: function () { + this.entire('Base', {template: 'errors.403'}, function (view) { + view.render(); + }); + }, + - }); + }); }); diff --git a/frontend/client/src/controllers/external-account.js b/frontend/client/src/controllers/external-account.js index e05b4bbc02..045a535663 100644 --- a/frontend/client/src/controllers/external-account.js +++ b/frontend/client/src/controllers/external-account.js @@ -20,34 +20,34 @@ ************************************************************************/ Espo.define('Controllers.ExternalAccount', 'Controller', function (Dep) { - - return Dep.extend({ - - defaultAction: 'list', - - list: function (options) { - this.collectionFactory.create('ExternalAccount', function (collection) { - collection.once('sync', function () { - this.main('ExternalAccount.Index', { - collection: collection, - }); - }, this); - collection.fetch(); - }, this); - }, - - edit: function (options) { - var id = options.id; - - this.collectionFactory.create('ExternalAccount', function (collection) { - collection.once('sync', function () { - this.main('ExternalAccount.Index', { - collection: collection, - id: id - }); - }, this); - collection.fetch(); - }, this); - }, - }); + + return Dep.extend({ + + defaultAction: 'list', + + list: function (options) { + this.collectionFactory.create('ExternalAccount', function (collection) { + collection.once('sync', function () { + this.main('ExternalAccount.Index', { + collection: collection, + }); + }, this); + collection.fetch(); + }, this); + }, + + edit: function (options) { + var id = options.id; + + this.collectionFactory.create('ExternalAccount', function (collection) { + collection.once('sync', function () { + this.main('ExternalAccount.Index', { + collection: collection, + id: id + }); + }, this); + collection.fetch(); + }, this); + }, + }); }); diff --git a/frontend/client/src/controllers/home.js b/frontend/client/src/controllers/home.js index 570de7eca1..2a0eda0832 100644 --- a/frontend/client/src/controllers/home.js +++ b/frontend/client/src/controllers/home.js @@ -20,21 +20,21 @@ ************************************************************************/ Espo.define('Controllers.Home', 'Controller', function (Dep) { - return Dep.extend({ + return Dep.extend({ - index: function () { - this.main('Home', null); - }, + index: function () { + this.main('Home', null); + }, - search: function (text) { - $.ajax({ - url: 'search', - type: 'GET', - data: { - text: text - }, - }); - }, - }); + search: function (text) { + $.ajax({ + url: 'search', + type: 'GET', + data: { + text: text + }, + }); + }, + }); }); diff --git a/frontend/client/src/controllers/import.js b/frontend/client/src/controllers/import.js index 05c167e87c..521235a637 100644 --- a/frontend/client/src/controllers/import.js +++ b/frontend/client/src/controllers/import.js @@ -19,20 +19,20 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ Espo.define('Controllers.Import', 'Controller', function (Dep) { - - return Dep.extend({ - - checkAccess: function () { - if (this.getUser().isAdmin()) { - return true; - } - return false; - }, - - index: function () { - this.main('Import.Index', null); - }, - - }); - + + return Dep.extend({ + + checkAccess: function () { + if (this.getUser().isAdmin()) { + return true; + } + return false; + }, + + index: function () { + this.main('Import.Index', null); + }, + + }); + }); diff --git a/frontend/client/src/controllers/page.js b/frontend/client/src/controllers/page.js index 5292beb212..99b598c726 100644 --- a/frontend/client/src/controllers/page.js +++ b/frontend/client/src/controllers/page.js @@ -20,12 +20,12 @@ ************************************************************************/ Espo.define('Controllers.Page', 'Controller', function (Dep) { - return Dep.extend({ - - view: function (options) { - var page = options.id; - this.main(null, {template: 'pages.' + Espo.Utils.convert(page, 'c-h')}); - - } - }); + return Dep.extend({ + + view: function (options) { + var page = options.id; + this.main(null, {template: 'pages.' + Espo.Utils.convert(page, 'c-h')}); + + } + }); }); diff --git a/frontend/client/src/controllers/preferences.js b/frontend/client/src/controllers/preferences.js index 6532bb9453..5e36dd44b0 100644 --- a/frontend/client/src/controllers/preferences.js +++ b/frontend/client/src/controllers/preferences.js @@ -20,30 +20,30 @@ ************************************************************************/ Espo.define('Controllers.Preferences', 'Controllers.Record', function (Dep) { - - return Dep.extend({ - - defaultAction: 'own', - - getModel: function (callback) { - var model = new Espo['Models.Preferences'](); - model.settings = this.getConfig(); - model.defs = this.getMetadata().get('entityDefs.Preferences'); - callback.call(this, model); - }, - - checkAccess: function (action) { - return true; - }, - - own: function () { - this.edit({ - id: this.getUser().id - }); - }, - - list: function () {}, - }); + + return Dep.extend({ + + defaultAction: 'own', + + getModel: function (callback) { + var model = new Espo['Models.Preferences'](); + model.settings = this.getConfig(); + model.defs = this.getMetadata().get('entityDefs.Preferences'); + callback.call(this, model); + }, + + checkAccess: function (action) { + return true; + }, + + own: function () { + this.edit({ + id: this.getUser().id + }); + }, + + list: function () {}, + }); }); diff --git a/frontend/client/src/controllers/record.js b/frontend/client/src/controllers/record.js index 86bcbb3360..898361957c 100644 --- a/frontend/client/src/controllers/record.js +++ b/frontend/client/src/controllers/record.js @@ -20,211 +20,211 @@ ************************************************************************/ Espo.define('Controllers.Record', 'Controller', function (Dep) { - return Dep.extend({ + return Dep.extend({ - viewMap: null, + viewMap: null, - defaultAction: 'list', - - checkAccess: function (action) { - if (this.getUser().isAdmin()) { - return true; - } - if (this.getAcl().check(this.name, action)) { - return true; - } - return false; - }, + defaultAction: 'list', + + checkAccess: function (action) { + if (this.getUser().isAdmin()) { + return true; + } + if (this.getAcl().check(this.name, action)) { + return true; + } + return false; + }, - initialize: function () { - this.viewMap = this.viewMap || {}; - this.viewsMap = this.viewsMap || {}; - }, + initialize: function () { + this.viewMap = this.viewMap || {}; + this.viewsMap = this.viewsMap || {}; + }, - getViewName: function (type) { - return this.viewMap[type] || this.getMetadata().get('clientDefs.' + this.name + '.views.' + type) || Espo.Utils.upperCaseFirst(type); - }, + getViewName: function (type) { + return this.viewMap[type] || this.getMetadata().get('clientDefs.' + this.name + '.views.' + type) || Espo.Utils.upperCaseFirst(type); + }, - getViews: function (type) { - var views = {}; - var recordView = this.getMetadata().get('clientDefs.' + this.name + '.recordViews.' + type); - if (recordView) { - if (!views.body) { - views.body = {}; - } - views.body.view = recordView; - } - return views; - }, - - beforeList: function () { - this.handleCheckAccess('read'); - }, + getViews: function (type) { + var views = {}; + var recordView = this.getMetadata().get('clientDefs.' + this.name + '.recordViews.' + type); + if (recordView) { + if (!views.body) { + views.body = {}; + } + views.body.view = recordView; + } + return views; + }, + + beforeList: function () { + this.handleCheckAccess('read'); + }, - list: function (options) { - this.getCollection(function (collection) { + list: function (options) { + this.getCollection(function (collection) { - this.main(this.getViewName('list'), { - scope: this.name, - collection: collection, - }); - }); - }, - - beforeView: function () { - this.handleCheckAccess('read'); - }, + this.main(this.getViewName('list'), { + scope: this.name, + collection: collection, + }); + }); + }, + + beforeView: function () { + this.handleCheckAccess('read'); + }, - view: function (options) { - var id = options.id; - - var createView = function (model) { - this.main(this.getViewName('detail'), { - scope: this.name, - model: model, - views: this.getViews('detail'), - }); - }.bind(this); - - if ('model' in options) { - var model = options.model; - createView(model); - - model.once('sync', function () { - this.hideLoadingNotification(); - }, this); - this.showLoadingNotification(); - model.fetch(); - } else { - this.getModel(function (model) { - model.id = id; - - this.showLoadingNotification(); - model.once('sync', function () { - createView(model); - }, this); - model.fetch({main: true}); - }); - } - }, - - beforeCreate: function () { - this.handleCheckAccess('edit'); - }, + view: function (options) { + var id = options.id; + + var createView = function (model) { + this.main(this.getViewName('detail'), { + scope: this.name, + model: model, + views: this.getViews('detail'), + }); + }.bind(this); + + if ('model' in options) { + var model = options.model; + createView(model); + + model.once('sync', function () { + this.hideLoadingNotification(); + }, this); + this.showLoadingNotification(); + model.fetch(); + } else { + this.getModel(function (model) { + model.id = id; + + this.showLoadingNotification(); + model.once('sync', function () { + createView(model); + }, this); + model.fetch({main: true}); + }); + } + }, + + beforeCreate: function () { + this.handleCheckAccess('edit'); + }, - create: function (options) { - options = options || {}; - this.getModel(function (model) { - model.populateDefaults(); - if (options.relate) { - model.setRelate(options.relate); - } - if (options.attributes) { - model.set(options.attributes) - } + create: function (options) { + options = options || {}; + this.getModel(function (model) { + model.populateDefaults(); + if (options.relate) { + model.setRelate(options.relate); + } + if (options.attributes) { + model.set(options.attributes) + } - this.main(this.getViewName('edit'), { - scope: this.name, - model: model, - returnUrl: options.returnUrl, - views: this.getViews('edit'), - }); - }); - }, - - beforeCreate: function () { - this.handleCheckAccess('edit'); - }, + this.main(this.getViewName('edit'), { + scope: this.name, + model: model, + returnUrl: options.returnUrl, + views: this.getViews('edit'), + }); + }); + }, + + beforeCreate: function () { + this.handleCheckAccess('edit'); + }, - edit: function (options) { - var id = options.id; + edit: function (options) { + var id = options.id; - this.getModel(function (model) { - model.id = id; - - this.showLoadingNotification(); - model.once('sync', function () { + this.getModel(function (model) { + model.id = id; + + this.showLoadingNotification(); + model.once('sync', function () { - if (options.attributes) { - model.set(options.attributes) - } - - this.main(this.getViewName('edit'), { - scope: this.name, - model: model, - returnUrl: options.returnUrl, - views: this.getViews('edit'), - }); - }, this); - model.fetch({main: true}); - }); - }, - - beforeMerge: function () { - this.handleCheckAccess('edit'); - }, + if (options.attributes) { + model.set(options.attributes) + } + + this.main(this.getViewName('edit'), { + scope: this.name, + model: model, + returnUrl: options.returnUrl, + views: this.getViews('edit'), + }); + }, this); + model.fetch({main: true}); + }); + }, + + beforeMerge: function () { + this.handleCheckAccess('edit'); + }, - merge: function (options) { - var ids = options.ids.split(','); + merge: function (options) { + var ids = options.ids.split(','); - this.getModel(function (model) { - var models = []; + this.getModel(function (model) { + var models = []; - var proceed = function () { - this.main('Merge', { - models: models, - scope: this.name - }); - }.bind(this); + var proceed = function () { + this.main('Merge', { + models: models, + scope: this.name + }); + }.bind(this); - var i = 0; - ids.forEach(function (id) { - var current = model.clone(); - current.id = id; - models.push(current); - current.once('sync', function () { - i++; - if (i == ids.length) { - proceed(); - } - }); - current.fetch(); - }.bind(this)); - }.bind(this)); - }, + var i = 0; + ids.forEach(function (id) { + var current = model.clone(); + current.id = id; + models.push(current); + current.once('sync', function () { + i++; + if (i == ids.length) { + proceed(); + } + }); + current.fetch(); + }.bind(this)); + }.bind(this)); + }, - /** - * Get collection for the current controller. - * @param {Espo.Collection}. - */ - getCollection: function (callback, context) { - context = context || this; - - if (!this.name) { - throw new Error('No collection for unnamed controller'); - } - var collectionName = this.name; - this.collectionFactory.create(collectionName, function (collection) { - callback.call(context, collection); - }, context); - }, + /** + * Get collection for the current controller. + * @param {Espo.Collection}. + */ + getCollection: function (callback, context) { + context = context || this; + + if (!this.name) { + throw new Error('No collection for unnamed controller'); + } + var collectionName = this.name; + this.collectionFactory.create(collectionName, function (collection) { + callback.call(context, collection); + }, context); + }, - /** - * Get model for the current controller. - * @param {Espo.Model}. - */ - getModel: function (callback, context) { - context = context || this; - - if (!this.name) { - throw new Error('No collection for unnamed controller'); - } - var modelName = this.name; - this.modelFactory.create(modelName, function (model) { - callback.call(context, model); - }, context); - }, - }); + /** + * Get model for the current controller. + * @param {Espo.Model}. + */ + getModel: function (callback, context) { + context = context || this; + + if (!this.name) { + throw new Error('No collection for unnamed controller'); + } + var modelName = this.name; + this.modelFactory.create(modelName, function (model) { + callback.call(context, model); + }, context); + }, + }); }); diff --git a/frontend/client/src/controllers/role.js b/frontend/client/src/controllers/role.js index caee4e6aeb..397d9004e2 100644 --- a/frontend/client/src/controllers/role.js +++ b/frontend/client/src/controllers/role.js @@ -19,16 +19,16 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ Espo.define('Controllers.Role', 'Controllers.Record', function (Dep) { - - return Dep.extend({ - - checkAccess: function () { - if (this.getUser().isAdmin()) { - return true; - } - return false; - }, + + return Dep.extend({ + + checkAccess: function () { + if (this.getUser().isAdmin()) { + return true; + } + return false; + }, - }); - + }); + }); diff --git a/frontend/client/src/controllers/team.js b/frontend/client/src/controllers/team.js index bba16575ed..5437461424 100644 --- a/frontend/client/src/controllers/team.js +++ b/frontend/client/src/controllers/team.js @@ -19,18 +19,18 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ Espo.define('Controllers.Team', 'Controllers.Record', function (Dep) { - - return Dep.extend({ - - checkAccess: function (action) { - if (action == 'read') { - return true; - } - if (this.getUser().isAdmin()) { - return true; - } - } - - }); + + return Dep.extend({ + + checkAccess: function (action) { + if (action == 'read') { + return true; + } + if (this.getUser().isAdmin()) { + return true; + } + } + + }); }); diff --git a/frontend/client/src/controllers/user.js b/frontend/client/src/controllers/user.js index fcff05529a..e415ebe1d8 100644 --- a/frontend/client/src/controllers/user.js +++ b/frontend/client/src/controllers/user.js @@ -20,8 +20,8 @@ ************************************************************************/ Espo.define('Controllers.User', 'Controllers.Record', function (Dep) { - - return Dep.extend({ + + return Dep.extend({ - }); + }); }); diff --git a/frontend/client/src/date-time.js b/frontend/client/src/date-time.js index 45a789194b..609000ec1a 100644 --- a/frontend/client/src/date-time.js +++ b/frontend/client/src/date-time.js @@ -25,161 +25,161 @@ Espo.DateTime = function () { _.extend(Espo.DateTime.prototype, { - internalDateFormat: 'YYYY-MM-DD', + internalDateFormat: 'YYYY-MM-DD', - internalDateTimeFormat: 'YYYY-MM-DD HH:mm', + internalDateTimeFormat: 'YYYY-MM-DD HH:mm', - dateFormat: 'MM/DD/YYYY', + dateFormat: 'MM/DD/YYYY', - timeFormat: 'HH:mm', + timeFormat: 'HH:mm', - timeZone: null, + timeZone: null, - weekStart: 1, + weekStart: 1, - hasMeridian: function () { - return (new RegExp('A', 'i')).test(this.timeFormat); - }, - - getDateFormat: function () { - return this.dateFormat; - }, + hasMeridian: function () { + return (new RegExp('A', 'i')).test(this.timeFormat); + }, + + getDateFormat: function () { + return this.dateFormat; + }, - getDateTimeFormat: function () { - return this.dateFormat + ' ' + this.timeFormat; - }, + getDateTimeFormat: function () { + return this.dateFormat + ' ' + this.timeFormat; + }, - fromDisplayDate: function (string) { - if (!string) { - return null; - } - var m = moment(string, this.dateFormat); - if (!m.isValid()) { - return -1; - } - return m.format(this.internalDateFormat); - }, + fromDisplayDate: function (string) { + if (!string) { + return null; + } + var m = moment(string, this.dateFormat); + if (!m.isValid()) { + return -1; + } + return m.format(this.internalDateFormat); + }, - toDisplayDate: function (string) { - if (!string || (typeof string != 'string')) { - return ''; - } - - var m = moment(string, this.internalDateFormat); - if (!m.isValid()) { - return ''; - } - - return m.format(this.dateFormat); - }, + toDisplayDate: function (string) { + if (!string || (typeof string != 'string')) { + return ''; + } + + var m = moment(string, this.internalDateFormat); + if (!m.isValid()) { + return ''; + } + + return m.format(this.dateFormat); + }, - fromDisplay: function (string) { - if (!string) { - return null; - } - var m; - if (this.timeZone) { - m = moment.tz(string, this.getDateTimeFormat(), this.timeZone).utc(); - } else { - m = moment.utc(string, this.getDateTimeFormat()); - } - - if (!m.isValid()) { - return -1; - } - return m.format(this.internalDateTimeFormat) + ':00'; - }, + fromDisplay: function (string) { + if (!string) { + return null; + } + var m; + if (this.timeZone) { + m = moment.tz(string, this.getDateTimeFormat(), this.timeZone).utc(); + } else { + m = moment.utc(string, this.getDateTimeFormat()); + } + + if (!m.isValid()) { + return -1; + } + return m.format(this.internalDateTimeFormat) + ':00'; + }, - toDisplay: function (string) { - if (!string) { - return ''; - } - return this.toMoment(string).format(this.getDateTimeFormat()); - }, - - getNowMoment: function () { - var m = moment(); - if (this.timeZone) { - m = m.tz(this.timeZone); - } - return m; - }, + toDisplay: function (string) { + if (!string) { + return ''; + } + return this.toMoment(string).format(this.getDateTimeFormat()); + }, + + getNowMoment: function () { + var m = moment(); + if (this.timeZone) { + m = m.tz(this.timeZone); + } + return m; + }, - toMoment: function (string) { - var m = moment.utc(string, this.internalDateTimeFormat); - if (this.timeZone) { - m = m.tz(this.timeZone); - } - return m; - }, + toMoment: function (string) { + var m = moment.utc(string, this.internalDateTimeFormat); + if (this.timeZone) { + m = m.tz(this.timeZone); + } + return m; + }, - fromIso: function (string) { - if (!string) { - return ''; - } - var m = moment(string).utc(); - return m.format(this.internalDateTimeFormat); - }, + fromIso: function (string) { + if (!string) { + return ''; + } + var m = moment(string).utc(); + return m.format(this.internalDateTimeFormat); + }, - toIso: function (string) { - if (!string) { - return null; - } - return this.toMoment(string).format(); - }, + toIso: function (string) { + if (!string) { + return null; + } + return this.toMoment(string).format(); + }, - getToday: function () { - return moment.utc().format(this.internalDateFormat); - }, + getToday: function () { + return moment.utc().format(this.internalDateFormat); + }, - getNow: function (multiplicity) { - if (!multiplicity) { - return moment.utc().format(this.internalDateTimeFormat); - } else { - var unix = moment().unix(); - unix = unix - (unix % (multiplicity * 60)); - return moment.unix(unix).utc().format(this.internalDateTimeFormat); - } - }, + getNow: function (multiplicity) { + if (!multiplicity) { + return moment.utc().format(this.internalDateTimeFormat); + } else { + var unix = moment().unix(); + unix = unix - (unix % (multiplicity * 60)); + return moment.unix(unix).utc().format(this.internalDateTimeFormat); + } + }, - setSettingsAndPreferences: function (settings, preferences) { - - if (settings.has('dateFormat')) { - this.dateFormat = settings.get('dateFormat'); - } - if (settings.has('timeFormat')) { - this.timeFormat = settings.get('timeFormat'); - } - if (settings.has('timeZone')) { - this.timeZone = settings.get('timeZone') || null; - if (this.timeZone == 'UTC') { - this.timeZone = null; - } - } - if (settings.has('weekStart')) { - this.weekStart = settings.get('weekStart'); - } - - preferences.on('change', function (model) { - this.dateFormat = model.get('dateFormat'); - this.timeFormat = model.get('timeFormat'); - this.timeZone = model.get('timeZone'); - this.weekStart = model.get('weekStart'); - if (this.timeZone == 'UTC') { - this.timeZone = null; - } - }, this); - }, - - setLanguage: function (language) { - moment.lang('en', { - months: language.translate('monthNames', 'lists'), - monthsShort: language.translate('monthNamesShort', 'lists'), - weekdays: language.translate('dayNames', 'lists'), - weekdaysShort: language.translate('dayNamesShort', 'lists'), - weekdaysMin: language.translate('dayNamesMin', 'lists'), - }); - moment.lang('en'); - }, + setSettingsAndPreferences: function (settings, preferences) { + + if (settings.has('dateFormat')) { + this.dateFormat = settings.get('dateFormat'); + } + if (settings.has('timeFormat')) { + this.timeFormat = settings.get('timeFormat'); + } + if (settings.has('timeZone')) { + this.timeZone = settings.get('timeZone') || null; + if (this.timeZone == 'UTC') { + this.timeZone = null; + } + } + if (settings.has('weekStart')) { + this.weekStart = settings.get('weekStart'); + } + + preferences.on('change', function (model) { + this.dateFormat = model.get('dateFormat'); + this.timeFormat = model.get('timeFormat'); + this.timeZone = model.get('timeZone'); + this.weekStart = model.get('weekStart'); + if (this.timeZone == 'UTC') { + this.timeZone = null; + } + }, this); + }, + + setLanguage: function (language) { + moment.lang('en', { + months: language.translate('monthNames', 'lists'), + monthsShort: language.translate('monthNamesShort', 'lists'), + weekdays: language.translate('dayNames', 'lists'), + weekdaysShort: language.translate('dayNamesShort', 'lists'), + weekdaysMin: language.translate('dayNamesMin', 'lists'), + }); + moment.lang('en'); + }, }); diff --git a/frontend/client/src/exceptions.js b/frontend/client/src/exceptions.js index 7d1b6b4cc8..e30b2538f1 100644 --- a/frontend/client/src/exceptions.js +++ b/frontend/client/src/exceptions.js @@ -22,15 +22,15 @@ Espo.Exceptions = Espo.Exceptions || {}; Espo.Exceptions.AccessDenied = function (message) { - this.message = message; - Error.apply(this, arguments); + this.message = message; + Error.apply(this, arguments); } Espo.Exceptions.AccessDenied.prototype = new Error(); -Espo.Exceptions.AccessDenied.prototype.name = 'AccessDenied'; +Espo.Exceptions.AccessDenied.prototype.name = 'AccessDenied'; Espo.Exceptions.NotFound = function (message) { - this.message = message; - Error.apply(this, arguments); + this.message = message; + Error.apply(this, arguments); } Espo.Exceptions.NotFound.prototype = new Error(); Espo.Exceptions.NotFound.prototype.name = 'NotFound'; diff --git a/frontend/client/src/field-manager.js b/frontend/client/src/field-manager.js index d000e1f702..2356ab901f 100644 --- a/frontend/client/src/field-manager.js +++ b/frontend/client/src/field-manager.js @@ -20,121 +20,121 @@ ************************************************************************/ Espo.FieldManager = function (defs, metadata) { - this.defs = defs; - this.metadata = metadata; + this.defs = defs; + this.metadata = metadata; }; _.extend(Espo.FieldManager.prototype, { - defs: null, - - metadata: null, + defs: null, + + metadata: null, - getParams: function (fieldType) { - if (fieldType in this.defs) { - return this.defs[fieldType].params || []; - } - return []; - }, - - checkFilter: function (fieldType) { - if (fieldType in this.defs) { - if ('filter' in this.defs[fieldType]) { - return this.defs[fieldType].filter; - } else { - return false; - } - } - return false; - }, - - isMergable: function (fieldType) { - if (fieldType in this.defs) { - if ('mergable' in this.defs[fieldType]) { - return this.defs[fieldType].mergable; - } else { - return true; - } - } - return false; - }, - - getEntityAttributes: function (entityName) { - var list = []; - - var defs = this.metadata.get('entityDefs.' + entityName + '.fields') || {}; - Object.keys(defs).forEach(function (field) { - this.getAttributes(defs[field]['type'], field).forEach(function (attr) { - if (!~list.indexOf(attr)) { - list.push(attr); - } - }); - }, this); - return list; - }, + getParams: function (fieldType) { + if (fieldType in this.defs) { + return this.defs[fieldType].params || []; + } + return []; + }, + + checkFilter: function (fieldType) { + if (fieldType in this.defs) { + if ('filter' in this.defs[fieldType]) { + return this.defs[fieldType].filter; + } else { + return false; + } + } + return false; + }, + + isMergable: function (fieldType) { + if (fieldType in this.defs) { + if ('mergable' in this.defs[fieldType]) { + return this.defs[fieldType].mergable; + } else { + return true; + } + } + return false; + }, + + getEntityAttributes: function (entityName) { + var list = []; + + var defs = this.metadata.get('entityDefs.' + entityName + '.fields') || {}; + Object.keys(defs).forEach(function (field) { + this.getAttributes(defs[field]['type'], field).forEach(function (attr) { + if (!~list.indexOf(attr)) { + list.push(attr); + } + }); + }, this); + return list; + }, - getActualAttributes: function (fieldType, fieldName) { - var fieldNames = []; - if (fieldType in this.defs) { - if ('actualFields' in this.defs[fieldType]) { - var actualfFields = this.defs[fieldType].actualFields; + getActualAttributes: function (fieldType, fieldName) { + var fieldNames = []; + if (fieldType in this.defs) { + if ('actualFields' in this.defs[fieldType]) { + var actualfFields = this.defs[fieldType].actualFields; - var naming = 'suffix'; - if ('naming' in this.defs[fieldType]) { - naming = this.defs[fieldType].naming; - } - if (naming == 'prefix') { - actualfFields.forEach(function (f) { - fieldNames.push(f + Espo.Utils.upperCaseFirst(fieldName)); - }); - } else { - actualfFields.forEach(function (f) { - fieldNames.push(fieldName + Espo.Utils.upperCaseFirst(f)); - }); - } - } else { - fieldNames.push(fieldName); - } - } - return fieldNames; - }, + var naming = 'suffix'; + if ('naming' in this.defs[fieldType]) { + naming = this.defs[fieldType].naming; + } + if (naming == 'prefix') { + actualfFields.forEach(function (f) { + fieldNames.push(f + Espo.Utils.upperCaseFirst(fieldName)); + }); + } else { + actualfFields.forEach(function (f) { + fieldNames.push(fieldName + Espo.Utils.upperCaseFirst(f)); + }); + } + } else { + fieldNames.push(fieldName); + } + } + return fieldNames; + }, - getNotActualAttributes: function (fieldType, fieldName) { - var fieldNames = []; - if (fieldType in this.defs) { - if ('notActualFields' in this.defs[fieldType]) { - var notActualFields = this.defs[fieldType].notActualFields; + getNotActualAttributes: function (fieldType, fieldName) { + var fieldNames = []; + if (fieldType in this.defs) { + if ('notActualFields' in this.defs[fieldType]) { + var notActualFields = this.defs[fieldType].notActualFields; - var naming = 'suffix'; - if ('naming' in this.defs[fieldType]) { - naming = this.defs[fieldType].naming; - } - if (naming == 'prefix') { - notActualFields.forEach(function (f) { - fieldNames.push(f + Espo.Utils.upperCaseFirst(fieldName)); - }); - } else { - notActualFields.forEach(function (f) { - fieldNames.push(fieldName + Espo.Utils.upperCaseFirst(f)); - }); - } - } - } - return fieldNames; - }, + var naming = 'suffix'; + if ('naming' in this.defs[fieldType]) { + naming = this.defs[fieldType].naming; + } + if (naming == 'prefix') { + notActualFields.forEach(function (f) { + fieldNames.push(f + Espo.Utils.upperCaseFirst(fieldName)); + }); + } else { + notActualFields.forEach(function (f) { + fieldNames.push(fieldName + Espo.Utils.upperCaseFirst(f)); + }); + } + } + } + return fieldNames; + }, - getAttributes: function (fieldType, fieldName) { - return _.union(this.getActualAttributes(fieldType, fieldName), this.getNotActualAttributes(fieldType, fieldName)); - }, + getAttributes: function (fieldType, fieldName) { + return _.union(this.getActualAttributes(fieldType, fieldName), this.getNotActualAttributes(fieldType, fieldName)); + }, - getViewName: function (fieldType) { - if (fieldType in this.defs) { - if ('view' in this.defs[fieldType]) { - return this.defs[fieldType].view; - } - } - return 'Fields.' + Espo.Utils.upperCaseFirst(fieldType); - }, + getViewName: function (fieldType) { + if (fieldType in this.defs) { + if ('view' in this.defs[fieldType]) { + return this.defs[fieldType].view; + } + } + return 'Fields.' + Espo.Utils.upperCaseFirst(fieldType); + }, }); diff --git a/frontend/client/src/language.js b/frontend/client/src/language.js index b571c3606f..078a9e7592 100644 --- a/frontend/client/src/language.js +++ b/frontend/client/src/language.js @@ -20,109 +20,109 @@ ************************************************************************/ Espo.Language = function (cache) { - this.cache = cache || null; - this.data = {}; + this.cache = cache || null; + this.data = {}; }; _.extend(Espo.Language.prototype, { - data: null, + data: null, - cache: null, - - url: 'I18n', - - has: function (name, category, scope) { - if (scope in this.data) { - if (category in this.data[scope]) { - if (name in this.data[scope][category]) { - return true; - } - } - } - }, + cache: null, + + url: 'I18n', + + has: function (name, category, scope) { + if (scope in this.data) { + if (category in this.data[scope]) { + if (name in this.data[scope][category]) { + return true; + } + } + } + }, - get: function (scope, category, name) { - if (scope in this.data) { - if (category in this.data[scope]) { - if (name in this.data[scope][category]) { - return this.data[scope][category][name]; - } - } - } - if (scope == 'Global') { - return name; - } - return false; - }, + get: function (scope, category, name) { + if (scope in this.data) { + if (category in this.data[scope]) { + if (name in this.data[scope][category]) { + return this.data[scope][category][name]; + } + } + } + if (scope == 'Global') { + return name; + } + return false; + }, - translate: function (name, category, scope) { - scope = scope || 'Global'; - category = category || 'labels'; - var res = this.get(scope, category, name); - if (res === false && scope != 'Global') { - res = this.get('Global', category, name); - } - return res; - }, - - translateOption: function (value, field, scope) { - var translation = this.translate(field, 'options', scope); - if (typeof translation != 'object') { - translation = {}; - } - return translation[value] || value; - }, - - loadFromCache: function () { - - if (this.cache) { - var cached = this.cache.get('app', 'language'); - if (cached) { - this.data = cached; - return true; - } - } - return null; - }, - - clearCache: function () { - if (this.cache) { - this.cache.clear('app', 'language'); - } - }, - - storeToCache: function () { - if (this.cache) { - this.cache.set('app', 'language', this.data); - } - }, - - load: function (callback, sync) { - var sync = (typeof sync == 'undefined') ? true: sync; - this.once('sync', callback); - if (!this.loadFromCache()) { - this.fetch(sync); - return; - } - this.trigger('sync'); - }, + translate: function (name, category, scope) { + scope = scope || 'Global'; + category = category || 'labels'; + var res = this.get(scope, category, name); + if (res === false && scope != 'Global') { + res = this.get('Global', category, name); + } + return res; + }, + + translateOption: function (value, field, scope) { + var translation = this.translate(field, 'options', scope); + if (typeof translation != 'object') { + translation = {}; + } + return translation[value] || value; + }, + + loadFromCache: function () { + + if (this.cache) { + var cached = this.cache.get('app', 'language'); + if (cached) { + this.data = cached; + return true; + } + } + return null; + }, + + clearCache: function () { + if (this.cache) { + this.cache.clear('app', 'language'); + } + }, + + storeToCache: function () { + if (this.cache) { + this.cache.set('app', 'language', this.data); + } + }, + + load: function (callback, sync) { + var sync = (typeof sync == 'undefined') ? true: sync; + this.once('sync', callback); + if (!this.loadFromCache()) { + this.fetch(sync); + return; + } + this.trigger('sync'); + }, - fetch: function (sync) { - var self = this; - $.ajax({ - url: this.url, - type: 'GET', - dataType: 'JSON', - async: !(sync || false), - success: function (data) { - self.data = data; - self.storeToCache(); - self.trigger('sync'); - } - }); - }, - + fetch: function (sync) { + var self = this; + $.ajax({ + url: this.url, + type: 'GET', + dataType: 'JSON', + async: !(sync || false), + success: function (data) { + self.data = data; + self.storeToCache(); + self.trigger('sync'); + } + }); + }, + }, Backbone.Events); diff --git a/frontend/client/src/layout-manager.js b/frontend/client/src/layout-manager.js index 95233c92af..95b8ff95c5 100644 --- a/frontend/client/src/layout-manager.js +++ b/frontend/client/src/layout-manager.js @@ -20,92 +20,92 @@ ************************************************************************/ Espo.LayoutManager = function (options) { - var options = options || {}; - this.cache = options.cache || null; - this.data = {}; - this.ajax = $.ajax; + var options = options || {}; + this.cache = options.cache || null; + this.data = {}; + this.ajax = $.ajax; } _.extend(Espo.LayoutManager.prototype, { - cache: null, - - data: null, - - _getKey: function (controller, type) { - return controller + '-' + type; - }, - - _getUrl: function (controller, type) { - return controller + '/layout/' + type; - }, + cache: null, + + data: null, + + _getKey: function (controller, type) { + return controller + '-' + type; + }, + + _getUrl: function (controller, type) { + return controller + '/layout/' + type; + }, - get: function (controller, type, callback, cache) { - if (typeof cache == 'undefined') { - cache = true; - } - - var key = this._getKey(controller, type); - - if (cache) { - if (key in this.data) { - if (typeof callback === 'function') { - callback(this.data[key]); - } - return; - } - } - - if (this.cache !== null && cache) { - var cached = this.cache.get('app-layout', key); - if (cached) { - if (typeof callback === 'function') { - callback(cached); - } - this.data[key] = cached; - return; - } - } + get: function (controller, type, callback, cache) { + if (typeof cache == 'undefined') { + cache = true; + } + + var key = this._getKey(controller, type); + + if (cache) { + if (key in this.data) { + if (typeof callback === 'function') { + callback(this.data[key]); + } + return; + } + } + + if (this.cache !== null && cache) { + var cached = this.cache.get('app-layout', key); + if (cached) { + if (typeof callback === 'function') { + callback(cached); + } + this.data[key] = cached; + return; + } + } - this.ajax({ - url: this._getUrl(controller, type), - type: 'GET', - dataType: 'json', - success: function (layout) { - if (typeof callback === 'function') { - callback(layout); - } - this.data[key] = layout; - if (this.cache !== null) { - this.cache.set('app-layout', key, layout); - } - }.bind(this), - /*error: function () { - console.error('Could not load layout ' + controller + '#' + type); - },*/ - }); - }, - - set: function (controller, type, layout, callback) { - var key = this._getKey(controller, type); + this.ajax({ + url: this._getUrl(controller, type), + type: 'GET', + dataType: 'json', + success: function (layout) { + if (typeof callback === 'function') { + callback(layout); + } + this.data[key] = layout; + if (this.cache !== null) { + this.cache.set('app-layout', key, layout); + } + }.bind(this), + /*error: function () { + console.error('Could not load layout ' + controller + '#' + type); + },*/ + }); + }, + + set: function (controller, type, layout, callback) { + var key = this._getKey(controller, type); - this.ajax({ - url: this._getUrl(controller, type), - type: 'PUT', - data: JSON.stringify(layout), - success: function () { - if (this.cache !== null) { - this.cache.set('app-layout', key, layout); - } - this.data[key] = layout; - this.trigger('sync'); - if (typeof callback === 'function') { - callback(); - } - }.bind(this) - }); - }, - + this.ajax({ + url: this._getUrl(controller, type), + type: 'PUT', + data: JSON.stringify(layout), + success: function () { + if (this.cache !== null) { + this.cache.set('app-layout', key, layout); + } + this.data[key] = layout; + this.trigger('sync'); + if (typeof callback === 'function') { + callback(); + } + }.bind(this) + }); + }, + }, Backbone.Events); diff --git a/frontend/client/src/loader.js b/frontend/client/src/loader.js index 39a225f2bf..495ce54bbe 100644 --- a/frontend/client/src/loader.js +++ b/frontend/client/src/loader.js @@ -21,321 +21,321 @@ (function (Espo, _, $) { - var root = this; + var root = this; - Espo.Loader = function (cache) { - this.cache = cache || null; - this._loadCallbacks = {}; - - this.pathsBeingLoaded = {}; - - this.libsConfig = {}; - } + Espo.Loader = function (cache) { + this.cache = cache || null; + this._loadCallbacks = {}; + + this.pathsBeingLoaded = {}; + + this.libsConfig = {}; + } - _.extend(Espo.Loader.prototype, { + _.extend(Espo.Loader.prototype, { - cache: null, + cache: null, - data: null, + data: null, - godClass: Espo, + godClass: Espo, - _loadCallbacks: null, - - libsConfigUrl: 'client/cfg/libs.json', + _loadCallbacks: null, + + libsConfigUrl: 'client/cfg/libs.json', - _getClass: function (name) { - if (name in this.godClass) { - return this.godClass[name]; - } - return false; - }, + _getClass: function (name) { + if (name in this.godClass) { + return this.godClass[name]; + } + return false; + }, - _setClass: function (name, o) { - this.godClass[name] = o; - }, + _setClass: function (name, o) { + this.godClass[name] = o; + }, - _nameToPath: function (name) { - var path; - if (name.indexOf(':') != -1) { - var arr = name.split(':'); - var name = arr[1]; - var mod = arr[0]; - if (mod == 'Custom') { - path = 'client/custom/src/' + Espo.Utils.convert(name, 'C-h').split('.').join('/'); - } else { - path = 'client/modules/' + Espo.Utils.convert(mod, 'C-h') + '/src/' + Espo.Utils.convert(name, 'C-h').split('.').join('/'); - } - } else { - path = 'client/src/' + Espo.Utils.convert(name, 'C-h').split('.').join('/'); - } - path += '.js'; - return path; - }, + _nameToPath: function (name) { + var path; + if (name.indexOf(':') != -1) { + var arr = name.split(':'); + var name = arr[1]; + var mod = arr[0]; + if (mod == 'Custom') { + path = 'client/custom/src/' + Espo.Utils.convert(name, 'C-h').split('.').join('/'); + } else { + path = 'client/modules/' + Espo.Utils.convert(mod, 'C-h') + '/src/' + Espo.Utils.convert(name, 'C-h').split('.').join('/'); + } + } else { + path = 'client/src/' + Espo.Utils.convert(name, 'C-h').split('.').join('/'); + } + path += '.js'; + return path; + }, - _execute: function (script) { - eval.call(root, script); - }, + _execute: function (script) { + eval.call(root, script); + }, - _executeLoadCallback: function (subject, o) { - if (subject in this._loadCallbacks) { - this._loadCallbacks[subject].forEach(function (callback) { - callback(o); - }); - delete this._loadCallbacks[subject]; - } - }, + _executeLoadCallback: function (subject, o) { + if (subject in this._loadCallbacks) { + this._loadCallbacks[subject].forEach(function (callback) { + callback(o); + }); + delete this._loadCallbacks[subject]; + } + }, - define: function (subject, dependency, callback) { - var self = this; - var proceed = function (relObj) { - var o = callback.apply(this, arguments); - if (!o) { - if (self.cache) { - self.cache.clear('script', name); - } - throw new Error("Could not load '" + subject + "'"); - } - self._setClass(subject, o); - self._executeLoadCallback(subject, o); - }; + define: function (subject, dependency, callback) { + var self = this; + var proceed = function (relObj) { + var o = callback.apply(this, arguments); + if (!o) { + if (self.cache) { + self.cache.clear('script', name); + } + throw new Error("Could not load '" + subject + "'"); + } + self._setClass(subject, o); + self._executeLoadCallback(subject, o); + }; - if (!dependency) { - proceed(); - } else { - this.require(dependency, function () { - proceed.apply(this, arguments); - }); - } - }, + if (!dependency) { + proceed(); + } else { + this.require(dependency, function () { + proceed.apply(this, arguments); + }); + } + }, - require: function (subject, callback) { - if (Object.prototype.toString.call(subject) === '[object Array]') { - var list = subject; - } else { - this.load(subject, callback); - return; - } - var totalCount = list.length; - var readyCount = 0; - var loaded = {}; + require: function (subject, callback) { + if (Object.prototype.toString.call(subject) === '[object Array]') { + var list = subject; + } else { + this.load(subject, callback); + return; + } + var totalCount = list.length; + var readyCount = 0; + var loaded = {}; - list.forEach(function (name) { - this.load(name, function (c) { - loaded[name] = c; - readyCount++; - if (readyCount == totalCount) { - var args = []; - for (var i in list) { - args.push(loaded[list[i]]); - } - callback.apply(this, args); - } - }); - }.bind(this)); - }, - - _addLoadCallback: function (name, callback) { - if (!(name in this._loadCallbacks)) { - this._loadCallbacks[name] = []; - } - this._loadCallbacks[name].push(callback); - }, - - dataLoaded: {}, - - load: function (name, callback, error) { - var dataType, type, path, fetchObject; - var realName = name; - - if (name.indexOf('lib!') === 0) { - dataType = 'script'; - type = 'lib'; - - realName = name.substr(4); - path = realName; - - var exportsTo = 'window'; - var exportsAs = realName; - - if (realName in this.libsConfig) { - path = this.libsConfig[realName].path || path; - exportsTo = this.libsConfig[realName].exportsTo || exportsTo; - exportsAs = this.libsConfig[realName].exportsAs || exportsAs; - } - - fetchObject = function (name, d) { - var from = root; - if (exportsTo == 'window') { - from = root; - } else { - exportsTo.split('.').forEach(function (item) { - from = from[item]; - }); - } - if (exportsAs in from) { - return from[exportsAs]; - } - } - - } else if (name.indexOf('res!') === 0) { - dataType = 'text'; - type = 'res'; - - realName = name.substr(4); - path = realName; - } else { - dataType = 'script'; - type = 'class'; - - if (!name || name == '') { - throw new Error("Can not load empty class name"); - } + list.forEach(function (name) { + this.load(name, function (c) { + loaded[name] = c; + readyCount++; + if (readyCount == totalCount) { + var args = []; + for (var i in list) { + args.push(loaded[list[i]]); + } + callback.apply(this, args); + } + }); + }.bind(this)); + }, + + _addLoadCallback: function (name, callback) { + if (!(name in this._loadCallbacks)) { + this._loadCallbacks[name] = []; + } + this._loadCallbacks[name].push(callback); + }, + + dataLoaded: {}, + + load: function (name, callback, error) { + var dataType, type, path, fetchObject; + var realName = name; + + if (name.indexOf('lib!') === 0) { + dataType = 'script'; + type = 'lib'; + + realName = name.substr(4); + path = realName; + + var exportsTo = 'window'; + var exportsAs = realName; + + if (realName in this.libsConfig) { + path = this.libsConfig[realName].path || path; + exportsTo = this.libsConfig[realName].exportsTo || exportsTo; + exportsAs = this.libsConfig[realName].exportsAs || exportsAs; + } + + fetchObject = function (name, d) { + var from = root; + if (exportsTo == 'window') { + from = root; + } else { + exportsTo.split('.').forEach(function (item) { + from = from[item]; + }); + } + if (exportsAs in from) { + return from[exportsAs]; + } + } + + } else if (name.indexOf('res!') === 0) { + dataType = 'text'; + type = 'res'; + + realName = name.substr(4); + path = realName; + } else { + dataType = 'script'; + type = 'class'; + + if (!name || name == '') { + throw new Error("Can not load empty class name"); + } - var c = this._getClass(name); - if (c) { - callback(c); - return; - } + var c = this._getClass(name); + if (c) { + callback(c); + return; + } - path = this._nameToPath(name); - } - - if (name in this.dataLoaded) { - callback(this.dataLoaded[name]); - return; - } - - if (this.cache) { - var cached = this.cache.get(type, name); - if (cached) { - if (dataType == 'script') { - this._execute(cached); - } - if (type == 'class') { - var c = this._getClass(name); - if (c) { - callback(c); - return; - } - this._addLoadCallback(name, callback); - } else { - var d = cached; - if (typeof fetchObject == 'function') { - d = fetchObject(realName, cached); - } - this.dataLoaded[name] = d; - callback(d); - } - - return; - } - } - - if (path in this.pathsBeingLoaded) { - this._addLoadCallback(name, callback); - return; - } - this.pathsBeingLoaded[path] = true; + path = this._nameToPath(name); + } + + if (name in this.dataLoaded) { + callback(this.dataLoaded[name]); + return; + } + + if (this.cache) { + var cached = this.cache.get(type, name); + if (cached) { + if (dataType == 'script') { + this._execute(cached); + } + if (type == 'class') { + var c = this._getClass(name); + if (c) { + callback(c); + return; + } + this._addLoadCallback(name, callback); + } else { + var d = cached; + if (typeof fetchObject == 'function') { + d = fetchObject(realName, cached); + } + this.dataLoaded[name] = d; + callback(d); + } + + return; + } + } + + if (path in this.pathsBeingLoaded) { + this._addLoadCallback(name, callback); + return; + } + this.pathsBeingLoaded[path] = true; - $.ajax({ - type: 'GET', - cache: false, - dataType: dataType, - local: true, - url: path, - success: function (response) { - if (this.cache) { - this.cache.set(type, name, response); - } + $.ajax({ + type: 'GET', + cache: false, + dataType: dataType, + local: true, + url: path, + success: function (response) { + if (this.cache) { + this.cache.set(type, name, response); + } - this._addLoadCallback(name, callback); - - if (dataType == 'script') { - this._execute(response); - } - - if (type == 'class') { - // TODO remove this and use define for all classes - var c = this._getClass(name); - if (c && typeof c === 'function') { - this._executeLoadCallback(name, c); - } - } else { - var d = response; - if (typeof fetchObject == 'function') { - d = fetchObject(realName, response); - } - this.dataLoaded[name] = d; - this._executeLoadCallback(name, d); - } - return; - }.bind(this), - error: function () { - if (typeof error == 'function') { - error(); - } - throw new Error("Could not load file '" + path + "'"); - } - }); - }, - - - loadLib: function (url, callback) { - if (this.cache) { - var script = this.cache.get('script', url); - if (script) { - this._execute(script); - if (typeof callback == 'function') { - callback(); - } - return; - } - } - - $.ajax({ - url: url, - type: 'GET', - dataType: 'script', - local: true, - success: function () { - if (typeof callback == 'function') { - callback(); - } - }, - error: function () { - throw new Error("Could not load file '" + url + "'"); - }, - }); - - }, - - loadLibsConfig: function (callback) { - $.ajax({ - url: this.libsConfigUrl, - dataType: 'json', - local: true, - success: function (data) { - this.libsConfig = data; - callback(); - }.bind(this) - }); - }, - - addLibsConfig: function (data) { - this.libsConfig = _.extend(this.libsConfig, data); - }, - }); + this._addLoadCallback(name, callback); + + if (dataType == 'script') { + this._execute(response); + } + + if (type == 'class') { + // TODO remove this and use define for all classes + var c = this._getClass(name); + if (c && typeof c === 'function') { + this._executeLoadCallback(name, c); + } + } else { + var d = response; + if (typeof fetchObject == 'function') { + d = fetchObject(realName, response); + } + this.dataLoaded[name] = d; + this._executeLoadCallback(name, d); + } + return; + }.bind(this), + error: function () { + if (typeof error == 'function') { + error(); + } + throw new Error("Could not load file '" + path + "'"); + } + }); + }, + + + loadLib: function (url, callback) { + if (this.cache) { + var script = this.cache.get('script', url); + if (script) { + this._execute(script); + if (typeof callback == 'function') { + callback(); + } + return; + } + } + + $.ajax({ + url: url, + type: 'GET', + dataType: 'script', + local: true, + success: function () { + if (typeof callback == 'function') { + callback(); + } + }, + error: function () { + throw new Error("Could not load file '" + url + "'"); + }, + }); + + }, + + loadLibsConfig: function (callback) { + $.ajax({ + url: this.libsConfigUrl, + dataType: 'json', + local: true, + success: function (data) { + this.libsConfig = data; + callback(); + }.bind(this) + }); + }, + + addLibsConfig: function (data) { + this.libsConfig = _.extend(this.libsConfig, data); + }, + }); - Espo.loader = new Espo.Loader(); - Espo.require = function (subject, callback) { - Espo.loader.require(subject, callback); - } - Espo.define = function (subject, dependency, callback) { - Espo.loader.define(subject, dependency, callback); - } - Espo.loadLib = function (url, callback) { - Espo.loader.loadLib(url, callback); - } + Espo.loader = new Espo.Loader(); + Espo.require = function (subject, callback) { + Espo.loader.require(subject, callback); + } + Espo.define = function (subject, dependency, callback) { + Espo.loader.define(subject, dependency, callback); + } + Espo.loadLib = function (url, callback) { + Espo.loader.loadLib(url, callback); + } }).call(this, Espo, _, $); diff --git a/frontend/client/src/metadata.js b/frontend/client/src/metadata.js index ba64fa69b0..ca6537c61e 100644 --- a/frontend/client/src/metadata.js +++ b/frontend/client/src/metadata.js @@ -20,83 +20,83 @@ ************************************************************************/ (function (Espo, _, $, Backbone) { - Espo.Metadata = function (cache) { - this.cache = cache || null; + Espo.Metadata = function (cache) { + this.cache = cache || null; - this.data = {}; - this.ajax = $.ajax; - } + this.data = {}; + this.ajax = $.ajax; + } - _.extend(Espo.Metadata.prototype, { + _.extend(Espo.Metadata.prototype, { - cache: null, + cache: null, - data: null, + data: null, - url: 'Metadata', + url: 'Metadata', - load: function (callback, sync) { - var sync = (typeof sync == 'undefined') ? false: sync; - this.off('sync'); - this.once('sync', callback); - if (!this.loadFromCache()) { - this.fetch(sync); - return; - } - this.trigger('sync'); - }, + load: function (callback, sync) { + var sync = (typeof sync == 'undefined') ? false: sync; + this.off('sync'); + this.once('sync', callback); + if (!this.loadFromCache()) { + this.fetch(sync); + return; + } + this.trigger('sync'); + }, - fetch: function (sync) { - var self = this; - this.ajax({ - url: this.url, - type: 'GET', - dataType: 'JSON', - async: !(sync || false), - success: function (data) { - self.data = data; - self.storeToCache(); - self.trigger('sync'); - } - }); - }, + fetch: function (sync) { + var self = this; + this.ajax({ + url: this.url, + type: 'GET', + dataType: 'JSON', + async: !(sync || false), + success: function (data) { + self.data = data; + self.storeToCache(); + self.trigger('sync'); + } + }); + }, - get: function (path, defaultValue) { - defaultValue = defaultValue || null; + get: function (path, defaultValue) { + defaultValue = defaultValue || null; - var pointer = this.data; - var arr = path.split('.'); - var result = defaultValue; - arr.forEach(function (key, i) { - if (!(key in pointer)) { - result = defaultValue; - return; - } - if (arr.length - 1 == i) { - result = pointer[key]; - } - pointer = pointer[key]; - }); - return result; - }, + var pointer = this.data; + var arr = path.split('.'); + var result = defaultValue; + arr.forEach(function (key, i) { + if (!(key in pointer)) { + result = defaultValue; + return; + } + if (arr.length - 1 == i) { + result = pointer[key]; + } + pointer = pointer[key]; + }); + return result; + }, - loadFromCache: function () { - if (this.cache) { - var cached = this.cache.get('app', 'metadata'); - if (cached) { - this.data = cached; - return true; - } - } - return null; - }, + loadFromCache: function () { + if (this.cache) { + var cached = this.cache.get('app', 'metadata'); + if (cached) { + this.data = cached; + return true; + } + } + return null; + }, - storeToCache: function () { - if (this.cache) { - this.cache.set('app', 'metadata', this.data); - } - }, + storeToCache: function () { + if (this.cache) { + this.cache.set('app', 'metadata', this.data); + } + }, - }, Backbone.Events); + }, Backbone.Events); }).call(this, Espo, _, $, Backbone); diff --git a/frontend/client/src/model-factory.js b/frontend/client/src/model-factory.js index c1669266e1..f14dd0d23a 100644 --- a/frontend/client/src/model-factory.js +++ b/frontend/client/src/model-factory.js @@ -19,53 +19,53 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ (function (Espo, _) { - - Espo.ModelFactory = function (loader, metadata, user) { - this.loader = loader; - this.metadata = metadata; - this.user = user; - - this.seeds = {}; - }; - - _.extend(Espo.ModelFactory.prototype, { - - loader: null, - - metadata: null, - - seeds: null, - - dateTime: null, - - user: null, - - create: function (name, callback, context) { - context = context || this; - this.getSeed(name, function (seed) { - var model = new seed(); - callback.call(context, model); - }.bind(this)); - }, - - getSeed: function (name, callback) { - if ('name' in this.seeds) { - callback(this.seeds[name]); - return; - } - - var className = this.metadata.get('clientDefs.' + name + '.model') || 'Model'; - - Espo.loader.load(className, function (modelClass) { - this.seeds[name] = modelClass.extend({ - name: name, - defs: this.metadata.get('entityDefs.' + name, {}), - dateTime: this.dateTime, - _user: this.user - }); - callback(this.seeds[name]); - }.bind(this)); - }, - }); - + + Espo.ModelFactory = function (loader, metadata, user) { + this.loader = loader; + this.metadata = metadata; + this.user = user; + + this.seeds = {}; + }; + + _.extend(Espo.ModelFactory.prototype, { + + loader: null, + + metadata: null, + + seeds: null, + + dateTime: null, + + user: null, + + create: function (name, callback, context) { + context = context || this; + this.getSeed(name, function (seed) { + var model = new seed(); + callback.call(context, model); + }.bind(this)); + }, + + getSeed: function (name, callback) { + if ('name' in this.seeds) { + callback(this.seeds[name]); + return; + } + + var className = this.metadata.get('clientDefs.' + name + '.model') || 'Model'; + + Espo.loader.load(className, function (modelClass) { + this.seeds[name] = modelClass.extend({ + name: name, + defs: this.metadata.get('entityDefs.' + name, {}), + dateTime: this.dateTime, + _user: this.user + }); + callback(this.seeds[name]); + }.bind(this)); + }, + }); + }).call(this, Espo, _); diff --git a/frontend/client/src/model-offline.js b/frontend/client/src/model-offline.js index 5420d35976..411c086c16 100644 --- a/frontend/client/src/model-offline.js +++ b/frontend/client/src/model-offline.js @@ -21,49 +21,49 @@ Espo.ModelOffline = Espo.Model.extend({ - name: null, + name: null, - cache: null, + cache: null, - _key: null, + _key: null, - initialize: function (attributes, options) { - options = options || {}; - Espo.Model.prototype.initialize.apply(this, arguments); - this._key = this.url = this.name; - this.cache = options.cache || null; - }, + initialize: function (attributes, options) { + options = options || {}; + Espo.Model.prototype.initialize.apply(this, arguments); + this._key = this.url = this.name; + this.cache = options.cache || null; + }, - load: function (sync) { - this.once('sync', function (model) { - model.storeToCache(); - }); + load: function (sync) { + this.once('sync', function (model) { + model.storeToCache(); + }); - this.fetch({ - async: !(sync || false) - }); - }, + this.fetch({ + async: !(sync || false) + }); + }, - loadFromCache: function () { - if (this.cache) { - var cached = this.cache.get('app', this._key); - if (cached) { - this.set(cached); - return true; - } - } - return null; - }, + loadFromCache: function () { + if (this.cache) { + var cached = this.cache.get('app', this._key); + if (cached) { + this.set(cached); + return true; + } + } + return null; + }, - storeToCache: function () { - if (this.cache) { - this.cache.set('app', this._key, this.toJSON()); - } - }, + storeToCache: function () { + if (this.cache) { + this.cache.set('app', this._key, this.toJSON()); + } + }, - isNew: function () { - return false; - }, + isNew: function () { + return false; + }, }); diff --git a/frontend/client/src/model.js b/frontend/client/src/model.js index 2c74dcc6e5..f344a9c5ca 100644 --- a/frontend/client/src/model.js +++ b/frontend/client/src/model.js @@ -20,175 +20,175 @@ ************************************************************************/ (function (Espo, _, Backbone) { - Espo.Model = Backbone.Model.extend({ + Espo.Model = Backbone.Model.extend({ - name: null, + name: null, - dateTime: null, + dateTime: null, - _user: null, - - defs: null, + _user: null, + + defs: null, - initialize: function () { - this.urlRoot = this.urlRoot || this.name; - - this.defs = this.defs || {}; - this.defs.fields = this.defs.fields || {}; - this.defs.links = this.defs.links || {}; + initialize: function () { + this.urlRoot = this.urlRoot || this.name; + + this.defs = this.defs || {}; + this.defs.fields = this.defs.fields || {}; + this.defs.links = this.defs.links || {}; - Backbone.Model.prototype.initialize.call(this); - }, - - url: function () { - var url = Backbone.Model.prototype.url.call(this); - return url; - }, - - isNew: function () { - return !this.id; - }, + Backbone.Model.prototype.initialize.call(this); + }, + + url: function () { + var url = Backbone.Model.prototype.url.call(this); + return url; + }, + + isNew: function () { + return !this.id; + }, - setDefs: function (defs) { - this.defs = defs || {}; - this.defs.fields = this.defs.fields || {}; - }, - - getClonedAttributes: function () { - var attributes = {}; - for (var name in this.attributes) { - // TODO maybe use cloneDeep method ??? - attributes[name] = Espo.Utils.cloneDeep(this.attributes[name]); - } - return attributes; - }, + setDefs: function (defs) { + this.defs = defs || {}; + this.defs.fields = this.defs.fields || {}; + }, + + getClonedAttributes: function () { + var attributes = {}; + for (var name in this.attributes) { + // TODO maybe use cloneDeep method ??? + attributes[name] = Espo.Utils.cloneDeep(this.attributes[name]); + } + return attributes; + }, - populateDefaults: function () { - var defaultHash = {}; - if ('fields' in this.defs) { - for (var field in this.defs.fields) { - var defaultValue = this.getFieldParam(field, 'default'); + populateDefaults: function () { + var defaultHash = {}; + if ('fields' in this.defs) { + for (var field in this.defs.fields) { + var defaultValue = this.getFieldParam(field, 'default'); - if (defaultValue != null) { - var defaultValue = this._getDefaultValue(defaultValue); - if (typeof defaultValue === 'object') { - defaultHash = _.extend(defaultHash, defaultValue); - } else { - defaultHash[field] = defaultValue; - } - } - } - } - - var user = this.getUser(); - if (user) { - if (this.hasField('assignedUser')) { - this.set('assignedUserId', this.getUser().id); - this.set('assignedUserName', this.getUser().get('name')); - } - var defaultTeamId = this.getUser().get('defaultTeamId'); - if (defaultTeamId) { - if (this.hasField('teams') && !this.getFieldParam('teams', 'default')) { - defaultHash['teamsIds'] = [defaultTeamId]; - defaultHash['teamsNames'] = {}; - defaultHash['teamsNames'][defaultTeamId] = this.getUser().get('defaultTeamName') - } - } - } - - this.set(defaultHash, {silent: true}); - }, + if (defaultValue != null) { + var defaultValue = this._getDefaultValue(defaultValue); + if (typeof defaultValue === 'object') { + defaultHash = _.extend(defaultHash, defaultValue); + } else { + defaultHash[field] = defaultValue; + } + } + } + } + + var user = this.getUser(); + if (user) { + if (this.hasField('assignedUser')) { + this.set('assignedUserId', this.getUser().id); + this.set('assignedUserName', this.getUser().get('name')); + } + var defaultTeamId = this.getUser().get('defaultTeamId'); + if (defaultTeamId) { + if (this.hasField('teams') && !this.getFieldParam('teams', 'default')) { + defaultHash['teamsIds'] = [defaultTeamId]; + defaultHash['teamsNames'] = {}; + defaultHash['teamsNames'][defaultTeamId] = this.getUser().get('defaultTeamName') + } + } + } + + this.set(defaultHash, {silent: true}); + }, - _getDefaultValue: function (defaultValue) { - if (typeof defaultValue == 'string' && defaultValue.indexOf('javascript:') === 0 ) { - var code = defaultValue.substring(11); - defaultValue = (new Function( "with(this) { " + code + "}")).call(this); - } - return defaultValue; - }, + _getDefaultValue: function (defaultValue) { + if (typeof defaultValue == 'string' && defaultValue.indexOf('javascript:') === 0 ) { + var code = defaultValue.substring(11); + defaultValue = (new Function( "with(this) { " + code + "}")).call(this); + } + return defaultValue; + }, - setRelate: function (data) { + setRelate: function (data) { - var setRelate = function (options) { - var link = options.link; - var model = options.model; - if (!link || !model) { - throw new Error('Bad related options'); - } - var type = this.defs.links[link].type; - switch (type) { - case 'belongsToParent': - this.set(link + 'Id', model.id); - this.set(link + 'Type', model.name); - this.set(link + 'Name', model.get('name')); - break; - case 'belongsTo': - this.set(link + 'Id', model.id); - this.set(link + 'Name', model.get('name')); - break; - case 'hasMany': - var ids = []; - ids.push(model.id); - var names = {}; - names[model.id] = model.get('name'); - this.set(link + 'Ids', ids); - this.set(link + 'Names', names); - break; - } - }.bind(this); - - if (Object.prototype.toString.call(data) === '[object Array]') { - data.forEach(function (options) { - setRelate(options); - }.bind(this)); - } else { - setRelate(data); - } - }, + var setRelate = function (options) { + var link = options.link; + var model = options.model; + if (!link || !model) { + throw new Error('Bad related options'); + } + var type = this.defs.links[link].type; + switch (type) { + case 'belongsToParent': + this.set(link + 'Id', model.id); + this.set(link + 'Type', model.name); + this.set(link + 'Name', model.get('name')); + break; + case 'belongsTo': + this.set(link + 'Id', model.id); + this.set(link + 'Name', model.get('name')); + break; + case 'hasMany': + var ids = []; + ids.push(model.id); + var names = {}; + names[model.id] = model.get('name'); + this.set(link + 'Ids', ids); + this.set(link + 'Names', names); + break; + } + }.bind(this); + + if (Object.prototype.toString.call(data) === '[object Array]') { + data.forEach(function (options) { + setRelate(options); + }.bind(this)); + } else { + setRelate(data); + } + }, - getFieldType: function (field) { - if (('defs' in this) && ('fields' in this.defs) && (field in this.defs.fields)) { - return this.defs.fields[field].type || null; - } - return null; - }, + getFieldType: function (field) { + if (('defs' in this) && ('fields' in this.defs) && (field in this.defs.fields)) { + return this.defs.fields[field].type || null; + } + return null; + }, - getFieldParam: function (field, param) { - if (('defs' in this) && ('fields' in this.defs) && (field in this.defs.fields)) { - if (param in this.defs.fields[field]) { - return this.defs.fields[field][param]; - } - } - return null; - }, + getFieldParam: function (field, param) { + if (('defs' in this) && ('fields' in this.defs) && (field in this.defs.fields)) { + if (param in this.defs.fields[field]) { + return this.defs.fields[field][param]; + } + } + return null; + }, - isFieldReadOnly: function (field) { - return this.getFieldParam(field, 'readOnly') || false; - }, + isFieldReadOnly: function (field) { + return this.getFieldParam(field, 'readOnly') || false; + }, - isRequired: function (field) { - return this.getFieldParam(field, 'required') || false; - }, + isRequired: function (field) { + return this.getFieldParam(field, 'required') || false; + }, - getTeamIds: function () { - return this.get('teamsIds') || []; - }, + getTeamIds: function () { + return this.get('teamsIds') || []; + }, - getDateTime: function () { - return this.dateTime; - }, + getDateTime: function () { + return this.dateTime; + }, - getUser: function () { - return this._user; - }, - - hasField: function (field) { - return ('defs' in this) && ('fields' in this.defs) && (field in this.defs.fields); - }, - - isEditable: function () { - return true; - }, - }); + getUser: function () { + return this._user; + }, + + hasField: function (field) { + return ('defs' in this) && ('fields' in this.defs) && (field in this.defs.fields); + }, + + isEditable: function () { + return true; + }, + }); }).call(this, Espo, _, Backbone); diff --git a/frontend/client/src/models/email.js b/frontend/client/src/models/email.js index 1930ae0a88..48d13f3cb1 100644 --- a/frontend/client/src/models/email.js +++ b/frontend/client/src/models/email.js @@ -19,9 +19,9 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ Espo.define('Models.Email', 'Model', function (Dep) { - - return Dep.extend({ + + return Dep.extend({ - }); + }); }); diff --git a/frontend/client/src/models/preferences.js b/frontend/client/src/models/preferences.js index 700bc49542..cd2df08c6a 100644 --- a/frontend/client/src/models/preferences.js +++ b/frontend/client/src/models/preferences.js @@ -19,51 +19,51 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ Espo.define('Models.Preferences', 'Model', function (Dep) { - - return Dep.extend({ - - name: "Preferences", - - settings: null, - - getTimeZoneOptions: function () { - if (this.settings) { - return this.settings.getFieldParam('timeZone', 'options'); - } - }, - - getLanguageOptions: function () { - if (this.settings) { - return this.settings.getFieldParam('language', 'options'); - } - }, - - getDefaultCurrencyOptions: function () { - if (this.settings) { - return this.settings.getDefaultCurrencyOptions(); - } - }, - - setDashletOptions: function (id, attributes) { - var value = this.get('dashletOptions') || {}; - value[id] = attributes; - this.set('dashletOptions', value); - }, - - getDashletOptions: function (id) { - var value = this.get('dashletOptions') || {}; - return value[id] || false; - }, - - unsetDashletOptions: function (id) { - var value = this.get('dashletOptions') || {}; - delete value[id]; - if (Object.getOwnPropertyNames(value).length == 0) { - value = null; - } - this.set('dashletOptions', value); - }, + + return Dep.extend({ + + name: "Preferences", + + settings: null, + + getTimeZoneOptions: function () { + if (this.settings) { + return this.settings.getFieldParam('timeZone', 'options'); + } + }, + + getLanguageOptions: function () { + if (this.settings) { + return this.settings.getFieldParam('language', 'options'); + } + }, + + getDefaultCurrencyOptions: function () { + if (this.settings) { + return this.settings.getDefaultCurrencyOptions(); + } + }, + + setDashletOptions: function (id, attributes) { + var value = this.get('dashletOptions') || {}; + value[id] = attributes; + this.set('dashletOptions', value); + }, + + getDashletOptions: function (id) { + var value = this.get('dashletOptions') || {}; + return value[id] || false; + }, + + unsetDashletOptions: function (id) { + var value = this.get('dashletOptions') || {}; + delete value[id]; + if (Object.getOwnPropertyNames(value).length == 0) { + value = null; + } + this.set('dashletOptions', value); + }, - }); + }); }); diff --git a/frontend/client/src/models/settings.js b/frontend/client/src/models/settings.js index c2ebf2678b..412b396c44 100644 --- a/frontend/client/src/models/settings.js +++ b/frontend/client/src/models/settings.js @@ -19,19 +19,19 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ Espo.define('Models.Settings', 'ModelOffline', function (Dep) { - - return Dep.extend({ - - name: 'Settings', + + return Dep.extend({ + + name: 'Settings', - getDefaultCurrencyOptions: function () { - return this.get('currencyList') || []; - }, - - getBaseCurrencyOptions: function () { - return this.get('currencyList') || []; - }, + getDefaultCurrencyOptions: function () { + return this.get('currencyList') || []; + }, + + getBaseCurrencyOptions: function () { + return this.get('currencyList') || []; + }, - }); + }); }); diff --git a/frontend/client/src/models/user.js b/frontend/client/src/models/user.js index 5f44d1ac26..82ae0ecef6 100644 --- a/frontend/client/src/models/user.js +++ b/frontend/client/src/models/user.js @@ -19,36 +19,36 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ Espo.define('Models.User', 'Model', function (Dep) { - - return Dep.extend({ - - name: "User", - - isAdmin: function () { - return this.get('isAdmin'); - }, + + return Dep.extend({ + + name: "User", + + isAdmin: function () { + return this.get('isAdmin'); + }, - isOwner: function (model) { - return this.id === model.get('assignedUserId') || this.id === model.get('createdById'); - }, + isOwner: function (model) { + return this.id === model.get('assignedUserId') || this.id === model.get('createdById'); + }, - inTeam: function (model) { - - var userTeamIds = this.getTeamIds(); + inTeam: function (model) { + + var userTeamIds = this.getTeamIds(); - if (model.name == 'Team') { - return (userTeamIds.indexOf(model.id) != -1); - } else { - var teamIds = model.getTeamIds(); - for (var i in userTeamIds) { - if (teamIds.indexOf(i) != -1) { - return true; - } - } - } - return false; - }, + if (model.name == 'Team') { + return (userTeamIds.indexOf(model.id) != -1); + } else { + var teamIds = model.getTeamIds(); + for (var i in userTeamIds) { + if (teamIds.indexOf(i) != -1) { + return true; + } + } + } + return false; + }, - }); + }); }); diff --git a/frontend/client/src/multi-collection.js b/frontend/client/src/multi-collection.js index 98d56aa25b..6de6618c2a 100644 --- a/frontend/client/src/multi-collection.js +++ b/frontend/client/src/multi-collection.js @@ -20,31 +20,31 @@ ************************************************************************/ (function (Espo, _,Backbone) { - Espo.MultiCollection = Espo.Collection.extend({ + Espo.MultiCollection = Espo.Collection.extend({ - /** - * @prop {Object} seeds Hash off model classes. - */ - seeds: null, + /** + * @prop {Object} seeds Hash off model classes. + */ + seeds: null, - initialize: function (models, options) { - options = options || {}; - - this.sortBy = options.sortBy || this.sortBy; - this.asc = ('asc' in options) ? options.asc : this.asc; - - Backbone.Collection.prototype.initialize.call(this); - }, + initialize: function (models, options) { + options = options || {}; + + this.sortBy = options.sortBy || this.sortBy; + this.asc = ('asc' in options) ? options.asc : this.asc; + + Backbone.Collection.prototype.initialize.call(this); + }, - parse: function (resp, options) { - this.total = resp.total; - return resp.list.map(function (attributes) { - var a = _.clone(attributes); - delete a['_scope']; - return new this.seeds[attributes._scope](a, options); - }.bind(this)); - }, + parse: function (resp, options) { + this.total = resp.total; + return resp.list.map(function (attributes) { + var a = _.clone(attributes); + delete a['_scope']; + return new this.seeds[attributes._scope](a, options); + }.bind(this)); + }, - }); + }); }).call(this, Espo, _, Backbone); diff --git a/frontend/client/src/pre-loader.js b/frontend/client/src/pre-loader.js index 12d3a7228d..700138faba 100644 --- a/frontend/client/src/pre-loader.js +++ b/frontend/client/src/pre-loader.js @@ -21,94 +21,94 @@ (function (Espo, _, $) { - Espo.PreLoader = function (cache, viewFactory) { - this.cache = cache; - this.viewFactory = viewFactory; - } + Espo.PreLoader = function (cache, viewFactory) { + this.cache = cache; + this.viewFactory = viewFactory; + } - _.extend(Espo.PreLoader.prototype, { + _.extend(Espo.PreLoader.prototype, { - configUrl: 'client/cfg/pre-load.json', + configUrl: 'client/cfg/pre-load.json', - cache: null, + cache: null, - viewFactory: null, + viewFactory: null, - load: function (callback, app) { + load: function (callback, app) { - var bar = $('
    ').prependTo('body');; - bar = bar.children(); - bar.css({ - 'transition': 'width .1s linear', - '-webkit-transition': 'width .1s linear' - }); + var bar = $('
    ').prependTo('body');; + bar = bar.children(); + bar.css({ + 'transition': 'width .1s linear', + '-webkit-transition': 'width .1s linear' + }); - var self = this; + var self = this; - var count = 0; - var countLoaded = 0; - var classesLoaded = 0; - var templatesLoaded = 0; - var layoutTypesLoaded = 0; + var count = 0; + var countLoaded = 0; + var classesLoaded = 0; + var templatesLoaded = 0; + var layoutTypesLoaded = 0; - var updateBar = function () { - var percents = countLoaded / count * 100; - bar.css('width', percents + '%').attr('aria-valuenow', percents); - } + var updateBar = function () { + var percents = countLoaded / count * 100; + bar.css('width', percents + '%').attr('aria-valuenow', percents); + } - var checkIfReady = function () { - if (countLoaded >= count) { - clearInterval(timer); - callback.call(app, app); - } - }; - var timer = setInterval(checkIfReady, 100); + var checkIfReady = function () { + if (countLoaded >= count) { + clearInterval(timer); + callback.call(app, app); + } + }; + var timer = setInterval(checkIfReady, 100); - var load = function (data) { - count = data.templates.length + data.layoutTypes.length+ data.classes.length; + var load = function (data) { + count = data.templates.length + data.layoutTypes.length+ data.classes.length; - var loadTemplates = function () { - data.templates.forEach(function (name) { - self.viewFactory._loader.load('template', name, function () { - layoutTypesLoaded++; - countLoaded++; - updateBar(); - }); - }); - } - var loadLayoutTypes = function () { - data.layoutTypes.forEach(function (name) { - self.viewFactory._loader.load('layoutTemplate', name, function () { - layoutTypesLoaded++; - countLoaded++; - updateBar(); - }); - }); - } - var loadClasses = function () { - data.classes.forEach(function (name) { - Espo.loader.load(name, function () { - classesLoaded++; - countLoaded++; - updateBar(); - }); - }); - } + var loadTemplates = function () { + data.templates.forEach(function (name) { + self.viewFactory._loader.load('template', name, function () { + layoutTypesLoaded++; + countLoaded++; + updateBar(); + }); + }); + } + var loadLayoutTypes = function () { + data.layoutTypes.forEach(function (name) { + self.viewFactory._loader.load('layoutTemplate', name, function () { + layoutTypesLoaded++; + countLoaded++; + updateBar(); + }); + }); + } + var loadClasses = function () { + data.classes.forEach(function (name) { + Espo.loader.load(name, function () { + classesLoaded++; + countLoaded++; + updateBar(); + }); + }); + } - loadTemplates(); - loadLayoutTypes(); - loadClasses(); - }; + loadTemplates(); + loadLayoutTypes(); + loadClasses(); + }; - $.ajax({ - url: this.configUrl, - dataType: 'json', - local: true, - success: function (data) { - load(data); - } - }); - } - }); + $.ajax({ + url: this.configUrl, + dataType: 'json', + local: true, + success: function (data) { + load(data); + } + }); + } + }); }).call(this, Espo, _, $); diff --git a/frontend/client/src/router.js b/frontend/client/src/router.js index eb813d2462..ac5bd7066d 100644 --- a/frontend/client/src/router.js +++ b/frontend/client/src/router.js @@ -20,128 +20,128 @@ ************************************************************************/ (function (Espo, _, Backbone) { - Espo.Router = Backbone.Router.extend({ + Espo.Router = Backbone.Router.extend({ - routes: { + routes: { - "logout": "logout", - - "clearCache": "clearCache", + "logout": "logout", + + "clearCache": "clearCache", - "search/:text": "search", + "search/:text": "search", - ":controller/view/:id/:options": "view", - ":controller/view/:id": "view", - ":controller/edit/:id/:options": "edit", - ":controller/edit/:id": "edit", - ":controller/create": "create", + ":controller/view/:id/:options": "view", + ":controller/view/:id": "view", + ":controller/edit/:id/:options": "edit", + ":controller/edit/:id": "edit", + ":controller/create": "create", - ":controller/:action/:options": "action", - ":controller/:action": "action", + ":controller/:action/:options": "action", + ":controller/:action": "action", - ":controller": "defaultAction", + ":controller": "defaultAction", - "*actions": "home", - }, + "*actions": "home", + }, - _last: null, + _last: null, - initialize: function () { - this.history = []; - this.on('route', function () { - this.history.push(Backbone.history.fragment); - }); - }, + initialize: function () { + this.history = []; + this.on('route', function () { + this.history.push(Backbone.history.fragment); + }); + }, - navigateBack: function (options) { - var url; - if (this.history.length > 1) { - url = this.history[this.history.length - 1]; - } else { - url = this.history[0]; - } - this.navigate(url, options); - }, + navigateBack: function (options) { + var url; + if (this.history.length > 1) { + url = this.history[this.history.length - 1]; + } else { + url = this.history[0]; + } + this.navigate(url, options); + }, - _parseOptionsParams: function (string) { - if (!string) { - return {}; - } + _parseOptionsParams: function (string) { + if (!string) { + return {}; + } - if (string.indexOf('&') === -1 && string.indexOf('=') === -1) { - return string; - } + if (string.indexOf('&') === -1 && string.indexOf('=') === -1) { + return string; + } - var options = {}; - if (typeof string !== 'undefined') { - string.split('&').forEach(function (item, i) { - var p = item.split('='); - options[p[0]] = true; - if (p.length > 1) { - options[p[0]] = p[1]; - } - }); - } - return options; - }, + var options = {}; + if (typeof string !== 'undefined') { + string.split('&').forEach(function (item, i) { + var p = item.split('='); + options[p[0]] = true; + if (p.length > 1) { + options[p[0]] = p[1]; + } + }); + } + return options; + }, - record: function (controller, action, id, options) { - var options = this._parseOptionsParams(options); - options.id = id; - this.dispatch(controller, action, options); - }, + record: function (controller, action, id, options) { + var options = this._parseOptionsParams(options); + options.id = id; + this.dispatch(controller, action, options); + }, - view: function (controller, id, options) { - this.record(controller, 'view', id, options); - }, + view: function (controller, id, options) { + this.record(controller, 'view', id, options); + }, - edit: function (controller, id, options) { - this.record(controller, 'edit', id, options); - }, + edit: function (controller, id, options) { + this.record(controller, 'edit', id, options); + }, - create: function (controller, options) { - this.record(controller, 'create', null, options); - }, + create: function (controller, options) { + this.record(controller, 'create', null, options); + }, - action: function (controller, action, options) { - this.dispatch(controller, action, this._parseOptionsParams(options)); - }, + action: function (controller, action, options) { + this.dispatch(controller, action, this._parseOptionsParams(options)); + }, - defaultAction: function (controller) { - this.dispatch(controller, null); - }, + defaultAction: function (controller) { + this.dispatch(controller, null); + }, - home: function () { - this.dispatch('Home', null); - }, + home: function () { + this.dispatch('Home', null); + }, - search: function (text) { - this.dispatch('Home', 'search', text); - }, + search: function (text) { + this.dispatch('Home', 'search', text); + }, - logout: function () { - this.dispatch(null, 'logout'); - this.navigate('', {trigger: false}); - }, - - clearCache: function () { - this.dispatch(null, 'clearCache'); - }, + logout: function () { + this.dispatch(null, 'logout'); + this.navigate('', {trigger: false}); + }, + + clearCache: function () { + this.dispatch(null, 'clearCache'); + }, - dispatch: function (controller, action, options) { - var o = { - controller: controller, - action: action, - options: options - } - this._last = o; - this.trigger('routed', o); - }, + dispatch: function (controller, action, options) { + var o = { + controller: controller, + action: action, + options: options + } + this._last = o; + this.trigger('routed', o); + }, - getLast: function () { - return this._last; - }, - }); + getLast: function () { + return this._last; + }, + }); }).call(this, Espo, _, Backbone); diff --git a/frontend/client/src/search-manager.js b/frontend/client/src/search-manager.js index ea1c4608d7..ee042c7fd6 100644 --- a/frontend/client/src/search-manager.js +++ b/frontend/client/src/search-manager.js @@ -20,181 +20,181 @@ ************************************************************************/ (function (Espo, _) { - Espo.SearchManager = function (collection, type, storage, dateTime, defaultData) { - this.collection = collection; - this.scope = collection.name; - this.storage = storage; - this.type = type || 'list'; - this.dateTime = dateTime; - - this.data = this.defaultData = defaultData || { - textFilter: '', - bool: {}, - advanced: {}, - }; - - this.sanitizeData(); - }; - - _.extend(Espo.SearchManager.prototype, { - - data: null, - - sanitizeData: function () { - if (!('advanced' in this.data)) { - this.data.advanced = {}; - } - if (!('bool' in this.data)) { - this.data.bool = {}; - } - if (!('textFilter' in this.data)) { - this.data.textFilter = ''; - } - }, - - getWhere: function () { - var where = []; - - if (this.data.textFilter && this.data.textFilter != '') { - where.push({ - type: 'textFilter', - value: this.data.textFilter - }); - } - - if (this.data.bool) { - var o = { - type: 'boolFilters', - value: [], - }; - for (var name in this.data.bool) { - if (this.data.bool[name]) { - o.value.push(name); - } - } - if (o.value.length) { - where.push(o); - } - } - - if (this.data.advanced) { - for (var name in this.data.advanced) { - var field = name; - var defs = this.data.advanced[name]; - - if (!defs) { - continue; - } - - - if ('where' in defs) { - where.push(defs.where); - } else { - if ('field' in defs) { - field = defs.field; - } - var type = defs.type; - if (defs.dateTime) { - where.push(this.getDateTimeWhere(type, field, defs.value)); - } else { - value = defs.value; - where.push({ - type: type, - field: field, - value: value, - }); - } + Espo.SearchManager = function (collection, type, storage, dateTime, defaultData) { + this.collection = collection; + this.scope = collection.name; + this.storage = storage; + this.type = type || 'list'; + this.dateTime = dateTime; + + this.data = this.defaultData = defaultData || { + textFilter: '', + bool: {}, + advanced: {}, + }; + + this.sanitizeData(); + }; + + _.extend(Espo.SearchManager.prototype, { + + data: null, + + sanitizeData: function () { + if (!('advanced' in this.data)) { + this.data.advanced = {}; + } + if (!('bool' in this.data)) { + this.data.bool = {}; + } + if (!('textFilter' in this.data)) { + this.data.textFilter = ''; + } + }, + + getWhere: function () { + var where = []; + + if (this.data.textFilter && this.data.textFilter != '') { + where.push({ + type: 'textFilter', + value: this.data.textFilter + }); + } + + if (this.data.bool) { + var o = { + type: 'boolFilters', + value: [], + }; + for (var name in this.data.bool) { + if (this.data.bool[name]) { + o.value.push(name); + } + } + if (o.value.length) { + where.push(o); + } + } + + if (this.data.advanced) { + for (var name in this.data.advanced) { + var field = name; + var defs = this.data.advanced[name]; + + if (!defs) { + continue; + } + + + if ('where' in defs) { + where.push(defs.where); + } else { + if ('field' in defs) { + field = defs.field; + } + var type = defs.type; + if (defs.dateTime) { + where.push(this.getDateTimeWhere(type, field, defs.value)); + } else { + value = defs.value; + where.push({ + type: type, + field: field, + value: value, + }); + } - } - } - } - return where; - }, - - loadStored: function () { - this.data = this.storage.get(this.type + 'Search', this.scope) || _.clone(this.defaultData); - this.sanitizeData(); - return this; - }, - - get: function () { - return this.data; - }, - - setAdvanced: function (advanced) { - this.data.advanced = advanced; - }, - - set: function (data) { - this.data = data; - if (this.storage) { - this.storage.set(this.type + 'Search', this.scope, data); - } - }, - - reset: function () { - this.data = _.clone(this.defaultData); - if (this.storage) { - this.storage.clear(this.type + 'Search', this.scope); - } - }, - - getDateTimeWhere: function (type, field, value) { - var where = { - field: field - }; - if (!value && ~['on', 'before', 'after'].indexOf(type)) { - return null; - } - - switch (type) { - case 'today': - where.type = 'between'; - var start = this.dateTime.getNowMoment().startOf('day').utc(); - - var from = start.format(this.dateTime.internalDateTimeFormat); - var to = start.add('days', 1).format(this.dateTime.internalDateTimeFormat); - where.value = [from, to]; - break; - case 'past': - where.type = 'before'; - where.value = this.dateTime.getNowMoment().utc().format(this.dateTime.internalDateTimeFormat); - break; - case 'future': - where.type = 'after'; - where.value = this.dateTime.getNowMoment().utc().format(this.dateTime.internalDateTimeFormat); - break; - case 'on': - where.type = 'between'; - var start = moment(value, this.dateTime.internalDateFormat, this.timeZone).utc(); - - var from = start.format(this.dateTime.internalDateTimeFormat); - var to = start.add('days', 1).format(this.dateTime.internalDateTimeFormat); - - where.value = [from, to]; - break; - case 'before': - where.type = 'before'; - where.value = moment(value, this.dateTime.internalDateFormat, this.timeZone).utc().format(this.dateTime.internalDateTimeFormat); - break; - case 'after': - where.type = 'after'; - where.value = moment(value, this.dateTime.internalDateFormat, this.timeZone).utc().format(this.dateTime.internalDateTimeFormat); - break; - case 'between': - where.type = 'between'; - if (value[0] && value[1]) { - var from = moment(value[0], this.dateTime.internalDateFormat, this.timeZone).utc().format(this.dateTime.internalDateTimeFormat); - var to = moment(value[1], this.dateTime.internalDateFormat, this.timeZone).utc().format(this.dateTime.internalDateTimeFormat); - where.value = [from, to]; - } - break; - default: - where.type = type; - } - - return where; - }, - }); + } + } + } + return where; + }, + + loadStored: function () { + this.data = this.storage.get(this.type + 'Search', this.scope) || _.clone(this.defaultData); + this.sanitizeData(); + return this; + }, + + get: function () { + return this.data; + }, + + setAdvanced: function (advanced) { + this.data.advanced = advanced; + }, + + set: function (data) { + this.data = data; + if (this.storage) { + this.storage.set(this.type + 'Search', this.scope, data); + } + }, + + reset: function () { + this.data = _.clone(this.defaultData); + if (this.storage) { + this.storage.clear(this.type + 'Search', this.scope); + } + }, + + getDateTimeWhere: function (type, field, value) { + var where = { + field: field + }; + if (!value && ~['on', 'before', 'after'].indexOf(type)) { + return null; + } + + switch (type) { + case 'today': + where.type = 'between'; + var start = this.dateTime.getNowMoment().startOf('day').utc(); + + var from = start.format(this.dateTime.internalDateTimeFormat); + var to = start.add('days', 1).format(this.dateTime.internalDateTimeFormat); + where.value = [from, to]; + break; + case 'past': + where.type = 'before'; + where.value = this.dateTime.getNowMoment().utc().format(this.dateTime.internalDateTimeFormat); + break; + case 'future': + where.type = 'after'; + where.value = this.dateTime.getNowMoment().utc().format(this.dateTime.internalDateTimeFormat); + break; + case 'on': + where.type = 'between'; + var start = moment(value, this.dateTime.internalDateFormat, this.timeZone).utc(); + + var from = start.format(this.dateTime.internalDateTimeFormat); + var to = start.add('days', 1).format(this.dateTime.internalDateTimeFormat); + + where.value = [from, to]; + break; + case 'before': + where.type = 'before'; + where.value = moment(value, this.dateTime.internalDateFormat, this.timeZone).utc().format(this.dateTime.internalDateTimeFormat); + break; + case 'after': + where.type = 'after'; + where.value = moment(value, this.dateTime.internalDateFormat, this.timeZone).utc().format(this.dateTime.internalDateTimeFormat); + break; + case 'between': + where.type = 'between'; + if (value[0] && value[1]) { + var from = moment(value[0], this.dateTime.internalDateFormat, this.timeZone).utc().format(this.dateTime.internalDateTimeFormat); + var to = moment(value[1], this.dateTime.internalDateFormat, this.timeZone).utc().format(this.dateTime.internalDateTimeFormat); + where.value = [from, to]; + } + break; + default: + where.type = type; + } + + return where; + }, + }); }).call(this, Espo, _); diff --git a/frontend/client/src/storage.js b/frontend/client/src/storage.js index 10353f6b3e..40e856a42e 100644 --- a/frontend/client/src/storage.js +++ b/frontend/client/src/storage.js @@ -20,75 +20,75 @@ ************************************************************************/ (function (Espo, _) { - Espo.Storage = function () { - }; - - _.extend(Espo.Storage.prototype, { - - _prefix: 'espo', - - _composeFullPrefix: function (type) { - return this._prefix + '-' + type; - }, - - _composeKey: function (type, name) { - return this._composeFullPrefix(type) + '-' + name; - }, - - _checkType: function (type) { - if (typeof type === 'undefined' && toString.call(type) != '[object String]' || type == 'cache') { - throw new TypeError("Bad type \"" + type + "\" passed to Espo.Storage."); - } - }, - - get: function (type, name) { - this._checkType(type); - - var key = this._composeKey(type, name); - var stored = localStorage.getItem(key); - if (stored) { - var str = stored; - if (stored[0] == "{" || stored[0] == "[") { - try { - str = JSON.parse(stored); - } catch (error) { - str = stored; - } - stored = str; - } - return stored; - } - return null; - }, - - set: function (type, name, value) { - this._checkType(type); + Espo.Storage = function () { + }; + + _.extend(Espo.Storage.prototype, { + + _prefix: 'espo', + + _composeFullPrefix: function (type) { + return this._prefix + '-' + type; + }, + + _composeKey: function (type, name) { + return this._composeFullPrefix(type) + '-' + name; + }, + + _checkType: function (type) { + if (typeof type === 'undefined' && toString.call(type) != '[object String]' || type == 'cache') { + throw new TypeError("Bad type \"" + type + "\" passed to Espo.Storage."); + } + }, + + get: function (type, name) { + this._checkType(type); + + var key = this._composeKey(type, name); + var stored = localStorage.getItem(key); + if (stored) { + var str = stored; + if (stored[0] == "{" || stored[0] == "[") { + try { + str = JSON.parse(stored); + } catch (error) { + str = stored; + } + stored = str; + } + return stored; + } + return null; + }, + + set: function (type, name, value) { + this._checkType(type); - var key = this._composeKey(type, name); - if (value instanceof Object) { - value = JSON.stringify(value); - } - localStorage.setItem(key, value); - }, - - clear: function (type, name) { - var reText; - if (typeof type !== 'undefined') { - if (typeof name === 'undefined') { - reText = '^' + this._composeFullPrefix(type); - } else { - reText = '^' + this._composeKey(type, name); - } - } else { - reText = '^' + this._prefix + '-'; - } - var re = new RegExp(reText); - for (var i in localStorage) { - if (re.test(i)) { - delete localStorage[i]; - } - } - } - }); + var key = this._composeKey(type, name); + if (value instanceof Object) { + value = JSON.stringify(value); + } + localStorage.setItem(key, value); + }, + + clear: function (type, name) { + var reText; + if (typeof type !== 'undefined') { + if (typeof name === 'undefined') { + reText = '^' + this._composeFullPrefix(type); + } else { + reText = '^' + this._composeKey(type, name); + } + } else { + reText = '^' + this._prefix + '-'; + } + var re = new RegExp(reText); + for (var i in localStorage) { + if (re.test(i)) { + delete localStorage[i]; + } + } + } + }); }).call(this, Espo, _); diff --git a/frontend/client/src/ui.js b/frontend/client/src/ui.js index adbb0bd0c8..4b2fe35265 100644 --- a/frontend/client/src/ui.js +++ b/frontend/client/src/ui.js @@ -20,188 +20,188 @@ ************************************************************************/ (function (Espo, $) { - var Dialog = function (options) { - options = options || {}; - - this.className = 'dialog'; - this.backdrop = 'static'; - this.closeButton = true; - this.header = false; - this.body = ''; - this.width = false; - this.height = false; - this.buttons = []; - this.removeOnClose = true; - this.graggable = false; - this.container = 'body' - this.onRemove = function () {}; - - var params = ['className', 'backdrop', 'closeButton', 'header', 'body', 'width', 'height', 'buttons', 'removeOnClose', 'graggable', 'container', 'onRemove']; - params.forEach(function (param) { - if (param in options) { - this[param] = options[param]; - } - }.bind(this)); - - this.id = 'dialog-' + Math.floor((Math.random() * 100000)); - - this.contents = ''; - if (this.header) { - this.contents += ''; - } - - this.contents += ''; - - if (this.buttons.length) { - this.contents += '
    '; - this.buttons.forEach(function (o) { - this.contents += ' '; - }.bind(this)); - this.contents += '
    '; - } - - this.contents = '' - - $('
    ').attr('id', this.id) - .attr('class', this.className + ' modal') - .attr('role', 'dialog') - .attr('tabindex', '-1') - .html(this.contents) - .appendTo($(this.container)); - - this.$el = $('#' + this.id); - this.el = this.$el.get(0); - - this.$el.find('header a.close').on('click', function () { - this.close(); - }.bind(this)); - - this.buttons.forEach(function (o) { - if (typeof o.onClick == 'function') { - $('#' + this.id + ' button[data-name="' + o.name + '"]').on('click', function () { - o.onClick(this); - }.bind(this)); - } - }.bind(this)); - - if (this.graggable) { - this.$el.find('header').css('cursor', 'pointer'); - this.$el.draggable({ - handle: 'header', - }); - } - - var modalContentEl = this.$el.find('.modal-content'); - - if (this.width) { - modalContentEl.css('width', this.width); - modalContentEl.css('margin-left', '-' + (parseInt(this.width.replace('px', '')) / 5) + 'px'); - } - - if (this.removeOnClose) { - this.$el.on('hidden.bs.modal', function (e) { - if (this.$el.get(0) == e.target) { - this.remove(); - } - }.bind(this)); - } - - this.$el.on('show.bs.modal', function (event) { - var idx = $('.modal:visible').length; - $(this).css('z-index', 1040 + (10 * idx)); - }); - this.$el.on('shown.bs.modal', function (event) { - var idx = ($('.modal:visible').length) - 1; - $('.modal-backdrop').not('.stacked').css('z-index', 1039 + (10 * idx)); - $('.modal-backdrop').not('.stacked').addClass('stacked'); - }); - this.$el.on('hidden.bs.modal', function (event) { - if ($('.modal:visible').length > 0) { - setTimeout(function() { - $(document.body).addClass('modal-open'); - }, 0); - } - }); + var Dialog = function (options) { + options = options || {}; + + this.className = 'dialog'; + this.backdrop = 'static'; + this.closeButton = true; + this.header = false; + this.body = ''; + this.width = false; + this.height = false; + this.buttons = []; + this.removeOnClose = true; + this.graggable = false; + this.container = 'body' + this.onRemove = function () {}; + + var params = ['className', 'backdrop', 'closeButton', 'header', 'body', 'width', 'height', 'buttons', 'removeOnClose', 'graggable', 'container', 'onRemove']; + params.forEach(function (param) { + if (param in options) { + this[param] = options[param]; + } + }.bind(this)); + + this.id = 'dialog-' + Math.floor((Math.random() * 100000)); + + this.contents = ''; + if (this.header) { + this.contents += ''; + } + + this.contents += ''; + + if (this.buttons.length) { + this.contents += '
    '; + this.buttons.forEach(function (o) { + this.contents += ' '; + }.bind(this)); + this.contents += '
    '; + } + + this.contents = '' + + $('
    ').attr('id', this.id) + .attr('class', this.className + ' modal') + .attr('role', 'dialog') + .attr('tabindex', '-1') + .html(this.contents) + .appendTo($(this.container)); + + this.$el = $('#' + this.id); + this.el = this.$el.get(0); + + this.$el.find('header a.close').on('click', function () { + this.close(); + }.bind(this)); + + this.buttons.forEach(function (o) { + if (typeof o.onClick == 'function') { + $('#' + this.id + ' button[data-name="' + o.name + '"]').on('click', function () { + o.onClick(this); + }.bind(this)); + } + }.bind(this)); + + if (this.graggable) { + this.$el.find('header').css('cursor', 'pointer'); + this.$el.draggable({ + handle: 'header', + }); + } + + var modalContentEl = this.$el.find('.modal-content'); + + if (this.width) { + modalContentEl.css('width', this.width); + modalContentEl.css('margin-left', '-' + (parseInt(this.width.replace('px', '')) / 5) + 'px'); + } + + if (this.removeOnClose) { + this.$el.on('hidden.bs.modal', function (e) { + if (this.$el.get(0) == e.target) { + this.remove(); + } + }.bind(this)); + } + + this.$el.on('show.bs.modal', function (event) { + var idx = $('.modal:visible').length; + $(this).css('z-index', 1040 + (10 * idx)); + }); + this.$el.on('shown.bs.modal', function (event) { + var idx = ($('.modal:visible').length) - 1; + $('.modal-backdrop').not('.stacked').css('z-index', 1039 + (10 * idx)); + $('.modal-backdrop').not('.stacked').addClass('stacked'); + }); + this.$el.on('hidden.bs.modal', function (event) { + if ($('.modal:visible').length > 0) { + setTimeout(function() { + $(document.body).addClass('modal-open'); + }, 0); + } + }); - } - Dialog.prototype.show = function () { - this.$el.modal({ - backdrop: this.backdrop, - }); - - /*this.$el.css('z-index', 1200); - $('.modal-backdrop').css('z-index', 1100);*/ - }; - Dialog.prototype.close = function () { - this.$el.modal('hide'); - $(this).trigger('dialog:close'); - }; - Dialog.prototype.remove = function () { - this.onRemove(); - this.$el.remove(); - $(this).off(); - }; - - Espo.Ui = { - - Dialog: Dialog, - - dialog: function (options) { - return new Dialog(options); - }, - - notify: function (message, type, timeout, closeButton) { - $('#nofitication').remove(); - - if (message) { - type = type || 'warning'; - if (typeof closeButton == 'undefined') { - closeButton = false; - } - - if (type == 'error') { - type = 'danger'; - } - - var el = $('
    ').css({ - position: 'fixed', - top: '0px', - 'z-index': 2000, - }).html(message); - - if (closeButton) { - el.append(''); - } - - if (timeout) { - setTimeout(function () { - el.alert('close'); - }, timeout); - } - - el.appendTo('body'); - el.css("left", ($(window).width() - el.width()) / 2 + $(window).scrollLeft() + "px"); - } - }, - - warning: function (message) { - Espo.Ui.notify(message, 'warning', 2000); - }, - - success: function (message) { - Espo.Ui.notify(message, 'success', 2000); - }, - - error: function (message) { - Espo.Ui.notify(message, 'error', 2000); - }, - - info: function (message) { - Espo.Ui.notify(message, 'info', 2000); - }, - } + } + Dialog.prototype.show = function () { + this.$el.modal({ + backdrop: this.backdrop, + }); + + /*this.$el.css('z-index', 1200); + $('.modal-backdrop').css('z-index', 1100);*/ + }; + Dialog.prototype.close = function () { + this.$el.modal('hide'); + $(this).trigger('dialog:close'); + }; + Dialog.prototype.remove = function () { + this.onRemove(); + this.$el.remove(); + $(this).off(); + }; + + Espo.Ui = { + + Dialog: Dialog, + + dialog: function (options) { + return new Dialog(options); + }, + + notify: function (message, type, timeout, closeButton) { + $('#nofitication').remove(); + + if (message) { + type = type || 'warning'; + if (typeof closeButton == 'undefined') { + closeButton = false; + } + + if (type == 'error') { + type = 'danger'; + } + + var el = $('
    ').css({ + position: 'fixed', + top: '0px', + 'z-index': 2000, + }).html(message); + + if (closeButton) { + el.append(''); + } + + if (timeout) { + setTimeout(function () { + el.alert('close'); + }, timeout); + } + + el.appendTo('body'); + el.css("left", ($(window).width() - el.width()) / 2 + $(window).scrollLeft() + "px"); + } + }, + + warning: function (message) { + Espo.Ui.notify(message, 'warning', 2000); + }, + + success: function (message) { + Espo.Ui.notify(message, 'success', 2000); + }, + + error: function (message) { + Espo.Ui.notify(message, 'error', 2000); + }, + + info: function (message) { + Espo.Ui.notify(message, 'info', 2000); + }, + } }).call(this, Espo, $); diff --git a/frontend/client/src/utils.js b/frontend/client/src/utils.js index 46eeb09016..5c0105e997 100644 --- a/frontend/client/src/utils.js +++ b/frontend/client/src/utils.js @@ -20,135 +20,135 @@ ************************************************************************/ (function (Espo, _) { - Espo.Utils = { - - checkActionAccess: function (acl, model, item) { - var hasAccess = true; - if (item.acl) { - if (!item.aclScope) { - if (model) { - hasAccess = acl.checkModel(model, item.acl); - } else { - hasAccess = acl.check(item.scope, item.acl); - } - } else { - hasAccess = acl.check(item.aclScope, item.acl); - } - } - return hasAccess; - }, + Espo.Utils = { + + checkActionAccess: function (acl, model, item) { + var hasAccess = true; + if (item.acl) { + if (!item.aclScope) { + if (model) { + hasAccess = acl.checkModel(model, item.acl); + } else { + hasAccess = acl.check(item.scope, item.acl); + } + } else { + hasAccess = acl.check(item.aclScope, item.acl); + } + } + return hasAccess; + }, - convert: function (string, p) { - if (string == null) { - return string; - } + convert: function (string, p) { + if (string == null) { + return string; + } - var result = string; - switch (p) { - case 'c-h': - case 'C-h': - result = Espo.Utils.camelCaseToHyphen(string); - break; - case 'h-c': - result = Espo.Utils.hyphenToCamelCase(string); - break; - case 'h-C': - result = Espo.Utils.hyphenToUpperCamelCase(string); - break; - } - return result; - }, - - isObject: function (obj) { - if (obj === null) { - return false; - } - return typeof obj === 'object'; - }, - - clone: function (obj) { - if (!Espo.Utils.isObject(obj)) { - return obj; - } - return _.isArray(obj) ? obj.slice() : _.extend({}, obj); - }, - - cloneDeep: function (data) { - data = Espo.Utils.clone(data); - - if (Espo.Utils.isObject(data) || _.isArray(data)) { - for (var i in data) { - data[i] = this.cloneDeep(data[i]); - } - } - return data; - }, + var result = string; + switch (p) { + case 'c-h': + case 'C-h': + result = Espo.Utils.camelCaseToHyphen(string); + break; + case 'h-c': + result = Espo.Utils.hyphenToCamelCase(string); + break; + case 'h-C': + result = Espo.Utils.hyphenToUpperCamelCase(string); + break; + } + return result; + }, + + isObject: function (obj) { + if (obj === null) { + return false; + } + return typeof obj === 'object'; + }, + + clone: function (obj) { + if (!Espo.Utils.isObject(obj)) { + return obj; + } + return _.isArray(obj) ? obj.slice() : _.extend({}, obj); + }, + + cloneDeep: function (data) { + data = Espo.Utils.clone(data); + + if (Espo.Utils.isObject(data) || _.isArray(data)) { + for (var i in data) { + data[i] = this.cloneDeep(data[i]); + } + } + return data; + }, - /** - * Compose class name. - * @param {String} module - * @param {String} name - * @param {String} location - * @return {String} - */ - composeClassName: function (module, name, location) { - if (module) { - return module + ':' + location + '.' + name; - } else { - return location + '.' + name; - } - }, + /** + * Compose class name. + * @param {String} module + * @param {String} name + * @param {String} location + * @return {String} + */ + composeClassName: function (module, name, location) { + if (module) { + return module + ':' + location + '.' + name; + } else { + return location + '.' + name; + } + }, - composeViewClassName: function (name) { - if (name.indexOf(':') != -1) { - var arr = name.split(':'); - var modPart = arr[0]; - var namePart = arr[1]; - return modPart + ':' + 'Views' + '.' + namePart; - } else { - return 'Views' + '.' + name; - } - }, + composeViewClassName: function (name) { + if (name.indexOf(':') != -1) { + var arr = name.split(':'); + var modPart = arr[0]; + var namePart = arr[1]; + return modPart + ':' + 'Views' + '.' + namePart; + } else { + return 'Views' + '.' + name; + } + }, - toDom: function (string) { - return Espo.Utils.convert(string, 'c-h').split('.').join('-'); - }, + toDom: function (string) { + return Espo.Utils.convert(string, 'c-h').split('.').join('-'); + }, - upperCaseFirst: function (string) { - if (string == null) { - return string; - } - return string.charAt(0).toUpperCase() + string.slice(1); - }, + upperCaseFirst: function (string) { + if (string == null) { + return string; + } + return string.charAt(0).toUpperCase() + string.slice(1); + }, - hyphenToUpperCamelCase: function (string) { - if (string == null) { - return string; - } - return this.upperCaseFirst(string.replace(/-([a-z])/g, function (g) {return g[1].toUpperCase();})); - }, + hyphenToUpperCamelCase: function (string) { + if (string == null) { + return string; + } + return this.upperCaseFirst(string.replace(/-([a-z])/g, function (g) {return g[1].toUpperCase();})); + }, - hyphenToCamelCase: function (string) { - if (string == null) { - return string; - } - return string.replace(/-([a-z])/g, function (g) {return g[1].toUpperCase();}); - }, + hyphenToCamelCase: function (string) { + if (string == null) { + return string; + } + return string.replace(/-([a-z])/g, function (g) {return g[1].toUpperCase();}); + }, - camelCaseToHyphen: function (string) { - if (string == null) { - return string; - } - return string.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); - }, + camelCaseToHyphen: function (string) { + if (string == null) { + return string; + } + return string.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); + }, - trimSlash: function (str) { - if (str.substr(-1) == '/') { - return str.substr(0, str.length - 1); - } - return str; - } - }; + trimSlash: function (str) { + if (str.substr(-1) == '/') { + return str.substr(0, str.length - 1); + } + return str; + } + }; }).call(this, Espo, _); diff --git a/frontend/client/src/view-helper.js b/frontend/client/src/view-helper.js index 8571cfadd3..6d1c3e2153 100644 --- a/frontend/client/src/view-helper.js +++ b/frontend/client/src/view-helper.js @@ -21,200 +21,200 @@ (function (Espo, _, Handlebars) { - Espo.ViewHelper = function (options) { - this.urlRegex = /(^|[^\[])(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; - this._registerHandlebarsHelpers(); - - this.mdSearch = [ - /\("?(.*?)"?\)\[(.*?)\]/g, - /\&\#x60;(([\s\S]*?)\&\#x60;)/, - /(\*\*|__)(.*?)\1/, - /(\*|_)(.*?)\1/, - /\~\~(.*?)\~\~/ - ]; - this.mdReplace = [ - '$1', - '$2', - '$2', - '$2', - '$1', - ]; - - } + Espo.ViewHelper = function (options) { + this.urlRegex = /(^|[^\[])(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; + this._registerHandlebarsHelpers(); + + this.mdSearch = [ + /\("?(.*?)"?\)\[(.*?)\]/g, + /\&\#x60;(([\s\S]*?)\&\#x60;)/, + /(\*\*|__)(.*?)\1/, + /(\*|_)(.*?)\1/, + /\~\~(.*?)\~\~/ + ]; + this.mdReplace = [ + '$1', + '$2', + '$2', + '$2', + '$1', + ]; + + } - _.extend(Espo.ViewHelper.prototype, { + _.extend(Espo.ViewHelper.prototype, { - layoutManager: null, + layoutManager: null, - settings: null, + settings: null, - user: null, + user: null, - preferences: null, + preferences: null, - language: null, + language: null, - _registerHandlebarsHelpers: function () { - var self = this; + _registerHandlebarsHelpers: function () { + var self = this; - Handlebars.registerHelper('img', function (img) { - return new Handlebars.SafeString(""); - }); + Handlebars.registerHelper('img', function (img) { + return new Handlebars.SafeString(""); + }); - Handlebars.registerHelper('prop', function (object, name) { - if (name in object) { - return object[name]; - } - }); + Handlebars.registerHelper('prop', function (object, name) { + if (name in object) { + return object[name]; + } + }); - Handlebars.registerHelper('var', function (name, context, options) { - return new Handlebars.SafeString(context[name]); - }); + Handlebars.registerHelper('var', function (name, context, options) { + return new Handlebars.SafeString(context[name]); + }); - Handlebars.registerHelper('concat', function (left, right) { - return left + right; - }); + Handlebars.registerHelper('concat', function (left, right) { + return left + right; + }); - Handlebars.registerHelper('ifEqual', function (left, right, options) { - if (left == right) { - return options.fn(this); - } - return options.inverse(this); - }); + Handlebars.registerHelper('ifEqual', function (left, right, options) { + if (left == right) { + return options.fn(this); + } + return options.inverse(this); + }); - Handlebars.registerHelper('ifNotEqual', function (left, right, options) { - if (left != right) { - return options.fn(this); - } - return options.inverse(this); - }); + Handlebars.registerHelper('ifNotEqual', function (left, right, options) { + if (left != right) { + return options.fn(this); + } + return options.inverse(this); + }); - Handlebars.registerHelper('ifPropEquals', function (object, property, value, options) { - if (object[property] == value) { - return options.fn(this); - } - return options.inverse(this); - }); - - Handlebars.registerHelper('ifAttrEquals', function (model, attr, value, options) { - if (model.get(attr) == value) { - return options.fn(this); - } - return options.inverse(this); - }); - - Handlebars.registerHelper('ifAttrNotEmpty', function (model, attr, options) { - if (model.get(attr)) { - return options.fn(this); - } - return options.inverse(this); - }); + Handlebars.registerHelper('ifPropEquals', function (object, property, value, options) { + if (object[property] == value) { + return options.fn(this); + } + return options.inverse(this); + }); + + Handlebars.registerHelper('ifAttrEquals', function (model, attr, value, options) { + if (model.get(attr) == value) { + return options.fn(this); + } + return options.inverse(this); + }); + + Handlebars.registerHelper('ifAttrNotEmpty', function (model, attr, options) { + if (model.get(attr)) { + return options.fn(this); + } + return options.inverse(this); + }); - Handlebars.registerHelper('get', function (model, name) { - return model.get(name); - }); + Handlebars.registerHelper('get', function (model, name) { + return model.get(name); + }); - Handlebars.registerHelper('length', function (arr) { - return arr.length; - }); + Handlebars.registerHelper('length', function (arr) { + return arr.length; + }); - Handlebars.registerHelper('translate', function (name, options) { - var scope = options.hash.scope || null; - var category = options.hash.category || null; - if (name === 'null') { - return ''; - } - return self.language.translate(name, category, scope); - }); + Handlebars.registerHelper('translate', function (name, options) { + var scope = options.hash.scope || null; + var category = options.hash.category || null; + if (name === 'null') { + return ''; + } + return self.language.translate(name, category, scope); + }); - Handlebars.registerHelper('button', function (name, options) { - var style = options.hash.style || 'default'; - var scope = options.hash.scope || null; - var label = options.hash.label || name; - return new Handlebars.SafeString(''); - }); + Handlebars.registerHelper('button', function (name, options) { + var style = options.hash.style || 'default'; + var scope = options.hash.scope || null; + var label = options.hash.label || name; + return new Handlebars.SafeString(''); + }); - Handlebars.registerHelper('hyphen', function (string) { - return Espo.Utils.convert(string, 'c-h'); - }); + Handlebars.registerHelper('hyphen', function (string) { + return Espo.Utils.convert(string, 'c-h'); + }); - Handlebars.registerHelper('toDom', function (string) { - return Espo.Utils.toDom(string); - }); + Handlebars.registerHelper('toDom', function (string) { + return Espo.Utils.toDom(string); + }); - Handlebars.registerHelper('breaklines', function (text) { - text = Handlebars.Utils.escapeExpression(text || ''); - text = text.replace(/(\r\n|\n|\r)/gm, '
    '); - return new Handlebars.SafeString(text); - }); - - Handlebars.registerHelper('complexText', function (text) { - text = Handlebars.Utils.escapeExpression(text || ''); - - text = text.replace(self.urlRegex, '$1($2)[$2]'); - - self.mdSearch.forEach(function (re, i) { - text = text.replace(re, self.mdReplace[i]); - }); - - text = text.replace(/(\r\n|\n|\r)/gm, '
    '); - - text = text.replace('[#see-more-text]', ' ' + self.language.translate('See more')) + ''; - return new Handlebars.SafeString(text); - }); + Handlebars.registerHelper('breaklines', function (text) { + text = Handlebars.Utils.escapeExpression(text || ''); + text = text.replace(/(\r\n|\n|\r)/gm, '
    '); + return new Handlebars.SafeString(text); + }); + + Handlebars.registerHelper('complexText', function (text) { + text = Handlebars.Utils.escapeExpression(text || ''); + + text = text.replace(self.urlRegex, '$1($2)[$2]'); + + self.mdSearch.forEach(function (re, i) { + text = text.replace(re, self.mdReplace[i]); + }); + + text = text.replace(/(\r\n|\n|\r)/gm, '
    '); + + text = text.replace('[#see-more-text]', ' ' + self.language.translate('See more')) + ''; + return new Handlebars.SafeString(text); + }); - Handlebars.registerHelper('translateOption', function (name, options) { - var scope = options.hash.scope || null; - var field = options.hash.field || null; - if (!field) { - return ''; - } - var translationHash = self.language.translate(field, 'options', scope) || {}; - return translationHash[name] || name; - }); + Handlebars.registerHelper('translateOption', function (name, options) { + var scope = options.hash.scope || null; + var field = options.hash.field || null; + if (!field) { + return ''; + } + var translationHash = self.language.translate(field, 'options', scope) || {}; + return translationHash[name] || name; + }); - Handlebars.registerHelper('options', function (list, value, options) { - value = value || false; - list = list || {}; - var html = ''; - var isArray = (Object.prototype.toString.call(list) === '[object Array]'); + Handlebars.registerHelper('options', function (list, value, options) { + value = value || false; + list = list || {}; + var html = ''; + var isArray = (Object.prototype.toString.call(list) === '[object Array]'); - var multiple = (Object.prototype.toString.call(value) === '[object Array]'); - var checkOption = function (name) { - if (multiple) { - return value.indexOf(name) != -1; - } else { - return value === name; - } - }; + var multiple = (Object.prototype.toString.call(value) === '[object Array]'); + var checkOption = function (name) { + if (multiple) { + return value.indexOf(name) != -1; + } else { + return value === name; + } + }; - var scope = options.hash.scope || false; - var category = options.hash.category || false; - var field = options.hash.field || false; + var scope = options.hash.scope || false; + var category = options.hash.category || false; + var field = options.hash.field || false; - var translationHash; - if (!category && field) { - var translationHash = self.language.translate(field, 'options', scope) || {}; - } + var translationHash; + if (!category && field) { + var translationHash = self.language.translate(field, 'options', scope) || {}; + } - var translate = function (name) { - if (!category && field) { - if (typeof translationHash === 'object' && name in translationHash) { - return translationHash[name]; - } - return name; - } - return self.language.translate(name, category, scope); - }; + var translate = function (name) { + if (!category && field) { + if (typeof translationHash === 'object' && name in translationHash) { + return translationHash[name]; + } + return name; + } + return self.language.translate(name, category, scope); + }; - for (var key in list) { - var keyVal = list[key]; - html += "" - } - return new Handlebars.SafeString(html); - }); - } - }); + for (var key in list) { + var keyVal = list[key]; + html += "" + } + return new Handlebars.SafeString(html); + }); + } + }); }).call(this, Espo, _, Handlebars); diff --git a/frontend/client/src/view.js b/frontend/client/src/view.js index 06bb69c923..9618ab66c8 100644 --- a/frontend/client/src/view.js +++ b/frontend/client/src/view.js @@ -20,136 +20,136 @@ ************************************************************************/ (function (Espo, Backbone, _, Bull, $) { - Espo.View = Bull.View.extend({ + Espo.View = Bull.View.extend({ - addActionHandler: function (action, handler) { - this.events = this.events || {}; + addActionHandler: function (action, handler) { + this.events = this.events || {}; - var fullAction = 'click button[data-action=\"'+action+'\"]'; - this.events[fullAction] = handler; - }, + var fullAction = 'click button[data-action=\"'+action+'\"]'; + this.events[fullAction] = handler; + }, - notify: function (label, type, timeout, scope) { - if (label == false) { - Espo.Ui.notify(false); - return; - } - scope = scope || null; - timeout = timeout || 2000; - if (!type) { - timeout = null; - } - var text = this.getLanguage().translate(label, 'labels', scope); - Espo.Ui.notify(text, type, timeout); - }, + notify: function (label, type, timeout, scope) { + if (label == false) { + Espo.Ui.notify(false); + return; + } + scope = scope || null; + timeout = timeout || 2000; + if (!type) { + timeout = null; + } + var text = this.getLanguage().translate(label, 'labels', scope); + Espo.Ui.notify(text, type, timeout); + }, - getHelper: function () { - return this._helper; - }, + getHelper: function () { + return this._helper; + }, - getUser: function () { - if (this._helper) { - return this._helper.user; - } - }, + getUser: function () { + if (this._helper) { + return this._helper.user; + } + }, - getPreferences: function () { - if (this._helper) { - return this._helper.preferences; - } - }, + getPreferences: function () { + if (this._helper) { + return this._helper.preferences; + } + }, - getConfig: function () { - if (this._helper) { - return this._helper.settings; - } - }, + getConfig: function () { + if (this._helper) { + return this._helper.settings; + } + }, - getAcl: function () { - if (this._helper) { - return this._helper.acl; - } - }, + getAcl: function () { + if (this._helper) { + return this._helper.acl; + } + }, - getModelFactory: function () { - if (this._helper) { - return this._helper.modelFactory; - } - }, + getModelFactory: function () { + if (this._helper) { + return this._helper.modelFactory; + } + }, - getCollectionFactory: function () { - if (this._helper) { - return this._helper.collectionFactory; - } - }, + getCollectionFactory: function () { + if (this._helper) { + return this._helper.collectionFactory; + } + }, - getRouter: function () { - if (this._helper) { - return this._helper.router; - } - }, + getRouter: function () { + if (this._helper) { + return this._helper.router; + } + }, - getStorage: function () { - if (this._helper) { - return this._helper.storage; - } - }, + getStorage: function () { + if (this._helper) { + return this._helper.storage; + } + }, - getLanguage: function () { - if (this._helper) { - return this._helper.language; - } - }, + getLanguage: function () { + if (this._helper) { + return this._helper.language; + } + }, - getMetadata: function () { - if (this._helper) { - return this._helper.metadata; - } - }, + getMetadata: function () { + if (this._helper) { + return this._helper.metadata; + } + }, - getCache: function () { - if (this._helper) { - return this._helper.cache; - } - }, + getCache: function () { + if (this._helper) { + return this._helper.cache; + } + }, - getStorage: function () { - if (this._helper) { - return this._helper.storage; - } - }, + getStorage: function () { + if (this._helper) { + return this._helper.storage; + } + }, - getDateTime: function () { - if (this._helper) { - return this._helper.dateTime; - } - }, + getDateTime: function () { + if (this._helper) { + return this._helper.dateTime; + } + }, - getFieldManager: function () { - if (this._helper) { - return this._helper.fieldManager; - } - }, - - getBaseController: function () { - if (this._helper) { - return this._helper.baseController; - } - }, + getFieldManager: function () { + if (this._helper) { + return this._helper.fieldManager; + } + }, + + getBaseController: function () { + if (this._helper) { + return this._helper.baseController; + } + }, - updatePageTitle: function () { - var title = this.getConfig().get('applicationTitle') || 'EspoCRM'; - this.setPageTitle(title); - }, + updatePageTitle: function () { + var title = this.getConfig().get('applicationTitle') || 'EspoCRM'; + this.setPageTitle(title); + }, - setPageTitle: function (title) { - $('head title').text(title); - }, + setPageTitle: function (title) { + $('head title').text(title); + }, - translate: function (label, category, scope) { - return this.getLanguage().translate(label, category, scope); - }, - }); + translate: function (label, category, scope) { + return this.getLanguage().translate(label, category, scope); + }, + }); }).call(this, Espo, Backbone, _, Bull, $); diff --git a/frontend/client/src/views/about.js b/frontend/client/src/views/about.js index 5cde26354c..c7a3cd8e86 100644 --- a/frontend/client/src/views/about.js +++ b/frontend/client/src/views/about.js @@ -21,18 +21,18 @@ Espo.define('Views.About', 'View', function (Dep) { - return Dep.extend({ + return Dep.extend({ - template: 'about', + template: 'about', - el: '#main', - - data: function () { - return { - version: this.getConfig().get('version') - }; - } + el: '#main', + + data: function () { + return { + version: this.getConfig().get('version') + }; + } - }); + }); }); diff --git a/frontend/client/src/views/admin/auth-token/list.js b/frontend/client/src/views/admin/auth-token/list.js index 2e2b520135..20112a3a21 100644 --- a/frontend/client/src/views/admin/auth-token/list.js +++ b/frontend/client/src/views/admin/auth-token/list.js @@ -21,23 +21,23 @@ Espo.define('Views.Admin.AuthToken.List', 'Views.List', function (Dep) { - return Dep.extend({ - - searchPanel: false, + return Dep.extend({ + + searchPanel: false, - setup: function () { - Dep.prototype.setup.call(this); - - this.menu.buttons = []; - }, + setup: function () { + Dep.prototype.setup.call(this); + + this.menu.buttons = []; + }, - getHeader: function () { - return '' + this.translate('Administration') + " » " + this.getLanguage().translate('Auth Tokens', 'labels', 'Administration'); - }, + getHeader: function () { + return '' + this.translate('Administration') + " » " + this.getLanguage().translate('Auth Tokens', 'labels', 'Administration'); + }, - updatePageTitle: function () { - this.setPageTitle(this.getLanguage().translate('Auth Tokens', 'labels', 'Administration')); - }, - }); + updatePageTitle: function () { + this.setPageTitle(this.getLanguage().translate('Auth Tokens', 'labels', 'Administration')); + }, + }); }); diff --git a/frontend/client/src/views/admin/auth-token/record/list.js b/frontend/client/src/views/admin/auth-token/record/list.js index a4cc16f2cd..0878cb3fbe 100644 --- a/frontend/client/src/views/admin/auth-token/record/list.js +++ b/frontend/client/src/views/admin/auth-token/record/list.js @@ -21,24 +21,24 @@ Espo.define('Views.Admin.AuthToken.Record.List', 'Views.Record.List', function (Dep) { - return Dep.extend({ - - rowActionsView: 'Admin.AuthToken.Record.RowActions.Remove', - - setup: function () { - Dep.prototype.setup.call(this); - - var actions = []; - - this.actions.forEach(function (item) { - if (item.name == 'delete') { - actions.push(item); - } - }, this); - - this.actions = actions; - }, + return Dep.extend({ + + rowActionsView: 'Admin.AuthToken.Record.RowActions.Remove', + + setup: function () { + Dep.prototype.setup.call(this); + + var actions = []; + + this.actions.forEach(function (item) { + if (item.name == 'delete') { + actions.push(item); + } + }, this); + + this.actions = actions; + }, - }); + }); }); diff --git a/frontend/client/src/views/admin/auth-token/record/row-actions/remove.js b/frontend/client/src/views/admin/auth-token/record/row-actions/remove.js index 0ff339b962..16e362cf35 100644 --- a/frontend/client/src/views/admin/auth-token/record/row-actions/remove.js +++ b/frontend/client/src/views/admin/auth-token/record/row-actions/remove.js @@ -21,16 +21,16 @@ Espo.define('Views.Admin.AuthToken.Record.RowActions.Remove', 'View', function (Dep) { - return Dep.extend({ - - _template: '{{translate "Remove"}}', - - data: function () { - return { - id: this.model.id - }; - } + return Dep.extend({ + + _template: '{{translate "Remove"}}', + + data: function () { + return { + id: this.model.id + }; + } - }); + }); }); diff --git a/frontend/client/src/views/admin/authentication.js b/frontend/client/src/views/admin/authentication.js index 5cc9b97607..738fa2ffe4 100644 --- a/frontend/client/src/views/admin/authentication.js +++ b/frontend/client/src/views/admin/authentication.js @@ -19,104 +19,104 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ -Espo.define('Views.Admin.Authentication', 'Views.Settings.Record.Edit', function (Dep) { +Espo.define('Views.Admin.Authentication', 'Views.Settings.Record.Edit', function (Dep) { - return Dep.extend({ - - layoutName: 'authentication', - - dependencyDefs: { - 'ldapAuth': { - map: { - true: [ - { - action: 'show', - fields: ['ldapUsername', 'ldapPassword'] - } - ] - }, - default: [ - { - action: 'hide', - fields: ['ldapUsername', 'ldapPassword'] - } - ] - }, - 'ldapAccountCanonicalForm': { - map: { - 'Backslash': [ - { - action: 'show', - fields: ['ldapAccountDomainName', 'ldapAccountDomainNameShort'] - } - ], - 'Principal': [ - { - action: 'show', - fields: ['ldapAccountDomainName', 'ldapAccountDomainNameShort'] - } - ] - }, - default: [ - { - action: 'hide', - fields: ['ldapAccountDomainName', 'ldapAccountDomainNameShort'] - } - ] - } - }, - - setup: function () { - Dep.prototype.setup.call(this); - - this.methodList = this.getMetadata().get('entityDefs.Settings.fields.authenticationMethod.options') || []; - - this.authFields = { - 'LDAP': [ - 'ldapHost', 'ldapPort', 'ldapAuth', 'ldapSecurity', - 'ldapUsername', 'ldapPassword', 'ldapBindRequiresDn', - 'ldapUserLoginFilter', 'ldapBaseDn', 'ldapAccountCanonicalForm', - 'ldapAccountDomainName', 'ldapAccountDomainNameShort', 'ldapAccountDomainName', - 'ldapAccountDomainNameShort', 'ldapTryUsernameSplit', 'ldapOptReferrals', - 'ldapCreateEspoUser' - ] - }; - }, + return Dep.extend({ + + layoutName: 'authentication', + + dependencyDefs: { + 'ldapAuth': { + map: { + true: [ + { + action: 'show', + fields: ['ldapUsername', 'ldapPassword'] + } + ] + }, + default: [ + { + action: 'hide', + fields: ['ldapUsername', 'ldapPassword'] + } + ] + }, + 'ldapAccountCanonicalForm': { + map: { + 'Backslash': [ + { + action: 'show', + fields: ['ldapAccountDomainName', 'ldapAccountDomainNameShort'] + } + ], + 'Principal': [ + { + action: 'show', + fields: ['ldapAccountDomainName', 'ldapAccountDomainNameShort'] + } + ] + }, + default: [ + { + action: 'hide', + fields: ['ldapAccountDomainName', 'ldapAccountDomainNameShort'] + } + ] + } + }, + + setup: function () { + Dep.prototype.setup.call(this); + + this.methodList = this.getMetadata().get('entityDefs.Settings.fields.authenticationMethod.options') || []; + + this.authFields = { + 'LDAP': [ + 'ldapHost', 'ldapPort', 'ldapAuth', 'ldapSecurity', + 'ldapUsername', 'ldapPassword', 'ldapBindRequiresDn', + 'ldapUserLoginFilter', 'ldapBaseDn', 'ldapAccountCanonicalForm', + 'ldapAccountDomainName', 'ldapAccountDomainNameShort', 'ldapAccountDomainName', + 'ldapAccountDomainNameShort', 'ldapTryUsernameSplit', 'ldapOptReferrals', + 'ldapCreateEspoUser' + ] + }; + }, - - afterRender: function () { - this.handlePanelsVisibility(); - this.listenTo(this.model, 'change:authenticationMethod', function () { - this.handlePanelsVisibility(); - }, this); - }, - - handlePanelsVisibility: function () { - var authenticationMethod = this.model.get('authenticationMethod'); + + afterRender: function () { + this.handlePanelsVisibility(); + this.listenTo(this.model, 'change:authenticationMethod', function () { + this.handlePanelsVisibility(); + }, this); + }, + + handlePanelsVisibility: function () { + var authenticationMethod = this.model.get('authenticationMethod'); - this.methodList.forEach(function (method) { - var list = (this.authFields[method] || []); - if (method != authenticationMethod) { - this.$el.find('.panel[data-panel-name="'+method+'"]').addClass('hidden'); - list.forEach(function (field) { - this.hideField(field); - }, this); - } else { - this.$el.find('.panel[data-panel-name="'+method+'"]').removeClass('hidden'); - - list.forEach(function (field) { - this.showField(field); - }, this); - Object.keys(this.dependencyDefs || {}).forEach(function (attr) { - if (~list.indexOf(attr)) { - this._handleDependencyAttribute(attr); - } - }, this); - } - }, this); - }, - - }); - + this.methodList.forEach(function (method) { + var list = (this.authFields[method] || []); + if (method != authenticationMethod) { + this.$el.find('.panel[data-panel-name="'+method+'"]').addClass('hidden'); + list.forEach(function (field) { + this.hideField(field); + }, this); + } else { + this.$el.find('.panel[data-panel-name="'+method+'"]').removeClass('hidden'); + + list.forEach(function (field) { + this.showField(field); + }, this); + Object.keys(this.dependencyDefs || {}).forEach(function (attr) { + if (~list.indexOf(attr)) { + this._handleDependencyAttribute(attr); + } + }, this); + } + }, this); + }, + + }); + }); diff --git a/frontend/client/src/views/admin/currency.js b/frontend/client/src/views/admin/currency.js index ba09af2a97..348a4348ac 100644 --- a/frontend/client/src/views/admin/currency.js +++ b/frontend/client/src/views/admin/currency.js @@ -19,51 +19,51 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ -Espo.define('Views.Admin.Currency', 'Views.Settings.Record.Edit', function (Dep) { +Espo.define('Views.Admin.Currency', 'Views.Settings.Record.Edit', function (Dep) { - return Dep.extend({ - - layoutName: 'currency', - - setup: function () { - Dep.prototype.setup.call(this); - }, - - afterRender: function () { - var currencyListField = this.getFieldView('currencyList'); - var defaultCurrencyField = this.getFieldView('defaultCurrency'); - var baseCurrencyField = this.getFieldView('baseCurrency'); - - var currencyRatesField = this.getFieldView('currencyRates'); - - if (currencyListField) { - this.listenTo(currencyListField, 'change', function () { - var data = currencyListField.fetch(); - var options = data.currencyList; - if (defaultCurrencyField) { - defaultCurrencyField.params.options = options; - defaultCurrencyField.render(); - } - if (baseCurrencyField) { - baseCurrencyField.params.options = options; - baseCurrencyField.render(); - } - if (currencyRatesField) { - currencyRatesField.render(); - } - }, this); - } - - if (baseCurrencyField) { - this.listenTo(baseCurrencyField, 'change', function () { - if (currencyRatesField) { - currencyRatesField.render(); - } - }, this); - } - }, - - }); - + return Dep.extend({ + + layoutName: 'currency', + + setup: function () { + Dep.prototype.setup.call(this); + }, + + afterRender: function () { + var currencyListField = this.getFieldView('currencyList'); + var defaultCurrencyField = this.getFieldView('defaultCurrency'); + var baseCurrencyField = this.getFieldView('baseCurrency'); + + var currencyRatesField = this.getFieldView('currencyRates'); + + if (currencyListField) { + this.listenTo(currencyListField, 'change', function () { + var data = currencyListField.fetch(); + var options = data.currencyList; + if (defaultCurrencyField) { + defaultCurrencyField.params.options = options; + defaultCurrencyField.render(); + } + if (baseCurrencyField) { + baseCurrencyField.params.options = options; + baseCurrencyField.render(); + } + if (currencyRatesField) { + currencyRatesField.render(); + } + }, this); + } + + if (baseCurrencyField) { + this.listenTo(baseCurrencyField, 'change', function () { + if (currencyRatesField) { + currencyRatesField.render(); + } + }, this); + } + }, + + }); + }); diff --git a/frontend/client/src/views/admin/extensions/done.js b/frontend/client/src/views/admin/extensions/done.js index 8ecbca0822..6ac20a37a5 100644 --- a/frontend/client/src/views/admin/extensions/done.js +++ b/frontend/client/src/views/admin/extensions/done.js @@ -21,40 +21,40 @@ Espo.define('Views.Admin.Extensions.Done', 'Views.Modal', function (Dep) { - return Dep.extend({ - - cssName: 'done-modal', - - header: false, - - template: 'admin.extensions.done', - - createButton: true, - - data: function () { - return { - version: this.options.version, - name: this.options.name, - text: this.translate('extensionInstalled', 'messages', 'Admin').replace('{version}', this.options.version) - .replace('{name}', this.options.name) - }; - }, - - setup: function () { - this.buttons = [ - { - name: 'close', - label: 'Close', - onClick: function (dialog) { - dialog.close(); - }.bind(this) - } - ]; - - this.header = this.getLanguage().translate('Installed successfully', 'labels', 'Admin'); - - }, - - }); + return Dep.extend({ + + cssName: 'done-modal', + + header: false, + + template: 'admin.extensions.done', + + createButton: true, + + data: function () { + return { + version: this.options.version, + name: this.options.name, + text: this.translate('extensionInstalled', 'messages', 'Admin').replace('{version}', this.options.version) + .replace('{name}', this.options.name) + }; + }, + + setup: function () { + this.buttons = [ + { + name: 'close', + label: 'Close', + onClick: function (dialog) { + dialog.close(); + }.bind(this) + } + ]; + + this.header = this.getLanguage().translate('Installed successfully', 'labels', 'Admin'); + + }, + + }); }); diff --git a/frontend/client/src/views/admin/extensions/index.js b/frontend/client/src/views/admin/extensions/index.js index de7c8b3cfe..e00282c4e2 100644 --- a/frontend/client/src/views/admin/extensions/index.js +++ b/frontend/client/src/views/admin/extensions/index.js @@ -19,185 +19,185 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ -Espo.define('Views.Admin.Extensions.Index', 'View', function (Dep) { +Espo.define('Views.Admin.Extensions.Index', 'View', function (Dep) { - return Dep.extend({ - - template: "admin.extensions.index", - - packageContents: null, - - events: { - 'change input[name="package"]': function (e) { - this.$el.find('button[data-action="upload"]').addClass('disabled'); - this.$el.find('.message-container').html(''); - var files = e.currentTarget.files; - if (files.length) { - this.selectFile(files[0]); - } - }, - 'click button[data-action="upload"]': function () { - this.upload(); - }, - 'click [data-action="install"]': function (e) { - var id = $(e.currentTarget).data('id'); - - var name = this.collection.get(id).get('name'); - var version = this.collection.get(id).get('version'); - - this.run(id, name, version); - - }, - 'click [data-action="uninstall"]': function (e) { - var id = $(e.currentTarget).data('id'); - - var name = this.collection.get(id).get('name'); - - var self = this; - if (confirm(this.translate('uninstallConfirmation', 'messages', 'Admin'))) { - Espo.Ui.notify(this.translate('Uninstalling...', 'labels', 'Admin')); - - $.ajax({ - url: 'Extension/action/uninstall', - type: 'POST', - data: JSON.stringify({ - id: id - }), - error: function (xhr) { - var msg = xhr.getResponseHeader('X-Status-Reason'); - this.showErrorNotification(this.translate('Error') + ': ' + msg); - }.bind(this) - }).done(function () { - this.listenToOnce(this.collection, 'sync', function () { - Espo.Ui.success(this.translate('uninstalled', 'messages', 'Extension').replace('{name}', name)); - }, this); - this.collection.fetch(); - - }.bind(this)); - } - } - }, - - setup: function () { - this.getCollectionFactory().create('Extension', function (collection) { - this.collection = collection; - - collection.maxSize = this.getConfig().get('recordsPerPage'); - - this.wait(true); - this.listenToOnce(collection, 'sync', function () { - this.createView('list', 'Extension.Record.List', { - collection: collection, - el: this.options.el + ' > .list-container', - }); - if (collection.length == 0) { - this.once('after:render', function () { - this.$el.find('.list-container').addClass('hidden'); - }.bind(this)); - } - this.wait(false); - }); - - collection.fetch(); - - }, this); - }, - - selectFile: function (file) { - var fileReader = new FileReader(); - fileReader.onload = function (e) { - this.packageContents = e.target.result; - this.$el.find('button[data-action="upload"]').removeClass('disabled'); - }.bind(this); - fileReader.readAsDataURL(file); - }, - - showError: function (msg) { - msg = this.translate(msg, 'errors', 'Admin'); - this.$el.find('.message-container').html(msg); - }, - - showErrorNotification: function (msg) { - if (!msg) { - this.$el.find('.notify-text').addClass('hidden'); - } else { - msg = this.translate(msg, 'errors', 'Admin'); - this.$el.find('.notify-text').html(msg); - this.$el.find('.notify-text').removeClass('hidden'); - } - }, - - upload: function () { - this.$el.find('button[data-action="upload"]').addClass('disabled'); - this.notify('Uploading...'); - $.ajax({ - url: 'Extension/action/upload', - type: 'POST', - contentType: 'application/zip', - timeout: 0, - data: this.packageContents, - error: function (xhr, t, e) { - this.showError(xhr.getResponseHeader('X-Status-Reason')); - this.notify(false); - }.bind(this) - }).done(function (data) { - if (!data.id) { - this.showError(this.translate('Error occured')); - return; - } - this.notify(false); - this.createView('popup', 'Admin.Extensions.Ready', { - upgradeData: data - }, function (view) { - view.render(); - this.$el.find('button[data-action="upload"]').removeClass('disabled'); - - view.once('run', function () { - view.close(); - this.$el.find('.panel.upload').addClass('hidden'); - this.run(data.id, data.version, data.name); - }, this); - }.bind(this)); - }.bind(this)).error; - }, - - run: function (id, version, name) { - var msg = this.translate('Installing...', 'labels', 'Admin'); - this.notify('Please wait...'); - - this.showError(false); - this.showErrorNotification(false); - - $.ajax({ - url: 'Extension/action/install', - type: 'POST', - data: JSON.stringify({ - id: id - }), - error: function (xhr) { - this.$el.find('.panel.upload').removeClass('hidden'); - var msg = xhr.getResponseHeader('X-Status-Reason'); - this.showErrorNotification(this.translate('Error') + ': ' + msg); - }.bind(this) - }).done(function () { - var cache = this.getCache(); - if (cache) { - cache.clear(); - } - this.createView('popup', 'Admin.Extensions.Done', { - version: version, - name: name - }, function (view) { - this.collection.fetch(); - this.$el.find('.list-container').removeClass('hidden'); - this.$el.find('.panel.upload').removeClass('hidden'); - this.notify(false); - view.render(); - }.bind(this)); - }.bind(this)); - }, - - }); - + return Dep.extend({ + + template: "admin.extensions.index", + + packageContents: null, + + events: { + 'change input[name="package"]': function (e) { + this.$el.find('button[data-action="upload"]').addClass('disabled'); + this.$el.find('.message-container').html(''); + var files = e.currentTarget.files; + if (files.length) { + this.selectFile(files[0]); + } + }, + 'click button[data-action="upload"]': function () { + this.upload(); + }, + 'click [data-action="install"]': function (e) { + var id = $(e.currentTarget).data('id'); + + var name = this.collection.get(id).get('name'); + var version = this.collection.get(id).get('version'); + + this.run(id, name, version); + + }, + 'click [data-action="uninstall"]': function (e) { + var id = $(e.currentTarget).data('id'); + + var name = this.collection.get(id).get('name'); + + var self = this; + if (confirm(this.translate('uninstallConfirmation', 'messages', 'Admin'))) { + Espo.Ui.notify(this.translate('Uninstalling...', 'labels', 'Admin')); + + $.ajax({ + url: 'Extension/action/uninstall', + type: 'POST', + data: JSON.stringify({ + id: id + }), + error: function (xhr) { + var msg = xhr.getResponseHeader('X-Status-Reason'); + this.showErrorNotification(this.translate('Error') + ': ' + msg); + }.bind(this) + }).done(function () { + this.listenToOnce(this.collection, 'sync', function () { + Espo.Ui.success(this.translate('uninstalled', 'messages', 'Extension').replace('{name}', name)); + }, this); + this.collection.fetch(); + + }.bind(this)); + } + } + }, + + setup: function () { + this.getCollectionFactory().create('Extension', function (collection) { + this.collection = collection; + + collection.maxSize = this.getConfig().get('recordsPerPage'); + + this.wait(true); + this.listenToOnce(collection, 'sync', function () { + this.createView('list', 'Extension.Record.List', { + collection: collection, + el: this.options.el + ' > .list-container', + }); + if (collection.length == 0) { + this.once('after:render', function () { + this.$el.find('.list-container').addClass('hidden'); + }.bind(this)); + } + this.wait(false); + }); + + collection.fetch(); + + }, this); + }, + + selectFile: function (file) { + var fileReader = new FileReader(); + fileReader.onload = function (e) { + this.packageContents = e.target.result; + this.$el.find('button[data-action="upload"]').removeClass('disabled'); + }.bind(this); + fileReader.readAsDataURL(file); + }, + + showError: function (msg) { + msg = this.translate(msg, 'errors', 'Admin'); + this.$el.find('.message-container').html(msg); + }, + + showErrorNotification: function (msg) { + if (!msg) { + this.$el.find('.notify-text').addClass('hidden'); + } else { + msg = this.translate(msg, 'errors', 'Admin'); + this.$el.find('.notify-text').html(msg); + this.$el.find('.notify-text').removeClass('hidden'); + } + }, + + upload: function () { + this.$el.find('button[data-action="upload"]').addClass('disabled'); + this.notify('Uploading...'); + $.ajax({ + url: 'Extension/action/upload', + type: 'POST', + contentType: 'application/zip', + timeout: 0, + data: this.packageContents, + error: function (xhr, t, e) { + this.showError(xhr.getResponseHeader('X-Status-Reason')); + this.notify(false); + }.bind(this) + }).done(function (data) { + if (!data.id) { + this.showError(this.translate('Error occured')); + return; + } + this.notify(false); + this.createView('popup', 'Admin.Extensions.Ready', { + upgradeData: data + }, function (view) { + view.render(); + this.$el.find('button[data-action="upload"]').removeClass('disabled'); + + view.once('run', function () { + view.close(); + this.$el.find('.panel.upload').addClass('hidden'); + this.run(data.id, data.version, data.name); + }, this); + }.bind(this)); + }.bind(this)).error; + }, + + run: function (id, version, name) { + var msg = this.translate('Installing...', 'labels', 'Admin'); + this.notify('Please wait...'); + + this.showError(false); + this.showErrorNotification(false); + + $.ajax({ + url: 'Extension/action/install', + type: 'POST', + data: JSON.stringify({ + id: id + }), + error: function (xhr) { + this.$el.find('.panel.upload').removeClass('hidden'); + var msg = xhr.getResponseHeader('X-Status-Reason'); + this.showErrorNotification(this.translate('Error') + ': ' + msg); + }.bind(this) + }).done(function () { + var cache = this.getCache(); + if (cache) { + cache.clear(); + } + this.createView('popup', 'Admin.Extensions.Done', { + version: version, + name: name + }, function (view) { + this.collection.fetch(); + this.$el.find('.list-container').removeClass('hidden'); + this.$el.find('.panel.upload').removeClass('hidden'); + this.notify(false); + view.render(); + }.bind(this)); + }.bind(this)); + }, + + }); + }); diff --git a/frontend/client/src/views/admin/extensions/ready.js b/frontend/client/src/views/admin/extensions/ready.js index b951f08962..b5d30ca25f 100644 --- a/frontend/client/src/views/admin/extensions/ready.js +++ b/frontend/client/src/views/admin/extensions/ready.js @@ -21,54 +21,54 @@ Espo.define('Views.Admin.Extensions.Ready', 'Views.Modal', function (Dep) { - return Dep.extend({ - - cssName: 'ready-modal', - - header: false, - - template: 'admin.extensions.ready', - - createButton: true, - - data: function () { - return { - version: this.upgradeData.version, - text: this.translate('installExtension', 'messages', 'Admin').replace('{version}', this.upgradeData.version) - .replace('{name}', this.upgradeData.name) - }; - }, - - setup: function () { - - this.buttons = [ - { - name: 'run', - text: this.translate('Install', 'labels', 'Admin'), - style: 'danger', - onClick: function (dialog) { - this.run(); - }.bind(this) - }, - { - name: 'cancel', - label: 'Cancel', - onClick: function (dialog) { - dialog.close(); - } - } - ]; - - this.upgradeData = this.options.upgradeData; - - this.header = this.getLanguage().translate('Ready for installation', 'labels', 'Admin'); - - }, - - run: function () { - this.trigger('run'); - this.remove(); - } - }); + return Dep.extend({ + + cssName: 'ready-modal', + + header: false, + + template: 'admin.extensions.ready', + + createButton: true, + + data: function () { + return { + version: this.upgradeData.version, + text: this.translate('installExtension', 'messages', 'Admin').replace('{version}', this.upgradeData.version) + .replace('{name}', this.upgradeData.name) + }; + }, + + setup: function () { + + this.buttons = [ + { + name: 'run', + text: this.translate('Install', 'labels', 'Admin'), + style: 'danger', + onClick: function (dialog) { + this.run(); + }.bind(this) + }, + { + name: 'cancel', + label: 'Cancel', + onClick: function (dialog) { + dialog.close(); + } + } + ]; + + this.upgradeData = this.options.upgradeData; + + this.header = this.getLanguage().translate('Ready for installation', 'labels', 'Admin'); + + }, + + run: function () { + this.trigger('run'); + this.remove(); + } + }); }); diff --git a/frontend/client/src/views/admin/field-manager/edit.js b/frontend/client/src/views/admin/field-manager/edit.js index 1a7f0337b7..1c77e68dd9 100644 --- a/frontend/client/src/views/admin/field-manager/edit.js +++ b/frontend/client/src/views/admin/field-manager/edit.js @@ -20,170 +20,170 @@ ************************************************************************/ Espo.define('Views.Admin.FieldManager.Edit', 'View', function (Dep) { - - return Dep.extend({ - - template: 'admin.field-manager.edit', - - data: function () { - return { - scope: this.scope, - field: this.field, - defs: this.defs, - params: this.params, - type: this.type, - fieldList: this.fieldList, - }; - }, - - events: { - 'click button[data-action="cancel"]': function () { - this.getRouter().navigate('#Admin/fieldManager/scope=' + this.scope, {trigger: true}); - }, - 'click button[data-action="save"]': function () { - this.save(); - }, - }, - - setup: function () { - this.scope = this.options.scope; - this.field = this.options.field; - this.type = this.options.type; - this.defs = {}; - - this.fieldList = []; - - this.isNew = false; - if (!this.field) { - this.isNew = true; - } - - this.model = new Espo.Model(); - this.model.name = 'Admin'; - this.model.urlRoot = 'Admin/fieldManager/' + this.scope; - - this.model.defs = { - fields: { - name: {required: true}, - label: {required: true}, - }, - }; - - if (!this.isNew) { - this.model.id = this.field; - this.model.set('name', this.field); - this.model.set('label', this.getLanguage().translate(this.field, 'fields', this.scope)); - } else { - this.model.set('type', this.type); - } + + return Dep.extend({ + + template: 'admin.field-manager.edit', + + data: function () { + return { + scope: this.scope, + field: this.field, + defs: this.defs, + params: this.params, + type: this.type, + fieldList: this.fieldList, + }; + }, + + events: { + 'click button[data-action="cancel"]': function () { + this.getRouter().navigate('#Admin/fieldManager/scope=' + this.scope, {trigger: true}); + }, + 'click button[data-action="save"]': function () { + this.save(); + }, + }, + + setup: function () { + this.scope = this.options.scope; + this.field = this.options.field; + this.type = this.options.type; + this.defs = {}; + + this.fieldList = []; + + this.isNew = false; + if (!this.field) { + this.isNew = true; + } + + this.model = new Espo.Model(); + this.model.name = 'Admin'; + this.model.urlRoot = 'Admin/fieldManager/' + this.scope; + + this.model.defs = { + fields: { + name: {required: true}, + label: {required: true}, + }, + }; + + if (!this.isNew) { + this.model.id = this.field; + this.model.set('name', this.field); + this.model.set('label', this.getLanguage().translate(this.field, 'fields', this.scope)); + } else { + this.model.set('type', this.type); + } - - this.wait(true); - this.getModelFactory().create(this.scope, function (model) { - - if (!this.isNew) { - this.type = model.getFieldType(this.field); - this.defs = model.defs.fields[this.field]; - } - - - - this.params = this.getFieldManager().getParams(this.type) || []; - - this.params.forEach(function (o) { - this.model.defs.fields[o.name] = o; - }, this); - - this.model.set(this.defs); - - if (this.isNew) { - this.model.populateDefaults(); - } - - this.createFieldView('varchar', 'name', !this.isNew); - this.createFieldView('varchar', 'label'); - + + this.wait(true); + this.getModelFactory().create(this.scope, function (model) { + + if (!this.isNew) { + this.type = model.getFieldType(this.field); + this.defs = model.defs.fields[this.field]; + } + + + + this.params = this.getFieldManager().getParams(this.type) || []; + + this.params.forEach(function (o) { + this.model.defs.fields[o.name] = o; + }, this); + + this.model.set(this.defs); + + if (this.isNew) { + this.model.populateDefaults(); + } + + this.createFieldView('varchar', 'name', !this.isNew); + this.createFieldView('varchar', 'label'); + - - this.getView('name').on('change', function (m) { - var name = this.model.get('name'); - this.model.set('label', name); - if (name) { - name = name.replace('-', '').replace(/[^\w\s]/gi, '').replace(/ (.)/g, function(match, g) { - return g.toUpperCase(); - }).replace(' ', ''); - if (name.length) { - name = name.charAt(0).toLowerCase() + name.slice(1); - } - } - this.model.set('name', name); - }, this); - - this.params.forEach(function (o) { - if (o.hidden) { - return; - } - this.createFieldView(o.type, o.name, null, o); - }, this); - - - this.wait(false); - }.bind(this)); - - }, - - createFieldView: function (type, name, readOnly, params) { - this.createView(name, this.getFieldManager().getViewName(type), { - model: this.model, - el: this.options.el + ' .field-' + name, - defs: { - name: name, - params: params - }, - mode: readOnly ? 'detail' : 'edit', - readOnly: readOnly, - }); - this.fieldList.push(name); - }, - - save: function () { - this.fieldList.forEach(function (field) { - var view = this.getView(field); - if (!view.readOnly) { - view.fetchToModel(); - } - }, this); - - var notValid = false; - this.fieldList.forEach(function (field) { - notValid = this.getView(field).validate() || notValid; - }, this); - - if (notValid) { - this.notify('Not valid', 'error'); - return; - } - - this.listenToOnce(this.model, 'sync', function () { - this.getMetadata().data['entityDefs'][this.scope]['fields'][this.model.get('name')] = this.model.toJSON(); - this.getMetadata().storeToCache(); - this.notify('Saved', 'success'); - - var data = this.getLanguage().data; - if (this.scope in data) { - if (!('fields' in data[this.scope])) { - data[this.scope]['fields'] = {}; - } - data[this.scope]['fields'][this.model.get('name')] = this.model.get('label'); - } - - this.getRouter().navigate('#Admin/fieldManager/scope=' + this.scope + '&field=' + this.model.get('name'), {trigger: true}); - }.bind(this)); - - this.notify('Saving...'); - this.model.save(); - }, - - }); + + this.getView('name').on('change', function (m) { + var name = this.model.get('name'); + this.model.set('label', name); + if (name) { + name = name.replace('-', '').replace(/[^\w\s]/gi, '').replace(/ (.)/g, function(match, g) { + return g.toUpperCase(); + }).replace(' ', ''); + if (name.length) { + name = name.charAt(0).toLowerCase() + name.slice(1); + } + } + this.model.set('name', name); + }, this); + + this.params.forEach(function (o) { + if (o.hidden) { + return; + } + this.createFieldView(o.type, o.name, null, o); + }, this); + + + this.wait(false); + }.bind(this)); + + }, + + createFieldView: function (type, name, readOnly, params) { + this.createView(name, this.getFieldManager().getViewName(type), { + model: this.model, + el: this.options.el + ' .field-' + name, + defs: { + name: name, + params: params + }, + mode: readOnly ? 'detail' : 'edit', + readOnly: readOnly, + }); + this.fieldList.push(name); + }, + + save: function () { + this.fieldList.forEach(function (field) { + var view = this.getView(field); + if (!view.readOnly) { + view.fetchToModel(); + } + }, this); + + var notValid = false; + this.fieldList.forEach(function (field) { + notValid = this.getView(field).validate() || notValid; + }, this); + + if (notValid) { + this.notify('Not valid', 'error'); + return; + } + + this.listenToOnce(this.model, 'sync', function () { + this.getMetadata().data['entityDefs'][this.scope]['fields'][this.model.get('name')] = this.model.toJSON(); + this.getMetadata().storeToCache(); + this.notify('Saved', 'success'); + + var data = this.getLanguage().data; + if (this.scope in data) { + if (!('fields' in data[this.scope])) { + data[this.scope]['fields'] = {}; + } + data[this.scope]['fields'][this.model.get('name')] = this.model.get('label'); + } + + this.getRouter().navigate('#Admin/fieldManager/scope=' + this.scope + '&field=' + this.model.get('name'), {trigger: true}); + }.bind(this)); + + this.notify('Saving...'); + this.model.save(); + }, + + }); }); diff --git a/frontend/client/src/views/admin/field-manager/index.js b/frontend/client/src/views/admin/field-manager/index.js index 9a018c931f..12a3ae489a 100644 --- a/frontend/client/src/views/admin/field-manager/index.js +++ b/frontend/client/src/views/admin/field-manager/index.js @@ -21,148 +21,148 @@ Espo.define('Views.Admin.FieldManager.Index', 'View', function (Dep) { - return Dep.extend({ + return Dep.extend({ - template: 'admin.field-manager.index', + template: 'admin.field-manager.index', - scopeList: null, + scopeList: null, - scope: null, + scope: null, - type: null, + type: null, - data: function () { - return { - scopeList: this.scopeList, - scope: this.scope, - }; - }, + data: function () { + return { + scopeList: this.scopeList, + scope: this.scope, + }; + }, - events: { - 'click #scopes-menu a.scope-link': function (e) { - var scope = $(e.currentTarget).data('scope'); - this.openScope(scope); - }, - - 'click #fields-content a.field-link': function (e) { - var scope = $(e.currentTarget).data('scope'); - var field = $(e.currentTarget).data('field'); - this.openField(scope, field); - }, - - 'click a[data-action="addField"]': function (e) { - var scope = $(e.currentTarget).data('scope'); - var type = $(e.currentTarget).data('type'); - this.createField(scope, type); - }, - }, + events: { + 'click #scopes-menu a.scope-link': function (e) { + var scope = $(e.currentTarget).data('scope'); + this.openScope(scope); + }, + + 'click #fields-content a.field-link': function (e) { + var scope = $(e.currentTarget).data('scope'); + var field = $(e.currentTarget).data('field'); + this.openField(scope, field); + }, + + 'click a[data-action="addField"]': function (e) { + var scope = $(e.currentTarget).data('scope'); + var type = $(e.currentTarget).data('type'); + this.createField(scope, type); + }, + }, - setup: function () { - this.scopeList = []; - var scopesAll = Object.keys(this.getMetadata().get('scopes')).sort(); - scopesAll.forEach(function (scope) { - if (this.getMetadata().get('scopes.' + scope + '.entity')) { - if (this.getMetadata().get('scopes.' + scope + '.customizable')) { - this.scopeList.push(scope); - } - } - }.bind(this)); + setup: function () { + this.scopeList = []; + var scopesAll = Object.keys(this.getMetadata().get('scopes')).sort(); + scopesAll.forEach(function (scope) { + if (this.getMetadata().get('scopes.' + scope + '.entity')) { + if (this.getMetadata().get('scopes.' + scope + '.customizable')) { + this.scopeList.push(scope); + } + } + }.bind(this)); - this.scope = this.options.scope || null; - this.field = this.options.field || null; - - this.on('after:render', function () { - this.renderFieldsHeader(); - if (!this.scope) { - this.renderDefaultPage(); - } else { - if (!this.field) { - this.openScope(this.scope); - } else { - this.openField(this.scope, this.field); - } - } - }); - }, + this.scope = this.options.scope || null; + this.field = this.options.field || null; + + this.on('after:render', function () { + this.renderFieldsHeader(); + if (!this.scope) { + this.renderDefaultPage(); + } else { + if (!this.field) { + this.openScope(this.scope); + } else { + this.openField(this.scope, this.field); + } + } + }); + }, - openScope: function (scope) { - this.scope = scope; - this.field = null; - - this.getRouter().navigate('#Admin/fieldManager/scope=' + scope, {trigger: false}); - - this.notify('Loading...'); - this.createView('content', 'Admin.FieldManager.List', { - el: '#fields-content', - scope: scope, - }, function (view) { - this.renderFieldsHeader(); - view.render(); - this.notify(false); - $(window).scrollTop(0); - }.bind(this)); - }, - - openField: function (scope, field) { - this.scope = scope; - this.field = field - - this.getRouter().navigate('#Admin/fieldManager/scope=' + scope + '&field=' + field, {trigger: false}); - - this.notify('Loading...'); - this.createView('content', 'Admin.FieldManager.Edit', { - el: '#fields-content', - scope: scope, - field: field, - }, function (view) { - this.renderFieldsHeader(); - view.render(); - this.notify(false); - $(window).scrollTop(0); - }.bind(this)); - }, - - createField: function (scope, type) { - this.scope = scope; - this.type = type; - - this.getRouter().navigate('#Admin/fieldManager/scope=' + scope + '&type=' + type + '&create=true', {trigger: false}); - - this.notify('Loading...'); - this.createView('content', 'Admin.FieldManager.Edit', { - el: '#fields-content', - scope: scope, - type: type, - }, function (view) { - this.renderFieldsHeader(); - view.render(); - this.notify(false); - $(window).scrollTop(0); - }.bind(this)); - }, + openScope: function (scope) { + this.scope = scope; + this.field = null; + + this.getRouter().navigate('#Admin/fieldManager/scope=' + scope, {trigger: false}); + + this.notify('Loading...'); + this.createView('content', 'Admin.FieldManager.List', { + el: '#fields-content', + scope: scope, + }, function (view) { + this.renderFieldsHeader(); + view.render(); + this.notify(false); + $(window).scrollTop(0); + }.bind(this)); + }, + + openField: function (scope, field) { + this.scope = scope; + this.field = field + + this.getRouter().navigate('#Admin/fieldManager/scope=' + scope + '&field=' + field, {trigger: false}); + + this.notify('Loading...'); + this.createView('content', 'Admin.FieldManager.Edit', { + el: '#fields-content', + scope: scope, + field: field, + }, function (view) { + this.renderFieldsHeader(); + view.render(); + this.notify(false); + $(window).scrollTop(0); + }.bind(this)); + }, + + createField: function (scope, type) { + this.scope = scope; + this.type = type; + + this.getRouter().navigate('#Admin/fieldManager/scope=' + scope + '&type=' + type + '&create=true', {trigger: false}); + + this.notify('Loading...'); + this.createView('content', 'Admin.FieldManager.Edit', { + el: '#fields-content', + scope: scope, + type: type, + }, function (view) { + this.renderFieldsHeader(); + view.render(); + this.notify(false); + $(window).scrollTop(0); + }.bind(this)); + }, - renderDefaultPage: function () { - $('#fields-header').html('').hide(); - $('#fields-content').html(this.translate('selectEntityType', 'messages', 'Admin')); - }, + renderDefaultPage: function () { + $('#fields-header').html('').hide(); + $('#fields-content').html(this.translate('selectEntityType', 'messages', 'Admin')); + }, - renderFieldsHeader: function () { - if (!this.scope) { - $('#fields-header').html(''); - return; - } - - if (this.field) { - $('#fields-header').show().html('' + this.getLanguage().translate(this.scope, 'scopeNamesPlural') + ' » ' + this.field); - } else { - $('#fields-header').show().html(this.getLanguage().translate(this.scope, 'scopeNamesPlural')); - } - }, + renderFieldsHeader: function () { + if (!this.scope) { + $('#fields-header').html(''); + return; + } + + if (this.field) { + $('#fields-header').show().html('' + this.getLanguage().translate(this.scope, 'scopeNamesPlural') + ' » ' + this.field); + } else { + $('#fields-header').show().html(this.getLanguage().translate(this.scope, 'scopeNamesPlural')); + } + }, - updatePageTitle: function () { - this.setPageTitle(this.getLanguage().translate('Field Manager')); - }, - }); + updatePageTitle: function () { + this.setPageTitle(this.getLanguage().translate('Field Manager')); + }, + }); }); diff --git a/frontend/client/src/views/admin/field-manager/list.js b/frontend/client/src/views/admin/field-manager/list.js index 8c71a8ffcc..a65757dc43 100644 --- a/frontend/client/src/views/admin/field-manager/list.js +++ b/frontend/client/src/views/admin/field-manager/list.js @@ -20,82 +20,82 @@ ************************************************************************/ Espo.define('Views.Admin.FieldManager.List', 'View', function (Dep) { - - return Dep.extend({ - - template: 'admin.field-manager.list', - - data: function () { - return { - scope: this.scope, - fieldDefsArray: this.fieldDefsArray, - typeList: this.typeList - }; - }, - - events: { - 'click [data-action="removeField"]': function (e) { - var field = $(e.currentTarget).data('name'); - - if (confirm(this.translate('confirmation', 'messages'))) { - this.notify('Removing...'); - $.ajax({ - url: 'Admin/fieldManager/' + this.scope + '/' + field, - type: 'DELETE', - success: function () { - this.notify('Removed', 'success'); - var data = this.getMetadata().data; - delete data['entityDefs'][this.scope]['fields'][field]; - this.getMetadata().storeToCache(); - $(e.currentTarget).closest('tr').remove(); - }.bind(this), - }); - } - } - }, - - setup: function () { - this.scope = this.options.scope; - - this.typeList = []; - - var fieldDefs = this.getMetadata().get('fields'); - - Object.keys(this.getMetadata().get('fields')).forEach(function (type) { - if (type in fieldDefs) { - if (!fieldDefs[type].notCreatable) { - this.typeList.push(type); - } - } - }, this); - - - - - - this.wait(true); - this.getModelFactory().create(this.scope, function (model) { - - this.fields = model.defs.fields; - - this.fieldList = Object.keys(this.fields).sort(); - - this.fieldDefsArray = []; - this.fieldList.forEach(function (field) { - var defs = this.fields[field]; - this.fieldDefsArray.push({ - name: field, - isCustom: defs.isCustom || false, - type: defs.type - }); - }, this); + + return Dep.extend({ + + template: 'admin.field-manager.list', + + data: function () { + return { + scope: this.scope, + fieldDefsArray: this.fieldDefsArray, + typeList: this.typeList + }; + }, + + events: { + 'click [data-action="removeField"]': function (e) { + var field = $(e.currentTarget).data('name'); + + if (confirm(this.translate('confirmation', 'messages'))) { + this.notify('Removing...'); + $.ajax({ + url: 'Admin/fieldManager/' + this.scope + '/' + field, + type: 'DELETE', + success: function () { + this.notify('Removed', 'success'); + var data = this.getMetadata().data; + delete data['entityDefs'][this.scope]['fields'][field]; + this.getMetadata().storeToCache(); + $(e.currentTarget).closest('tr').remove(); + }.bind(this), + }); + } + } + }, + + setup: function () { + this.scope = this.options.scope; + + this.typeList = []; + + var fieldDefs = this.getMetadata().get('fields'); + + Object.keys(this.getMetadata().get('fields')).forEach(function (type) { + if (type in fieldDefs) { + if (!fieldDefs[type].notCreatable) { + this.typeList.push(type); + } + } + }, this); + + + + + + this.wait(true); + this.getModelFactory().create(this.scope, function (model) { + + this.fields = model.defs.fields; + + this.fieldList = Object.keys(this.fields).sort(); + + this.fieldDefsArray = []; + this.fieldList.forEach(function (field) { + var defs = this.fields[field]; + this.fieldDefsArray.push({ + name: field, + isCustom: defs.isCustom || false, + type: defs.type + }); + }, this); - - this.wait(false); - }.bind(this)); - - }, - - }); + + this.wait(false); + }.bind(this)); + + }, + + }); }); diff --git a/frontend/client/src/views/admin/index.js b/frontend/client/src/views/admin/index.js index f0994524a4..db19ccfe53 100644 --- a/frontend/client/src/views/admin/index.js +++ b/frontend/client/src/views/admin/index.js @@ -19,24 +19,24 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ Espo.define('Views.Admin.Index', 'View', function (Dep) { - - return Dep.extend({ - - template: 'admin.index', - - data: function () { - return { - links: this.links - }; - }, - - setup: function () { - this.links = this.getMetadata().get('app.adminPanel'); - }, - - updatePageTitle: function () { - this.setPageTitle(this.getLanguage().translate('Administration')); - }, - - }); + + return Dep.extend({ + + template: 'admin.index', + + data: function () { + return { + links: this.links + }; + }, + + setup: function () { + this.links = this.getMetadata().get('app.adminPanel'); + }, + + updatePageTitle: function () { + this.setPageTitle(this.getLanguage().translate('Administration')); + }, + + }); }); diff --git a/frontend/client/src/views/admin/integrations/edit.js b/frontend/client/src/views/admin/integrations/edit.js index 272bbbefa9..d456496e6f 100644 --- a/frontend/client/src/views/admin/integrations/edit.js +++ b/frontend/client/src/views/admin/integrations/edit.js @@ -20,155 +20,155 @@ ************************************************************************/ Espo.define('Views.Admin.Integrations.Edit', 'View', function (Dep) { - - return Dep.extend({ - - template: 'admin.integrations.edit', - - data: function () { - return { - integration: this.integration, - dataFieldList: this.dataFieldList, - helpText: this.helpText - }; - }, - - events: { - 'click button[data-action="cancel"]': function () { - this.getRouter().navigate('#Admin/integrations', {trigger: true}); - }, - 'click button[data-action="save"]': function () { - this.save(); - }, - }, - - setup: function () { - this.integration = this.options.integration; - - this.helpText = false; - if (this.getLanguage().has(this.integration, 'help', 'Integration')) { - this.helpText = this.translate(this.integration, 'help', 'Integration'); - } - - this.fieldList = []; - - this.dataFieldList = []; - - this.model = new Espo.Model(); - this.model.id = this.integration; - this.model.name = 'Integration'; - this.model.urlRoot = 'Integration'; - - this.model.defs = { - fields: { - enabled: { - required: true, - type: 'bool' - }, - } - }; - - this.wait(true); - - var fields = this.fields = this.getMetadata().get('integrations.' + this.integration + '.fields'); + + return Dep.extend({ + + template: 'admin.integrations.edit', + + data: function () { + return { + integration: this.integration, + dataFieldList: this.dataFieldList, + helpText: this.helpText + }; + }, + + events: { + 'click button[data-action="cancel"]': function () { + this.getRouter().navigate('#Admin/integrations', {trigger: true}); + }, + 'click button[data-action="save"]': function () { + this.save(); + }, + }, + + setup: function () { + this.integration = this.options.integration; + + this.helpText = false; + if (this.getLanguage().has(this.integration, 'help', 'Integration')) { + this.helpText = this.translate(this.integration, 'help', 'Integration'); + } + + this.fieldList = []; + + this.dataFieldList = []; + + this.model = new Espo.Model(); + this.model.id = this.integration; + this.model.name = 'Integration'; + this.model.urlRoot = 'Integration'; + + this.model.defs = { + fields: { + enabled: { + required: true, + type: 'bool' + }, + } + }; + + this.wait(true); + + var fields = this.fields = this.getMetadata().get('integrations.' + this.integration + '.fields'); - Object.keys(this.fields).forEach(function (name) { - this.model.defs.fields[name] = this.fields[name]; - this.dataFieldList.push(name); - }, this); - - this.model.populateDefaults(); - - this.listenToOnce(this.model, 'sync', function () { - this.createFieldView('bool', 'enabled'); - Object.keys(this.fields).forEach(function (name) { - this.createFieldView(this.fields[name]['type'], name, null, this.fields[name]); - }, this); - - this.wait(false); - }, this); - - this.model.fetch(); - }, - - hideField: function (name) { - this.$el.find('label.field-label-' + name).addClass('hide'); - this.$el.find('div.field-' + name).addClass('hide'); - var view = this.getView(name); - if (view) { - view.enabled = false; - } - }, - - showField: function (name) { - this.$el.find('label.field-label-' + name).removeClass('hide'); - this.$el.find('div.field-' + name).removeClass('hide'); - var view = this.getView(name); - if (view) { - view.enabled = true; - } - }, - - afterRender: function () { - if (!this.model.get('enabled')) { - this.dataFieldList.forEach(function (name) { - this.hideField(name); - }, this); - } - - this.listenTo(this.model, 'change:enabled', function () { - if (this.model.get('enabled')) { - this.dataFieldList.forEach(function (name) { - this.showField(name); - }, this); - } else { - this.dataFieldList.forEach(function (name) { - this.hideField(name); - }, this); - } - }, this); - }, - - createFieldView: function (type, name, readOnly, params) { - this.createView(name, this.getFieldManager().getViewName(type), { - model: this.model, - el: this.options.el + ' .field-' + name, - defs: { - name: name, - params: params - }, - mode: readOnly ? 'detail' : 'edit', - readOnly: readOnly, - }); - this.fieldList.push(name); - }, - - save: function () { - this.fieldList.forEach(function (field) { - var view = this.getView(field); - if (!view.readOnly) { - view.fetchToModel(); - } - }, this); - - var notValid = false; - this.fieldList.forEach(function (field) { - notValid = this.getView(field).validate() || notValid; - }, this); - - if (notValid) { - this.notify('Not valid', 'error'); - return; - } - - this.listenToOnce(this.model, 'sync', function () { - this.notify('Saved', 'success'); - }, this); - - this.notify('Saving...'); - this.model.save(); - }, - - }); + Object.keys(this.fields).forEach(function (name) { + this.model.defs.fields[name] = this.fields[name]; + this.dataFieldList.push(name); + }, this); + + this.model.populateDefaults(); + + this.listenToOnce(this.model, 'sync', function () { + this.createFieldView('bool', 'enabled'); + Object.keys(this.fields).forEach(function (name) { + this.createFieldView(this.fields[name]['type'], name, null, this.fields[name]); + }, this); + + this.wait(false); + }, this); + + this.model.fetch(); + }, + + hideField: function (name) { + this.$el.find('label.field-label-' + name).addClass('hide'); + this.$el.find('div.field-' + name).addClass('hide'); + var view = this.getView(name); + if (view) { + view.enabled = false; + } + }, + + showField: function (name) { + this.$el.find('label.field-label-' + name).removeClass('hide'); + this.$el.find('div.field-' + name).removeClass('hide'); + var view = this.getView(name); + if (view) { + view.enabled = true; + } + }, + + afterRender: function () { + if (!this.model.get('enabled')) { + this.dataFieldList.forEach(function (name) { + this.hideField(name); + }, this); + } + + this.listenTo(this.model, 'change:enabled', function () { + if (this.model.get('enabled')) { + this.dataFieldList.forEach(function (name) { + this.showField(name); + }, this); + } else { + this.dataFieldList.forEach(function (name) { + this.hideField(name); + }, this); + } + }, this); + }, + + createFieldView: function (type, name, readOnly, params) { + this.createView(name, this.getFieldManager().getViewName(type), { + model: this.model, + el: this.options.el + ' .field-' + name, + defs: { + name: name, + params: params + }, + mode: readOnly ? 'detail' : 'edit', + readOnly: readOnly, + }); + this.fieldList.push(name); + }, + + save: function () { + this.fieldList.forEach(function (field) { + var view = this.getView(field); + if (!view.readOnly) { + view.fetchToModel(); + } + }, this); + + var notValid = false; + this.fieldList.forEach(function (field) { + notValid = this.getView(field).validate() || notValid; + }, this); + + if (notValid) { + this.notify('Not valid', 'error'); + return; + } + + this.listenToOnce(this.model, 'sync', function () { + this.notify('Saved', 'success'); + }, this); + + this.notify('Saving...'); + this.model.save(); + }, + + }); }); diff --git a/frontend/client/src/views/admin/integrations/index.js b/frontend/client/src/views/admin/integrations/index.js index 8605dc398d..248a90b5dd 100644 --- a/frontend/client/src/views/admin/integrations/index.js +++ b/frontend/client/src/views/admin/integrations/index.js @@ -21,78 +21,78 @@ Espo.define('Views.Admin.Integrations.Index', 'View', function (Dep) { - return Dep.extend({ + return Dep.extend({ - template: 'admin.integrations.index', + template: 'admin.integrations.index', - integrationList: null, + integrationList: null, - integration: null, + integration: null, - data: function () { - return { - integrationList: this.integrationList, - integration: this.integration, - }; - }, + data: function () { + return { + integrationList: this.integrationList, + integration: this.integration, + }; + }, - events: { - 'click #integrations-menu a.integration-link': function (e) { - var name = $(e.currentTarget).data('name'); - this.openIntegration(name); - }, - }, + events: { + 'click #integrations-menu a.integration-link': function (e) { + var name = $(e.currentTarget).data('name'); + this.openIntegration(name); + }, + }, - setup: function () { - this.integrationList = Object.keys(this.getMetadata().get('integrations') || {});; + setup: function () { + this.integrationList = Object.keys(this.getMetadata().get('integrations') || {});; - this.integration = this.options.integration || null; - - this.on('after:render', function () { - this.renderHeader(); - if (!this.integration) { - this.renderDefaultPage(); - } else { - this.openIntegration(this.integration); - } - }); - }, + this.integration = this.options.integration || null; + + this.on('after:render', function () { + this.renderHeader(); + if (!this.integration) { + this.renderDefaultPage(); + } else { + this.openIntegration(this.integration); + } + }); + }, - openIntegration: function (integration) { - this.integration = integration; - - this.getRouter().navigate('#Admin/integrations/name=' + integration, {trigger: false}); - - var viewName = 'Admin.Integrations.' + this.getMetadata().get('integrations.' + integration + '.authMethod'); - this.notify('Loading...'); - this.createView('content', viewName, { - el: '#integration-content', - integration: integration, - }, function (view) { - this.renderHeader(); - view.render(); - this.notify(false); - $(window).scrollTop(0); - }.bind(this)); - }, + openIntegration: function (integration) { + this.integration = integration; + + this.getRouter().navigate('#Admin/integrations/name=' + integration, {trigger: false}); + + var viewName = 'Admin.Integrations.' + this.getMetadata().get('integrations.' + integration + '.authMethod'); + this.notify('Loading...'); + this.createView('content', viewName, { + el: '#integration-content', + integration: integration, + }, function (view) { + this.renderHeader(); + view.render(); + this.notify(false); + $(window).scrollTop(0); + }.bind(this)); + }, - renderDefaultPage: function () { - $('#integration-header').html('').hide(); - $('#integration-content').html(this.translate('selectIntegration', 'messages', 'Integration')); - }, + renderDefaultPage: function () { + $('#integration-header').html('').hide(); + $('#integration-content').html(this.translate('selectIntegration', 'messages', 'Integration')); + }, - renderHeader: function () { - if (!this.integration) { - $('#integration-header').html(''); - return; - } - $('#integration-header').show().html(this.integration); - }, + renderHeader: function () { + if (!this.integration) { + $('#integration-header').html(''); + return; + } + $('#integration-header').show().html(this.integration); + }, - updatePageTitle: function () { - this.setPageTitle(this.getLanguage().translate('Integrations', 'labels', 'Admin')); - }, - }); + updatePageTitle: function () { + this.setPageTitle(this.getLanguage().translate('Integrations', 'labels', 'Admin')); + }, + }); }); diff --git a/frontend/client/src/views/admin/integrations/oauth2.js b/frontend/client/src/views/admin/integrations/oauth2.js index 87377f5782..353e073470 100644 --- a/frontend/client/src/views/admin/integrations/oauth2.js +++ b/frontend/client/src/views/admin/integrations/oauth2.js @@ -20,19 +20,19 @@ ************************************************************************/ Espo.define('Views.Admin.Integrations.OAuth2', 'Views.Admin.Integrations.Edit', function (Dep) { - - return Dep.extend({ - - template: 'admin.integrations.oauth2', - - data: function () { - - return _.extend({ - // TODO fetch from server - redirectUri: this.getConfig().get('siteUrl') + '/oauthcallback' - }, Dep.prototype.data.call(this)); - }, - - }); + + return Dep.extend({ + + template: 'admin.integrations.oauth2', + + data: function () { + + return _.extend({ + // TODO fetch from server + redirectUri: this.getConfig().get('siteUrl') + '/oauthcallback' + }, Dep.prototype.data.call(this)); + }, + + }); }); diff --git a/frontend/client/src/views/admin/layouts/base.js b/frontend/client/src/views/admin/layouts/base.js index f22e383dd7..44f15949f1 100644 --- a/frontend/client/src/views/admin/layouts/base.js +++ b/frontend/client/src/views/admin/layouts/base.js @@ -19,155 +19,155 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ -Espo.define('Views.Admin.Layouts.Base', 'View', function (Dep) { +Espo.define('Views.Admin.Layouts.Base', 'View', function (Dep) { - return Dep.extend({ - - scope: null, - - type: null, - - events: { - 'click button[data-action="save"]': function () { - this.disableButtons(); - this.notify('Saving...'); - this.save(this.enableButtons.bind(this)); - }, - 'click button[data-action="cancel"]': function () { - this.getRouter().navigate('#Admin/layouts', {trigger: true}); - }, - }, - - buttons: [ - { - name: 'save', - label: 'Save', - style: 'primary', - }, - { - name: 'cancel', - label: 'Cancel', - } - ], - - dataAttributes: null, - - dataAttributesDefs: null, - - disableButtons: function () { - this.$el.find('.button-container button').attr('disabled', true); - }, - - enableButtons: function () { - this.$el.find('.button-container button').removeAttr('disabled'); - }, - - save: function (callback) { - var layout = this.fetch(); - - if (!this.validate(layout)) { - this.enableButtons(); - return false; - } - - this.getHelper().layoutManager.set(this.scope, this.type, layout, function () { - this.notify('Saved', 'success', 2000); - - if (typeof callback == 'function') { - callback(); - } - }.bind(this)); - }, - - cancel: function () { - this.loadLayout(function () { - this.render(); - }.bind(this)); - }, - - reset: function () { - this.render(); - }, - - fetch: function () {}, - - setup: function () { - this.dataAttributes = _.clone(this.dataAttributes); - this.buttons = _.clone(this.buttons); - this.events = _.clone(this.events); - this.scope = this.options.scope; - this.type = this.options.type; - }, - - unescape: function (string) { - if (string == null) { - return ''; - } - - var map = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - ''': "'" - }; - var reg = new RegExp('(' + _.keys(map).join('|') + ')', 'g'); + return Dep.extend({ + + scope: null, + + type: null, + + events: { + 'click button[data-action="save"]': function () { + this.disableButtons(); + this.notify('Saving...'); + this.save(this.enableButtons.bind(this)); + }, + 'click button[data-action="cancel"]': function () { + this.getRouter().navigate('#Admin/layouts', {trigger: true}); + }, + }, + + buttons: [ + { + name: 'save', + label: 'Save', + style: 'primary', + }, + { + name: 'cancel', + label: 'Cancel', + } + ], + + dataAttributes: null, + + dataAttributesDefs: null, + + disableButtons: function () { + this.$el.find('.button-container button').attr('disabled', true); + }, + + enableButtons: function () { + this.$el.find('.button-container button').removeAttr('disabled'); + }, + + save: function (callback) { + var layout = this.fetch(); + + if (!this.validate(layout)) { + this.enableButtons(); + return false; + } + + this.getHelper().layoutManager.set(this.scope, this.type, layout, function () { + this.notify('Saved', 'success', 2000); + + if (typeof callback == 'function') { + callback(); + } + }.bind(this)); + }, + + cancel: function () { + this.loadLayout(function () { + this.render(); + }.bind(this)); + }, + + reset: function () { + this.render(); + }, + + fetch: function () {}, + + setup: function () { + this.dataAttributes = _.clone(this.dataAttributes); + this.buttons = _.clone(this.buttons); + this.events = _.clone(this.events); + this.scope = this.options.scope; + this.type = this.options.type; + }, + + unescape: function (string) { + if (string == null) { + return ''; + } + + var map = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + ''': "'" + }; + var reg = new RegExp('(' + _.keys(map).join('|') + ')', 'g'); - return ('' + string).replace(reg, function (match) { - return map[match]; - }); - }, - - openEditDialog: function (data) { - var tpl = this.unescape($("#edit-dialog-tpl").html()); - - var dialog = new Espo.Ui.Dialog({ - header: 'Field: ' + data.name, - body: _.template(tpl, data), - buttons: [ - { - name: 'ok', - text: '  Ok  ', - onClick: function (dialog) { - var o = this.parseDataAttributes(dialog); - var li = $("#layout ul > li[data-name='" + data.name + "']"); - for (var key in o) { - li.attr('data-' + key, o[key]); - li.data(key, o[key]); - li.find('.' + key + '-value').text(o[key]); - } - dialog.close(); - }.bind(this), - }, - { - name: 'cancel', - text: 'Cancel', - onClick: function (dialog) { - dialog.close(); - } - } - ] - }); - - this.dataAttributes.forEach(function (attr) { - var type = this.dataAttributesDefs[attr] || 'text'; - var value = data[attr]; - if (type == 'bool') { - if (value) { - value = "true"; - } - } - dialog.$el.find("[name='"+attr+"']").val(value); - }.bind(this)); - - dialog.show(); - }, - - parseDataAttributes: function () {}, - - validate: function (layout) { - return true; - }, - }); + return ('' + string).replace(reg, function (match) { + return map[match]; + }); + }, + + openEditDialog: function (data) { + var tpl = this.unescape($("#edit-dialog-tpl").html()); + + var dialog = new Espo.Ui.Dialog({ + header: 'Field: ' + data.name, + body: _.template(tpl, data), + buttons: [ + { + name: 'ok', + text: '  Ok  ', + onClick: function (dialog) { + var o = this.parseDataAttributes(dialog); + var li = $("#layout ul > li[data-name='" + data.name + "']"); + for (var key in o) { + li.attr('data-' + key, o[key]); + li.data(key, o[key]); + li.find('.' + key + '-value').text(o[key]); + } + dialog.close(); + }.bind(this), + }, + { + name: 'cancel', + text: 'Cancel', + onClick: function (dialog) { + dialog.close(); + } + } + ] + }); + + this.dataAttributes.forEach(function (attr) { + var type = this.dataAttributesDefs[attr] || 'text'; + var value = data[attr]; + if (type == 'bool') { + if (value) { + value = "true"; + } + } + dialog.$el.find("[name='"+attr+"']").val(value); + }.bind(this)); + + dialog.show(); + }, + + parseDataAttributes: function () {}, + + validate: function (layout) { + return true; + }, + }); }); diff --git a/frontend/client/src/views/admin/layouts/detail-convert.js b/frontend/client/src/views/admin/layouts/detail-convert.js index 266295abd6..ed6032a176 100644 --- a/frontend/client/src/views/admin/layouts/detail-convert.js +++ b/frontend/client/src/views/admin/layouts/detail-convert.js @@ -18,12 +18,12 @@ * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ - -Espo.define('Views.Admin.Layouts.DetailConvert', 'Views.Admin.Layouts.Detail', function (Dep) { + +Espo.define('Views.Admin.Layouts.DetailConvert', 'Views.Admin.Layouts.Detail', function (Dep) { - return Dep.extend({ - - - }); + return Dep.extend({ + + + }); }); diff --git a/frontend/client/src/views/admin/layouts/detail-small.js b/frontend/client/src/views/admin/layouts/detail-small.js index ba143ce0b5..6a0ace1019 100644 --- a/frontend/client/src/views/admin/layouts/detail-small.js +++ b/frontend/client/src/views/admin/layouts/detail-small.js @@ -18,13 +18,13 @@ * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ - -Espo.define('Views.Admin.Layouts.DetailSmall', 'Views.Admin.Layouts.Detail', function (Dep) { + +Espo.define('Views.Admin.Layouts.DetailSmall', 'Views.Admin.Layouts.Detail', function (Dep) { - return Dep.extend({ - - columnCount: 1, - - }); + return Dep.extend({ + + columnCount: 1, + + }); }); diff --git a/frontend/client/src/views/admin/layouts/detail.js b/frontend/client/src/views/admin/layouts/detail.js index b25cd05479..de382e0525 100644 --- a/frontend/client/src/views/admin/layouts/detail.js +++ b/frontend/client/src/views/admin/layouts/detail.js @@ -18,79 +18,79 @@ * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ - -Espo.define('Views.Admin.Layouts.Detail', 'Views.Admin.Layouts.Grid', function (Dep) { + +Espo.define('Views.Admin.Layouts.Detail', 'Views.Admin.Layouts.Grid', function (Dep) { - return Dep.extend({ - - dataAttributes: ['name', 'fullWidth'], - - dataAttributesDefs: { - fullWidth: 'bool', - }, - - ignoreList: ['modifiedAt', 'createdAt', 'modifiedBy', 'createdBy', 'assignedUser', 'teams'], - - setup: function () { - Dep.prototype.setup.call(this); - - this.wait(true); - this.loadLayout(function () { - this.wait(false); - }.bind(this)); - }, - - loadLayout: function (callback) { - this.getModelFactory().create(this.scope, function (model) { - this.getHelper().layoutManager.get(this.scope, this.type, function (layout) { - this.readDataFromLayout(model, layout); - if (callback) { - callback(); - } - }.bind(this), false); - }.bind(this)); - }, - - readDataFromLayout: function (model, layout) { - var allFields = []; - for (var field in model.defs.fields) { - if (this.isFieldEnabled(model, field)) { - allFields.push(field); - } - } - - this.enabledFields = []; - this.disabledFields = []; - - this.panels = layout; - - layout.forEach(function (panel) { - panel.rows.forEach(function (row) { - row.forEach(function (cell, i) { - if (i == this.columnCount) { - return; - } - this.enabledFields.push(cell.name); - }.bind(this)); - }.bind(this)); - }.bind(this)); - - - allFields.sort(); - - for (var i in allFields) { - if (!_.contains(this.enabledFields, allFields[i])) { - this.disabledFields.push(allFields[i]); - } - } - }, - - isFieldEnabled: function (model, name) { - if (this.ignoreList.indexOf(name) != -1) { - return false; - } - return !model.getFieldParam(name, 'disabled'); - } - }); + return Dep.extend({ + + dataAttributes: ['name', 'fullWidth'], + + dataAttributesDefs: { + fullWidth: 'bool', + }, + + ignoreList: ['modifiedAt', 'createdAt', 'modifiedBy', 'createdBy', 'assignedUser', 'teams'], + + setup: function () { + Dep.prototype.setup.call(this); + + this.wait(true); + this.loadLayout(function () { + this.wait(false); + }.bind(this)); + }, + + loadLayout: function (callback) { + this.getModelFactory().create(this.scope, function (model) { + this.getHelper().layoutManager.get(this.scope, this.type, function (layout) { + this.readDataFromLayout(model, layout); + if (callback) { + callback(); + } + }.bind(this), false); + }.bind(this)); + }, + + readDataFromLayout: function (model, layout) { + var allFields = []; + for (var field in model.defs.fields) { + if (this.isFieldEnabled(model, field)) { + allFields.push(field); + } + } + + this.enabledFields = []; + this.disabledFields = []; + + this.panels = layout; + + layout.forEach(function (panel) { + panel.rows.forEach(function (row) { + row.forEach(function (cell, i) { + if (i == this.columnCount) { + return; + } + this.enabledFields.push(cell.name); + }.bind(this)); + }.bind(this)); + }.bind(this)); + + + allFields.sort(); + + for (var i in allFields) { + if (!_.contains(this.enabledFields, allFields[i])) { + this.disabledFields.push(allFields[i]); + } + } + }, + + isFieldEnabled: function (model, name) { + if (this.ignoreList.indexOf(name) != -1) { + return false; + } + return !model.getFieldParam(name, 'disabled'); + } + }); }); diff --git a/frontend/client/src/views/admin/layouts/filters.js b/frontend/client/src/views/admin/layouts/filters.js index aa7b0992ba..964b1e5358 100644 --- a/frontend/client/src/views/admin/layouts/filters.js +++ b/frontend/client/src/views/admin/layouts/filters.js @@ -18,86 +18,86 @@ * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ - -Espo.define('Views.Admin.Layouts.Filters', 'Views.Admin.Layouts.Rows', function (Dep) { + +Espo.define('Views.Admin.Layouts.Filters', 'Views.Admin.Layouts.Rows', function (Dep) { - return Dep.extend({ - - dataAttributes: ['name'], - - editable: false, - - ignoreList: [], - - setup: function () { - Dep.prototype.setup.call(this); - - this.wait(true); - - this.getModelFactory().create(this.scope, function (model) { - this.getHelper().layoutManager.get(this.scope, this.type, function (layout) { - - var allFields = []; - for (var field in model.defs.fields) { - if (this.checkFieldType(model.getFieldParam(field, 'type')) && this.isFieldEnabled(model, field)) { - allFields.push(field); - } - } - - this.enabledFieldsList = []; - - this.enabledFields = []; - this.disabledFields = []; - for (var i in layout) { - this.enabledFields.push({ - name: layout[i], - label: this.getLanguage().translate(layout[i], 'fields', this.scope) - }); - this.enabledFieldsList.push(layout[i]); - } - - for (var i in allFields) { - if (!_.contains(this.enabledFieldsList, allFields[i])) { - this.disabledFields.push({ - name: allFields[i], - label: this.getLanguage().translate(allFields[i], 'fields', this.scope) - }); - } - } - this.rowLayout = this.enabledFields; - - for (var i in this.rowLayout) { - this.rowLayout[i].label = this.getLanguage().translate(this.rowLayout[i].name, 'fields', this.scope); - } - - this.wait(false); - }.bind(this), false); - }.bind(this)); - }, - - fetch: function () { - var layout = []; - $("#layout ul.enabled > li").each(function (i, el) { - layout.push($(el).data('name')); - }.bind(this)); - return layout; - }, - - checkFieldType: function (type) { - return this.getFieldManager().checkFilter(type); - }, - - validate: function () { - return true; - }, - - isFieldEnabled: function (model, name) { - if (this.ignoreList.indexOf(name) != -1) { - return false; - } - return !model.getFieldParam(name, 'disabled'); - } - - }); + return Dep.extend({ + + dataAttributes: ['name'], + + editable: false, + + ignoreList: [], + + setup: function () { + Dep.prototype.setup.call(this); + + this.wait(true); + + this.getModelFactory().create(this.scope, function (model) { + this.getHelper().layoutManager.get(this.scope, this.type, function (layout) { + + var allFields = []; + for (var field in model.defs.fields) { + if (this.checkFieldType(model.getFieldParam(field, 'type')) && this.isFieldEnabled(model, field)) { + allFields.push(field); + } + } + + this.enabledFieldsList = []; + + this.enabledFields = []; + this.disabledFields = []; + for (var i in layout) { + this.enabledFields.push({ + name: layout[i], + label: this.getLanguage().translate(layout[i], 'fields', this.scope) + }); + this.enabledFieldsList.push(layout[i]); + } + + for (var i in allFields) { + if (!_.contains(this.enabledFieldsList, allFields[i])) { + this.disabledFields.push({ + name: allFields[i], + label: this.getLanguage().translate(allFields[i], 'fields', this.scope) + }); + } + } + this.rowLayout = this.enabledFields; + + for (var i in this.rowLayout) { + this.rowLayout[i].label = this.getLanguage().translate(this.rowLayout[i].name, 'fields', this.scope); + } + + this.wait(false); + }.bind(this), false); + }.bind(this)); + }, + + fetch: function () { + var layout = []; + $("#layout ul.enabled > li").each(function (i, el) { + layout.push($(el).data('name')); + }.bind(this)); + return layout; + }, + + checkFieldType: function (type) { + return this.getFieldManager().checkFilter(type); + }, + + validate: function () { + return true; + }, + + isFieldEnabled: function (model, name) { + if (this.ignoreList.indexOf(name) != -1) { + return false; + } + return !model.getFieldParam(name, 'disabled'); + } + + }); }); diff --git a/frontend/client/src/views/admin/layouts/grid.js b/frontend/client/src/views/admin/layouts/grid.js index 68f64baa1a..a91f4d5627 100644 --- a/frontend/client/src/views/admin/layouts/grid.js +++ b/frontend/client/src/views/admin/layouts/grid.js @@ -18,281 +18,281 @@ * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ - -Espo.define('Views.Admin.Layouts.Grid', 'Views.Admin.Layouts.Base', function (Dep) { + +Espo.define('Views.Admin.Layouts.Grid', 'Views.Admin.Layouts.Base', function (Dep) { - return Dep.extend({ - - template: 'admin.layouts.grid', - - dataAttributes: null, - - panels: null, - - columnCount: 2, - - data: function () { - return { - scope: this.scope, - type: this.type, - buttons: this.buttons, - enabledFields: this.enabledFields, - disabledFields: this.disabledFields, - panels: this.panels, - columnCount: this.columnCount - }; - }, - - events: _.extend({ - 'click #layout a[data-action="addPanel"]': function () { - this.addPanel(); - this.makeDraggable(); - }, - 'click #layout a[data-action="removePanel"]': function (e) { - $(e.target).closest('ul.panels > li').find('ul.cells > li').each(function (i, li) { - if ($(li).attr('data-name')) { - $(li).appendTo($('#layout ul.disabled')); - } - }); - $(e.target).closest('ul.panels > li').remove(); - }, - 'click #layout a[data-action="addRow"]': function (e) { - var tpl = this.unescape($("#layout-row-tpl").html()); - var html = _.template(tpl); - $(e.target).closest('ul.panels > li').find('ul.rows').append(html); - this.makeDraggable(); - }, - 'click #layout a[data-action="removeRow"]': function (e) { - $(e.target).closest('ul.rows > li').find('ul.cells > li').each(function (i, li) { - if ($(li).attr('data-name')) { - $(li).appendTo($('#layout ul.disabled')); - } - }); - $(e.target).closest('ul.rows > li').remove(); - }, - 'click #layout a[data-action="removeField"]': function (e) { - var el = $(e.target).closest('li'); - var index = el.index(); - var parent = el.parent(); - - el.appendTo($("ul.disabled")); - - var empty = $('
  • '); - if (el.data('full-width')) { - for (var i = 0; i < this.columnCount; i++) { - parent.append(empty.clone()); - } - } else { - - if (index == 0) { - parent.prepend(empty); - } else { - empty.insertAfter(parent.children(':nth-child(' + index + ')')); - } - } - - el.data('full-width', null); - el.removeAttr('data-full-width'); - - this.makeDraggable(); - }, - 'click #layout a[data-action="minusCell"]': function (e) { - if (this.columnCount < 2) { - return; - } - $li = $(e.currentTarget).closest('li'); - $ul = $li.parent(); - - var count = 0; - - var isEmpty = false; - if ($ul.children('li:not(.empty)').size() == 0) { - isEmpty = true; - } - - $ul.children('li.empty').remove(); - $ul.children('li:not(:first-child)').remove(); - $ul.children('li').data('full-width', true).attr('data-full-width', true); - - if (isEmpty) { - $ul.append($('
  • ').data('full-width', true).attr('data-full-width', true)); - this.makeDraggable(); - } - - }, - 'click #layout a[data-action="edit-panel-label"]': function (e) { - var el = $(e.target).closest('header').children('label'); - var value = el.text(); - - var dialog = new Espo.Ui.Dialog({ - modal: true, - body: '', - buttons: [ - { - name: 'ok', - text: '  Ok  ', - onClick: function (dialog) { - el.text(dialog.$el.find('input[name="label"]').val()); - dialog.close(); - }.bind(this), - }, - { - name: 'cancel', - text: 'Cancel', - onClick: function (dialog) { - dialog.close(); - } - } - ] - }); - dialog.show(); - } - }, Dep.prototype.events), - - addPanel: function (data) { - var tpl = this.unescape($("#layout-panel-tpl").html()); - - var empty = false; - if (!data) { - empty = true; - } - - data = data || {label: 'new panel', rows: [[]]}; - - data.rows.forEach(function (row) { - var rest = this.columnCount - row.length; - - if (empty) { - for (var i = 0; i < rest; i++) { - row.push(false); - } - } - for (var i in row) { - if (row[i] != false) { - row[i].label = this.getLanguage().translate(row[i].name, 'fields', this.scope); - } - - } - }.bind(this)); - - - var html = _.template(tpl, data); - $("#layout .panels").append(html); - }, - - makeDraggable: function () { - $('#layout ul.panels').sortable({distance: 4}); - $('#layout ul.panels').disableSelection(); - - $('#layout ul.rows').sortable({ - distance: 4, - connectWith: '.rows', - }); - $('#layout ul.rows').disableSelection(); - - $('#layout ul.cells > li').draggable({revert: 'invalid', revertDuration: 200, zIndex: 10}).css('cursor', 'pointer'); - - $('#layout ul.cells > li').droppable().droppable('destroy'); - - var self = this; - $('#layout ul.cells:not(.disabled) > li').droppable({ - accept: '.cell', - zIndex: 10, - drop: function (e, ui) { - var index = ui.draggable.index(); - var parent = ui.draggable.parent(); - - if (parent.get(0) == $(this).parent().get(0)) { - if ($(this).index() < ui.draggable.index()) { - $(this).before(ui.draggable); - } else { - $(this).after(ui.draggable); - } - } else { - ui.draggable.insertAfter($(this)); - - if (index == 0) { - $(this).prependTo(parent); - } else { - $(this).insertAfter(parent.children(':nth-child(' + (index) + ')')); - } - } - - if ($(this).data('full-width')) { - $(ui.draggable).data('full-width', true).attr('data-full-width', true); - } - - ui.draggable.css({ - top: 0, - left: 0, - }); - - if ($(this).parent().hasClass('disabled') && !$(this).data('name')) { - $(this).remove(); - } - - self.makeDraggable(); - } - }); - }, - - afterRender: function () { - this.panels.forEach(function (panel) { - this.addPanel(panel); - }.bind(this)); - this.makeDraggable(); - }, - - fetch: function () { - var layout = []; - var self = this; - $("#layout ul.panels > li").each(function () { - var o = { - label: $(this).find('header label').text(), - rows: [] - }; - $(this).find('ul.rows > li').each(function (i, li) { - var row = []; - $(li).find('ul.cells > li').each(function (i, li) { - var cell = false; - if (!$(li).hasClass('empty')) { - cell = {}; - self.dataAttributes.forEach(function (attr) { - var value = $(li).data(Espo.Utils.toDom(attr)) || null; - if (value) { - cell[attr] = value; - } - }); - } - row.push(cell); - }); - o.rows.push(row); - }); - - layout.push(o); - }); - - return layout; - }, - - validate: function (layout) { - var fieldCount = 0; - layout.forEach(function (panel) { - panel.rows.forEach(function (row) { - row.forEach(function (cell) { - if (cell != false) { - fieldCount++; - } - }); - }); - }); - if (fieldCount == 0) { - alert('Layout cannot be empty.'); - return false; - } - return true; - }, - }); + return Dep.extend({ + + template: 'admin.layouts.grid', + + dataAttributes: null, + + panels: null, + + columnCount: 2, + + data: function () { + return { + scope: this.scope, + type: this.type, + buttons: this.buttons, + enabledFields: this.enabledFields, + disabledFields: this.disabledFields, + panels: this.panels, + columnCount: this.columnCount + }; + }, + + events: _.extend({ + 'click #layout a[data-action="addPanel"]': function () { + this.addPanel(); + this.makeDraggable(); + }, + 'click #layout a[data-action="removePanel"]': function (e) { + $(e.target).closest('ul.panels > li').find('ul.cells > li').each(function (i, li) { + if ($(li).attr('data-name')) { + $(li).appendTo($('#layout ul.disabled')); + } + }); + $(e.target).closest('ul.panels > li').remove(); + }, + 'click #layout a[data-action="addRow"]': function (e) { + var tpl = this.unescape($("#layout-row-tpl").html()); + var html = _.template(tpl); + $(e.target).closest('ul.panels > li').find('ul.rows').append(html); + this.makeDraggable(); + }, + 'click #layout a[data-action="removeRow"]': function (e) { + $(e.target).closest('ul.rows > li').find('ul.cells > li').each(function (i, li) { + if ($(li).attr('data-name')) { + $(li).appendTo($('#layout ul.disabled')); + } + }); + $(e.target).closest('ul.rows > li').remove(); + }, + 'click #layout a[data-action="removeField"]': function (e) { + var el = $(e.target).closest('li'); + var index = el.index(); + var parent = el.parent(); + + el.appendTo($("ul.disabled")); + + var empty = $('
  • '); + if (el.data('full-width')) { + for (var i = 0; i < this.columnCount; i++) { + parent.append(empty.clone()); + } + } else { + + if (index == 0) { + parent.prepend(empty); + } else { + empty.insertAfter(parent.children(':nth-child(' + index + ')')); + } + } + + el.data('full-width', null); + el.removeAttr('data-full-width'); + + this.makeDraggable(); + }, + 'click #layout a[data-action="minusCell"]': function (e) { + if (this.columnCount < 2) { + return; + } + $li = $(e.currentTarget).closest('li'); + $ul = $li.parent(); + + var count = 0; + + var isEmpty = false; + if ($ul.children('li:not(.empty)').size() == 0) { + isEmpty = true; + } + + $ul.children('li.empty').remove(); + $ul.children('li:not(:first-child)').remove(); + $ul.children('li').data('full-width', true).attr('data-full-width', true); + + if (isEmpty) { + $ul.append($('
  • ').data('full-width', true).attr('data-full-width', true)); + this.makeDraggable(); + } + + }, + 'click #layout a[data-action="edit-panel-label"]': function (e) { + var el = $(e.target).closest('header').children('label'); + var value = el.text(); + + var dialog = new Espo.Ui.Dialog({ + modal: true, + body: '', + buttons: [ + { + name: 'ok', + text: '  Ok  ', + onClick: function (dialog) { + el.text(dialog.$el.find('input[name="label"]').val()); + dialog.close(); + }.bind(this), + }, + { + name: 'cancel', + text: 'Cancel', + onClick: function (dialog) { + dialog.close(); + } + } + ] + }); + dialog.show(); + } + }, Dep.prototype.events), + + addPanel: function (data) { + var tpl = this.unescape($("#layout-panel-tpl").html()); + + var empty = false; + if (!data) { + empty = true; + } + + data = data || {label: 'new panel', rows: [[]]}; + + data.rows.forEach(function (row) { + var rest = this.columnCount - row.length; + + if (empty) { + for (var i = 0; i < rest; i++) { + row.push(false); + } + } + for (var i in row) { + if (row[i] != false) { + row[i].label = this.getLanguage().translate(row[i].name, 'fields', this.scope); + } + + } + }.bind(this)); + + + var html = _.template(tpl, data); + $("#layout .panels").append(html); + }, + + makeDraggable: function () { + $('#layout ul.panels').sortable({distance: 4}); + $('#layout ul.panels').disableSelection(); + + $('#layout ul.rows').sortable({ + distance: 4, + connectWith: '.rows', + }); + $('#layout ul.rows').disableSelection(); + + $('#layout ul.cells > li').draggable({revert: 'invalid', revertDuration: 200, zIndex: 10}).css('cursor', 'pointer'); + + $('#layout ul.cells > li').droppable().droppable('destroy'); + + var self = this; + $('#layout ul.cells:not(.disabled) > li').droppable({ + accept: '.cell', + zIndex: 10, + drop: function (e, ui) { + var index = ui.draggable.index(); + var parent = ui.draggable.parent(); + + if (parent.get(0) == $(this).parent().get(0)) { + if ($(this).index() < ui.draggable.index()) { + $(this).before(ui.draggable); + } else { + $(this).after(ui.draggable); + } + } else { + ui.draggable.insertAfter($(this)); + + if (index == 0) { + $(this).prependTo(parent); + } else { + $(this).insertAfter(parent.children(':nth-child(' + (index) + ')')); + } + } + + if ($(this).data('full-width')) { + $(ui.draggable).data('full-width', true).attr('data-full-width', true); + } + + ui.draggable.css({ + top: 0, + left: 0, + }); + + if ($(this).parent().hasClass('disabled') && !$(this).data('name')) { + $(this).remove(); + } + + self.makeDraggable(); + } + }); + }, + + afterRender: function () { + this.panels.forEach(function (panel) { + this.addPanel(panel); + }.bind(this)); + this.makeDraggable(); + }, + + fetch: function () { + var layout = []; + var self = this; + $("#layout ul.panels > li").each(function () { + var o = { + label: $(this).find('header label').text(), + rows: [] + }; + $(this).find('ul.rows > li').each(function (i, li) { + var row = []; + $(li).find('ul.cells > li').each(function (i, li) { + var cell = false; + if (!$(li).hasClass('empty')) { + cell = {}; + self.dataAttributes.forEach(function (attr) { + var value = $(li).data(Espo.Utils.toDom(attr)) || null; + if (value) { + cell[attr] = value; + } + }); + } + row.push(cell); + }); + o.rows.push(row); + }); + + layout.push(o); + }); + + return layout; + }, + + validate: function (layout) { + var fieldCount = 0; + layout.forEach(function (panel) { + panel.rows.forEach(function (row) { + row.forEach(function (cell) { + if (cell != false) { + fieldCount++; + } + }); + }); + }); + if (fieldCount == 0) { + alert('Layout cannot be empty.'); + return false; + } + return true; + }, + }); }); diff --git a/frontend/client/src/views/admin/layouts/index.js b/frontend/client/src/views/admin/layouts/index.js index 4fc346baa7..3caf61f321 100644 --- a/frontend/client/src/views/admin/layouts/index.js +++ b/frontend/client/src/views/admin/layouts/index.js @@ -21,123 +21,123 @@ Espo.define('Views.Admin.Layouts.Index', 'View', function (Dep) { - return Dep.extend({ + return Dep.extend({ - template: 'admin.layouts.index', + template: 'admin.layouts.index', - scopeList: null, + scopeList: null, - typeList: ['list', 'detail', 'listSmall', 'detailSmall', 'filters', 'massUpdate', 'relationships'], - - additionalLayouts: { - 'Opportunity': ['detailConvert'], - 'Contact': ['detailConvert'], - 'Account': ['detailConvert'], - }, + typeList: ['list', 'detail', 'listSmall', 'detailSmall', 'filters', 'massUpdate', 'relationships'], + + additionalLayouts: { + 'Opportunity': ['detailConvert'], + 'Contact': ['detailConvert'], + 'Account': ['detailConvert'], + }, - scope: null, + scope: null, - type: null, + type: null, - data: function () { - return { - scopeList: this.scopeList, - typeList: this.typeList, - scope: this.scope, - layoutScopeDataList: (function () { - var dataList = []; - this.scopeList.forEach(function (scope) { - var d = {}; - d.scope = scope; - d.typeList = _.clone(this.typeList); - (this.additionalLayouts[scope] || []).forEach(function (item) { - d.typeList.push(item); - }); - - dataList.push(d); - }, this); - return dataList; - }).call(this) - }; - }, + data: function () { + return { + scopeList: this.scopeList, + typeList: this.typeList, + scope: this.scope, + layoutScopeDataList: (function () { + var dataList = []; + this.scopeList.forEach(function (scope) { + var d = {}; + d.scope = scope; + d.typeList = _.clone(this.typeList); + (this.additionalLayouts[scope] || []).forEach(function (item) { + d.typeList.push(item); + }); + + dataList.push(d); + }, this); + return dataList; + }).call(this) + }; + }, - events: { - 'click #layouts-menu button.layout-link': function (e) { - var scope = $(e.currentTarget).data('scope'); - var type = $(e.currentTarget).data('type'); - if (this.getView('content')) { - if (this.scope == scope && this.type == type) { - return; - } - } - $("#layouts-menu button.layout-link").removeClass('disabled'); - $(e.target).addClass('disabled'); - this.openLayout(scope, type); - }, - }, + events: { + 'click #layouts-menu button.layout-link': function (e) { + var scope = $(e.currentTarget).data('scope'); + var type = $(e.currentTarget).data('type'); + if (this.getView('content')) { + if (this.scope == scope && this.type == type) { + return; + } + } + $("#layouts-menu button.layout-link").removeClass('disabled'); + $(e.target).addClass('disabled'); + this.openLayout(scope, type); + }, + }, - setup: function () { - this.scopeList = []; - var scopesAll = Object.keys(this.getMetadata().get('scopes')).sort(); - scopesAll.forEach(function (scope) { - if (this.getMetadata().get('scopes.' + scope + '.entity') && - this.getMetadata().get('scopes.' + scope + '.layouts')) { - this.scopeList.push(scope); - } - }.bind(this)); + setup: function () { + this.scopeList = []; + var scopesAll = Object.keys(this.getMetadata().get('scopes')).sort(); + scopesAll.forEach(function (scope) { + if (this.getMetadata().get('scopes.' + scope + '.entity') && + this.getMetadata().get('scopes.' + scope + '.layouts')) { + this.scopeList.push(scope); + } + }.bind(this)); - this.on('after:render', function () { - $("#layouts-menu button[data-scope='" + this.options.scope + "'][data-type='" + this.options.type + "']").addClass('disabled'); - this.renderLayoutHeader(); - if (!this.options.scope) { - this.renderDefaultPage(); - } - if (this.scope) { - this.openLayout(this.options.scope, this.options.type); - } - }); + this.on('after:render', function () { + $("#layouts-menu button[data-scope='" + this.options.scope + "'][data-type='" + this.options.type + "']").addClass('disabled'); + this.renderLayoutHeader(); + if (!this.options.scope) { + this.renderDefaultPage(); + } + if (this.scope) { + this.openLayout(this.options.scope, this.options.type); + } + }); - this.scope = this.options.scope || null; - this.type = this.options.type || null; - }, + this.scope = this.options.scope || null; + this.type = this.options.type || null; + }, - openLayout: function (scope, type) { - this.scope = scope; - this.type = type; + openLayout: function (scope, type) { + this.scope = scope; + this.type = type; - this.getRouter().navigate('#Admin/layouts/scope=' + scope + '&type=' + type, {trigger: false}); + this.getRouter().navigate('#Admin/layouts/scope=' + scope + '&type=' + type, {trigger: false}); - this.notify('Loading...'); + this.notify('Loading...'); - this.createView('content', 'Admin.Layouts.' + Espo.Utils.upperCaseFirst(type), { - el: '#layout-content', - scope: scope, - type: type, - }, function (view) { - this.renderLayoutHeader(); - view.render(); - this.notify(false); - $(window).scrollTop(0); - }.bind(this)); - }, + this.createView('content', 'Admin.Layouts.' + Espo.Utils.upperCaseFirst(type), { + el: '#layout-content', + scope: scope, + type: type, + }, function (view) { + this.renderLayoutHeader(); + view.render(); + this.notify(false); + $(window).scrollTop(0); + }.bind(this)); + }, - renderDefaultPage: function () { - $("#layout-header").html('').hide(); - $("#layout-content").html(this.translate('selectLayout', 'messages', 'Admin')); - }, + renderDefaultPage: function () { + $("#layout-header").html('').hide(); + $("#layout-content").html(this.translate('selectLayout', 'messages', 'Admin')); + }, - renderLayoutHeader: function () { - if (!this.scope) { - $("#layout-header").html(""); - return; - } - $("#layout-header").show().html(this.getLanguage().translate(this.scope, 'scopeNamesPlural') + " » " + this.getLanguage().translate(this.type, 'layouts', 'Admin')); - }, + renderLayoutHeader: function () { + if (!this.scope) { + $("#layout-header").html(""); + return; + } + $("#layout-header").show().html(this.getLanguage().translate(this.scope, 'scopeNamesPlural') + " » " + this.getLanguage().translate(this.type, 'layouts', 'Admin')); + }, - updatePageTitle: function () { - this.setPageTitle(this.getLanguage().translate('Layout Manager')); - }, - }); + updatePageTitle: function () { + this.setPageTitle(this.getLanguage().translate('Layout Manager')); + }, + }); }); diff --git a/frontend/client/src/views/admin/layouts/list-small.js b/frontend/client/src/views/admin/layouts/list-small.js index a63d58ee07..d163c5d135 100644 --- a/frontend/client/src/views/admin/layouts/list-small.js +++ b/frontend/client/src/views/admin/layouts/list-small.js @@ -18,11 +18,11 @@ * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ - -Espo.define('Views.Admin.Layouts.ListSmall', 'Views.Admin.Layouts.List', function (Dep) { + +Espo.define('Views.Admin.Layouts.ListSmall', 'Views.Admin.Layouts.List', function (Dep) { - return Dep.extend({ - }); + return Dep.extend({ + }); }); diff --git a/frontend/client/src/views/admin/layouts/list.js b/frontend/client/src/views/admin/layouts/list.js index 644c225998..b0642fad7c 100644 --- a/frontend/client/src/views/admin/layouts/list.js +++ b/frontend/client/src/views/admin/layouts/list.js @@ -18,108 +18,108 @@ * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ - -Espo.define('Views.Admin.Layouts.List', 'Views.Admin.Layouts.Rows', function (Dep) { + +Espo.define('Views.Admin.Layouts.List', 'Views.Admin.Layouts.Rows', function (Dep) { - return Dep.extend({ - - dataAttributes: ['name', 'width', 'link'], - - dataAttributesDefs: { - link: 'bool', - width: 'text', - }, - - editable: true, - - ignoreList: [], - - setup: function () { - Dep.prototype.setup.call(this); - - this.wait(true); - this.loadLayout(function () { - this.wait(false); - }.bind(this)); - }, - - loadLayout: function (callback) { - this.getModelFactory().create(Espo.Utils.hyphenToUpperCamelCase(this.scope), function (model) { - this.getHelper().layoutManager.get(this.scope, this.type, function (layout) { - this.readDataFromLayout(model, layout); - if (callback) { - callback(); - } - }.bind(this), false); - }.bind(this)); - }, - - readDataFromLayout: function (model, layout) { - var allFields = []; - for (var field in model.defs.fields) { - if (this.checkFieldType(model.getFieldParam(field, 'type')) && this.isFieldEnabled(model, field)) { - - allFields.push(field); - } - } - - this.enabledFieldsList = []; - - this.enabledFields = []; - this.disabledFields = []; - - for (var i in layout) { - this.enabledFields.push({ - name: layout[i].name, - label: this.getLanguage().translate(layout[i].name, 'fields', this.scope) - }); - this.enabledFieldsList.push(layout[i].name); - } - - - - for (var i in allFields) { - if (!_.contains(this.enabledFieldsList, allFields[i])) { - this.disabledFields.push({ - name: allFields[i], - label: this.getLanguage().translate(allFields[i], 'fields', this.scope) - }); - } - } - - this.rowLayout = layout; - - for (var i in this.rowLayout) { - this.rowLayout[i].label = this.getLanguage().translate(this.rowLayout[i].name, 'fields', this.scope); - } - }, - - parseDataAttributes: function (dialog) { - var width = parseFloat(dialog.$el.find("[name='width']").val()); - if (isNaN(width) || width > 100 || width < 0) { - width = ''; - } - return { - width: width, - link: dialog.$el.find("[name='link']").val() - }; - }, - - checkFieldType: function (type) { - if (['linkMultiple'].indexOf(type) != -1) { - return false; - } - return true; - }, - - isFieldEnabled: function (model, name) { - if (this.ignoreList.indexOf(name) != -1) { - return false; - } - return !model.getFieldParam(name, 'disabled'); - } - - }); + return Dep.extend({ + + dataAttributes: ['name', 'width', 'link'], + + dataAttributesDefs: { + link: 'bool', + width: 'text', + }, + + editable: true, + + ignoreList: [], + + setup: function () { + Dep.prototype.setup.call(this); + + this.wait(true); + this.loadLayout(function () { + this.wait(false); + }.bind(this)); + }, + + loadLayout: function (callback) { + this.getModelFactory().create(Espo.Utils.hyphenToUpperCamelCase(this.scope), function (model) { + this.getHelper().layoutManager.get(this.scope, this.type, function (layout) { + this.readDataFromLayout(model, layout); + if (callback) { + callback(); + } + }.bind(this), false); + }.bind(this)); + }, + + readDataFromLayout: function (model, layout) { + var allFields = []; + for (var field in model.defs.fields) { + if (this.checkFieldType(model.getFieldParam(field, 'type')) && this.isFieldEnabled(model, field)) { + + allFields.push(field); + } + } + + this.enabledFieldsList = []; + + this.enabledFields = []; + this.disabledFields = []; + + for (var i in layout) { + this.enabledFields.push({ + name: layout[i].name, + label: this.getLanguage().translate(layout[i].name, 'fields', this.scope) + }); + this.enabledFieldsList.push(layout[i].name); + } + + + + for (var i in allFields) { + if (!_.contains(this.enabledFieldsList, allFields[i])) { + this.disabledFields.push({ + name: allFields[i], + label: this.getLanguage().translate(allFields[i], 'fields', this.scope) + }); + } + } + + this.rowLayout = layout; + + for (var i in this.rowLayout) { + this.rowLayout[i].label = this.getLanguage().translate(this.rowLayout[i].name, 'fields', this.scope); + } + }, + + parseDataAttributes: function (dialog) { + var width = parseFloat(dialog.$el.find("[name='width']").val()); + if (isNaN(width) || width > 100 || width < 0) { + width = ''; + } + return { + width: width, + link: dialog.$el.find("[name='link']").val() + }; + }, + + checkFieldType: function (type) { + if (['linkMultiple'].indexOf(type) != -1) { + return false; + } + return true; + }, + + isFieldEnabled: function (model, name) { + if (this.ignoreList.indexOf(name) != -1) { + return false; + } + return !model.getFieldParam(name, 'disabled'); + } + + }); }); diff --git a/frontend/client/src/views/admin/layouts/mass-update.js b/frontend/client/src/views/admin/layouts/mass-update.js index 36ebdd6c9f..ece3944606 100644 --- a/frontend/client/src/views/admin/layouts/mass-update.js +++ b/frontend/client/src/views/admin/layouts/mass-update.js @@ -18,82 +18,82 @@ * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ - -Espo.define('Views.Admin.Layouts.MassUpdate', 'Views.Admin.Layouts.Rows', function (Dep) { + +Espo.define('Views.Admin.Layouts.MassUpdate', 'Views.Admin.Layouts.Rows', function (Dep) { - return Dep.extend({ - - dataAttributes: ['name'], - - editable: false, - - ignoreList: [], - - setup: function () { - Dep.prototype.setup.call(this); - - this.wait(true); - - this.getModelFactory().create(this.scope, function (model) { - this.getHelper().layoutManager.get(this.scope, this.type, function (layout) { - - var allFields = []; - for (var field in model.defs.fields) { - if (!model.getFieldParam(field, 'readOnly') && this.isFieldEnabled(model, field)) { - allFields.push(field); - } - } - - this.enabledFieldsList = []; - - this.enabledFields = []; - this.disabledFields = []; - for (var i in layout) { - this.enabledFields.push({ - name: layout[i], - label: this.getLanguage().translate(layout[i], 'fields', this.scope) - }); - this.enabledFieldsList.push(layout[i]); - } - - for (var i in allFields) { - if (!_.contains(this.enabledFieldsList, allFields[i])) { - this.disabledFields.push({ - name: allFields[i], - label: this.getLanguage().translate(allFields[i], 'fields', this.scope) - }); - } - } - this.rowLayout = this.enabledFields; - - for (var i in this.rowLayout) { - this.rowLayout[i].label = this.getLanguage().translate(this.rowLayout[i].name, 'fields', this.scope); - } - - this.wait(false); - }.bind(this), false); - }.bind(this)); - }, - - fetch: function () { - var layout = []; - $("#layout ul.enabled > li").each(function (i, el) { - layout.push($(el).data('name')); - }.bind(this)); - return layout; - }, - - validate: function () { - return true; - }, - - isFieldEnabled: function (model, name) { - if (this.ignoreList.indexOf(name) != -1) { - return false; - } - return !model.getFieldParam(name, 'disabled'); - } - - }); + return Dep.extend({ + + dataAttributes: ['name'], + + editable: false, + + ignoreList: [], + + setup: function () { + Dep.prototype.setup.call(this); + + this.wait(true); + + this.getModelFactory().create(this.scope, function (model) { + this.getHelper().layoutManager.get(this.scope, this.type, function (layout) { + + var allFields = []; + for (var field in model.defs.fields) { + if (!model.getFieldParam(field, 'readOnly') && this.isFieldEnabled(model, field)) { + allFields.push(field); + } + } + + this.enabledFieldsList = []; + + this.enabledFields = []; + this.disabledFields = []; + for (var i in layout) { + this.enabledFields.push({ + name: layout[i], + label: this.getLanguage().translate(layout[i], 'fields', this.scope) + }); + this.enabledFieldsList.push(layout[i]); + } + + for (var i in allFields) { + if (!_.contains(this.enabledFieldsList, allFields[i])) { + this.disabledFields.push({ + name: allFields[i], + label: this.getLanguage().translate(allFields[i], 'fields', this.scope) + }); + } + } + this.rowLayout = this.enabledFields; + + for (var i in this.rowLayout) { + this.rowLayout[i].label = this.getLanguage().translate(this.rowLayout[i].name, 'fields', this.scope); + } + + this.wait(false); + }.bind(this), false); + }.bind(this)); + }, + + fetch: function () { + var layout = []; + $("#layout ul.enabled > li").each(function (i, el) { + layout.push($(el).data('name')); + }.bind(this)); + return layout; + }, + + validate: function () { + return true; + }, + + isFieldEnabled: function (model, name) { + if (this.ignoreList.indexOf(name) != -1) { + return false; + } + return !model.getFieldParam(name, 'disabled'); + } + + }); }); diff --git a/frontend/client/src/views/admin/layouts/relationships.js b/frontend/client/src/views/admin/layouts/relationships.js index 5dcb5e763e..c0264f0b4a 100644 --- a/frontend/client/src/views/admin/layouts/relationships.js +++ b/frontend/client/src/views/admin/layouts/relationships.js @@ -21,69 +21,69 @@ Espo.define('Views.Admin.Layouts.Relationships', 'Views.Admin.Layouts.Rows', function (Dep) { - return Dep.extend({ + return Dep.extend({ - dataAttributes: ['name'], + dataAttributes: ['name'], - editable: false, + editable: false, - setup: function () { - Dep.prototype.setup.call(this); + setup: function () { + Dep.prototype.setup.call(this); - this.wait(true); + this.wait(true); - this.getModelFactory().create(this.scope, function (model) { - this.getHelper().layoutManager.get(this.scope, this.type, function (layout) { + this.getModelFactory().create(this.scope, function (model) { + this.getHelper().layoutManager.get(this.scope, this.type, function (layout) { - var allFields = []; - for (var field in model.defs.links) { - if (['hasMany', 'hasChildren'].indexOf(model.defs.links[field].type) != -1) { - allFields.push(field); - } - } + var allFields = []; + for (var field in model.defs.links) { + if (['hasMany', 'hasChildren'].indexOf(model.defs.links[field].type) != -1) { + allFields.push(field); + } + } - this.enabledFieldsList = []; + this.enabledFieldsList = []; - this.enabledFields = []; - this.disabledFields = []; - for (var i in layout) { - this.enabledFields.push({ - name: layout[i], - label: this.getLanguage().translate(layout[i], 'links', this.scope) - }); - this.enabledFieldsList.push(layout[i]); - } + this.enabledFields = []; + this.disabledFields = []; + for (var i in layout) { + this.enabledFields.push({ + name: layout[i], + label: this.getLanguage().translate(layout[i], 'links', this.scope) + }); + this.enabledFieldsList.push(layout[i]); + } - for (var i in allFields) { - if (!_.contains(this.enabledFieldsList, allFields[i])) { - this.disabledFields.push({ - name: allFields[i], - label: this.getLanguage().translate(allFields[i], 'links', this.scope) - }); - } - } - this.rowLayout = this.enabledFields; + for (var i in allFields) { + if (!_.contains(this.enabledFieldsList, allFields[i])) { + this.disabledFields.push({ + name: allFields[i], + label: this.getLanguage().translate(allFields[i], 'links', this.scope) + }); + } + } + this.rowLayout = this.enabledFields; - for (var i in this.rowLayout) { - this.rowLayout[i].label = this.getLanguage().translate(this.rowLayout[i].name, 'links', this.scope); - } + for (var i in this.rowLayout) { + this.rowLayout[i].label = this.getLanguage().translate(this.rowLayout[i].name, 'links', this.scope); + } - this.wait(false); - }.bind(this), false); - }.bind(this)); - }, + this.wait(false); + }.bind(this), false); + }.bind(this)); + }, - fetch: function () { - var layout = []; - $("#layout ul.enabled > li").each(function (i, el) { - layout.push($(el).data('name')); - }.bind(this)); - return layout; - }, + fetch: function () { + var layout = []; + $("#layout ul.enabled > li").each(function (i, el) { + layout.push($(el).data('name')); + }.bind(this)); + return layout; + }, - validate: function () { - return true; - }, - }); + validate: function () { + return true; + }, + }); }); diff --git a/frontend/client/src/views/admin/layouts/rows.js b/frontend/client/src/views/admin/layouts/rows.js index 68ede95161..03ef9833a8 100644 --- a/frontend/client/src/views/admin/layouts/rows.js +++ b/frontend/client/src/views/admin/layouts/rows.js @@ -18,72 +18,72 @@ * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ - -Espo.define('Views.Admin.Layouts.Rows', 'Views.Admin.Layouts.Base', function (Dep) { + +Espo.define('Views.Admin.Layouts.Rows', 'Views.Admin.Layouts.Base', function (Dep) { - return Dep.extend({ - - template: 'admin.layouts.rows', + return Dep.extend({ + + template: 'admin.layouts.rows', - - events: _.extend({ - 'click #layout a[data-action="editField"]': function (e) { - var data = {}; - this.dataAttributes.forEach(function (attr) { - data[attr] = $(e.target).closest('li').data(Espo.Utils.toDom(attr)) - }); - this.openEditDialog(data); - }, - }, Dep.prototype.events), - - dataAttributes: null, - - dataAttributesDefs: {}, - - editable: false, - - data: function () { - return { - scope: this.scope, - type: this.type, - buttons: this.buttons, - enabledFields: this.enabledFields, - disabledFields: this.disabledFields, - layout: this.rowLayout, - dataAttributes: this.dataAttributes, - dataAttributesDefs: this.dataAttributesDefs, - editable: this.editable, - }; - }, - - afterRender: function () { - $('#layout ul.enabled, #layout ul.disabled').sortable({ - connectWith: '#layout ul.connected' - }); - }, - - fetch: function () { - var layout = []; - $("#layout ul.enabled > li").each(function (i, el) { - var o = {}; - this.dataAttributes.forEach(function (attr) { - var value = $(el).data(Espo.Utils.toDom(attr)) || null; - if (value) { - o[attr] = value; - } - }); - layout.push(o); - }.bind(this)); - return layout; - }, - - validate: function (layout) { - if (layout.length == 0) { - this.notify('Layout cannot be empty', 'error'); - return false; - } - return true; - }, - }); + + events: _.extend({ + 'click #layout a[data-action="editField"]': function (e) { + var data = {}; + this.dataAttributes.forEach(function (attr) { + data[attr] = $(e.target).closest('li').data(Espo.Utils.toDom(attr)) + }); + this.openEditDialog(data); + }, + }, Dep.prototype.events), + + dataAttributes: null, + + dataAttributesDefs: {}, + + editable: false, + + data: function () { + return { + scope: this.scope, + type: this.type, + buttons: this.buttons, + enabledFields: this.enabledFields, + disabledFields: this.disabledFields, + layout: this.rowLayout, + dataAttributes: this.dataAttributes, + dataAttributesDefs: this.dataAttributesDefs, + editable: this.editable, + }; + }, + + afterRender: function () { + $('#layout ul.enabled, #layout ul.disabled').sortable({ + connectWith: '#layout ul.connected' + }); + }, + + fetch: function () { + var layout = []; + $("#layout ul.enabled > li").each(function (i, el) { + var o = {}; + this.dataAttributes.forEach(function (attr) { + var value = $(el).data(Espo.Utils.toDom(attr)) || null; + if (value) { + o[attr] = value; + } + }); + layout.push(o); + }.bind(this)); + return layout; + }, + + validate: function (layout) { + if (layout.length == 0) { + this.notify('Layout cannot be empty', 'error'); + return false; + } + return true; + }, + }); }); diff --git a/frontend/client/src/views/admin/outbound-email.js b/frontend/client/src/views/admin/outbound-email.js index df7f5312c7..8d94b92c29 100644 --- a/frontend/client/src/views/admin/outbound-email.js +++ b/frontend/client/src/views/admin/outbound-email.js @@ -18,73 +18,73 @@ * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ - -Espo.define('Views.Admin.OutboundEmail', 'Views.Settings.Record.Edit', function (Dep) { + +Espo.define('Views.Admin.OutboundEmail', 'Views.Settings.Record.Edit', function (Dep) { - return Dep.extend({ - - layoutName: 'outboundEmail', - - dependencyDefs: { - 'assignmentEmailNotifications': { - map: { - true: [ - { - action: 'show', - fields: ['assignmentEmailNotificationsEntityList'] - } - ] - }, - default: [ - { - action: 'hide', - fields: ['assignmentEmailNotificationsEntityList'] - } - ] - }, - 'smtpAuth': { - map: { - true: [ - { - action: 'show', - fields: ['smtpUsername', 'smtpPassword'] - } - ] - }, - default: [ - { - action: 'hide', - fields: ['smtpUsername', 'smtpPassword'] - } - ] - } - }, - - setup: function () { - Dep.prototype.setup.call(this); - - this.model.defs.fields.assignmentEmailNotificationsEntityList.options = Object.keys(this.getMetadata().get('scopes')).filter(function (scope) { - return this.getMetadata().get('scopes.' + scope + '.tab') && this.getMetadata().get('scopes.' + scope + '.entity'); - }, this); - }, - - afterRender: function () { - Dep.prototype.afterRender.call(this); - - var smtpSecurityField = this.getFieldView('smtpSecurity'); - this.listenTo(smtpSecurityField, 'change', function () { - var smtpSecurity = smtpSecurityField.fetch()['smtpSecurity']; - if (smtpSecurity == 'SSL') { - this.model.set('smtpPort', '465'); - } else if (smtpSecurity == 'TLS') { - this.model.set('smtpPort', '587'); - } else { - this.model.set('smtpPort', '25'); - } - }.bind(this)); - }, - - }); - + return Dep.extend({ + + layoutName: 'outboundEmail', + + dependencyDefs: { + 'assignmentEmailNotifications': { + map: { + true: [ + { + action: 'show', + fields: ['assignmentEmailNotificationsEntityList'] + } + ] + }, + default: [ + { + action: 'hide', + fields: ['assignmentEmailNotificationsEntityList'] + } + ] + }, + 'smtpAuth': { + map: { + true: [ + { + action: 'show', + fields: ['smtpUsername', 'smtpPassword'] + } + ] + }, + default: [ + { + action: 'hide', + fields: ['smtpUsername', 'smtpPassword'] + } + ] + } + }, + + setup: function () { + Dep.prototype.setup.call(this); + + this.model.defs.fields.assignmentEmailNotificationsEntityList.options = Object.keys(this.getMetadata().get('scopes')).filter(function (scope) { + return this.getMetadata().get('scopes.' + scope + '.tab') && this.getMetadata().get('scopes.' + scope + '.entity'); + }, this); + }, + + afterRender: function () { + Dep.prototype.afterRender.call(this); + + var smtpSecurityField = this.getFieldView('smtpSecurity'); + this.listenTo(smtpSecurityField, 'change', function () { + var smtpSecurity = smtpSecurityField.fetch()['smtpSecurity']; + if (smtpSecurity == 'SSL') { + this.model.set('smtpPort', '465'); + } else if (smtpSecurity == 'TLS') { + this.model.set('smtpPort', '587'); + } else { + this.model.set('smtpPort', '25'); + } + }.bind(this)); + }, + + }); + }); diff --git a/frontend/client/src/views/admin/settings.js b/frontend/client/src/views/admin/settings.js index 90f6b2a04e..43e5489363 100644 --- a/frontend/client/src/views/admin/settings.js +++ b/frontend/client/src/views/admin/settings.js @@ -21,15 +21,15 @@ Espo.define('Views.Admin.Settings', 'Views.Settings.Record.Edit', function (Dep) { - return Dep.extend({ - - layoutName: 'settings', + return Dep.extend({ + + layoutName: 'settings', - afterRender: function () { - Dep.prototype.afterRender.call(this); + afterRender: function () { + Dep.prototype.afterRender.call(this); - }, + }, - }); + }); }); diff --git a/frontend/client/src/views/admin/upgrade/done.js b/frontend/client/src/views/admin/upgrade/done.js index 190ecaf91d..319753b91a 100644 --- a/frontend/client/src/views/admin/upgrade/done.js +++ b/frontend/client/src/views/admin/upgrade/done.js @@ -21,41 +21,41 @@ Espo.define('Views.Admin.Upgrade.Done', 'Views.Modal', function (Dep) { - return Dep.extend({ - - cssName: 'done-modal', - - header: false, - - template: 'admin.upgrade.done', - - createButton: true, - - data: function () { - return { - version: this.options.version, - text: this.translate('upgradeDone', 'messages', 'Admin').replace('{version}', this.options.version) - }; - }, - - setup: function () { - this.buttons = [ - { - name: 'close', - label: 'Close', - onClick: function (dialog) { - setTimeout(function () { - this.getRouter().navigate('#Admin', {trigger: true}); - }.bind(this), 500); - dialog.close(); - }.bind(this) - } - ]; - - this.header = this.getLanguage().translate('Upgraded successfully', 'labels', 'Admin'); - - }, - - }); + return Dep.extend({ + + cssName: 'done-modal', + + header: false, + + template: 'admin.upgrade.done', + + createButton: true, + + data: function () { + return { + version: this.options.version, + text: this.translate('upgradeDone', 'messages', 'Admin').replace('{version}', this.options.version) + }; + }, + + setup: function () { + this.buttons = [ + { + name: 'close', + label: 'Close', + onClick: function (dialog) { + setTimeout(function () { + this.getRouter().navigate('#Admin', {trigger: true}); + }.bind(this), 500); + dialog.close(); + }.bind(this) + } + ]; + + this.header = this.getLanguage().translate('Upgraded successfully', 'labels', 'Admin'); + + }, + + }); }); diff --git a/frontend/client/src/views/admin/upgrade/index.js b/frontend/client/src/views/admin/upgrade/index.js index d3c2010e99..3d36816a93 100644 --- a/frontend/client/src/views/admin/upgrade/index.js +++ b/frontend/client/src/views/admin/upgrade/index.js @@ -21,119 +21,119 @@ Espo.define('Views.Admin.Upgrade.Index', 'View', function (Dep) { - return Dep.extend({ + return Dep.extend({ - template: 'admin.upgrade.index', - - packageContents: null, + template: 'admin.upgrade.index', + + packageContents: null, - data: function () { - return { - backupsMsg: this.translate('upgradeBackup', 'messages', 'Admin') - }; - }, + data: function () { + return { + backupsMsg: this.translate('upgradeBackup', 'messages', 'Admin') + }; + }, - events: { - 'change input[name="package"]': function (e) { - this.$el.find('button[data-action="upload"]').addClass('disabled'); - this.$el.find('.message-container').html(''); - var files = e.currentTarget.files; - if (files.length) { - this.selectFile(files[0]); - } - }, - 'click button[data-action="upload"]': function () { - this.upload(); - } - }, + events: { + 'change input[name="package"]': function (e) { + this.$el.find('button[data-action="upload"]').addClass('disabled'); + this.$el.find('.message-container').html(''); + var files = e.currentTarget.files; + if (files.length) { + this.selectFile(files[0]); + } + }, + 'click button[data-action="upload"]': function () { + this.upload(); + } + }, - setup: function () { + setup: function () { - }, - - selectFile: function (file) { - var fileReader = new FileReader(); - fileReader.onload = function (e) { - this.packageContents = e.target.result; - this.$el.find('button[data-action="upload"]').removeClass('disabled'); - }.bind(this); - fileReader.readAsDataURL(file); - }, - - showError: function (msg) { - msg = this.translate(msg, 'errors', 'Admin'); - this.$el.find('.message-container').html(msg); - }, - - upload: function () { - this.$el.find('button[data-action="upload"]').addClass('disabled'); - this.notify('Uploading...'); - $.ajax({ - url: 'Admin/action/uploadUpgradePackage', - type: 'POST', - contentType: 'application/zip', - timeout: 0, - data: this.packageContents, - error: function (xhr, t, e) { - this.showError(xhr.getResponseHeader('X-Status-Reason')); - this.notify(false); - }.bind(this) - }).done(function (data) { - if (!data.id) { - this.showError(this.translate('Error occured')); - return; - } - this.notify(false); - this.createView('popup', 'Admin.Upgrade.Ready', { - upgradeData: data - }, function (view) { - view.render(); - this.$el.find('button[data-action="upload"]').removeClass('disabled'); - - view.once('run', function () { - view.close(); - this.$el.find('.panel.upload').addClass('hidden'); - this.run(data.id, data.version); - }, this); - }.bind(this)); - }.bind(this)).error; - }, - - textNotification: function (text) { - this.$el.find('.notify-text').html(text); - }, - - run: function (id, version) { - var msg = this.translate('Upgrading...', 'labels', 'Admin'); - this.notify('Please wait...'); - this.textNotification(msg); - - $.ajax({ - url: 'Admin/action/runUpgrade', - type: 'POST', - data: JSON.stringify({ - id: id - }), - error: function (xhr) { - this.$el.find('.panel.upload').removeClass('hidden'); - var msg = xhr.getResponseHeader('X-Status-Reason'); - this.textNotification(this.translate('Error') + ': ' + msg); - }.bind(this) - }).done(function () { - var cache = this.getCache(); - if (cache) { - cache.clear(); - } - this.createView('popup', 'Admin.Upgrade.Done', { - version: version - }, function (view) { - this.notify(false); - view.render(); - }.bind(this)); - }.bind(this)); - }, + }, + + selectFile: function (file) { + var fileReader = new FileReader(); + fileReader.onload = function (e) { + this.packageContents = e.target.result; + this.$el.find('button[data-action="upload"]').removeClass('disabled'); + }.bind(this); + fileReader.readAsDataURL(file); + }, + + showError: function (msg) { + msg = this.translate(msg, 'errors', 'Admin'); + this.$el.find('.message-container').html(msg); + }, + + upload: function () { + this.$el.find('button[data-action="upload"]').addClass('disabled'); + this.notify('Uploading...'); + $.ajax({ + url: 'Admin/action/uploadUpgradePackage', + type: 'POST', + contentType: 'application/zip', + timeout: 0, + data: this.packageContents, + error: function (xhr, t, e) { + this.showError(xhr.getResponseHeader('X-Status-Reason')); + this.notify(false); + }.bind(this) + }).done(function (data) { + if (!data.id) { + this.showError(this.translate('Error occured')); + return; + } + this.notify(false); + this.createView('popup', 'Admin.Upgrade.Ready', { + upgradeData: data + }, function (view) { + view.render(); + this.$el.find('button[data-action="upload"]').removeClass('disabled'); + + view.once('run', function () { + view.close(); + this.$el.find('.panel.upload').addClass('hidden'); + this.run(data.id, data.version); + }, this); + }.bind(this)); + }.bind(this)).error; + }, + + textNotification: function (text) { + this.$el.find('.notify-text').html(text); + }, + + run: function (id, version) { + var msg = this.translate('Upgrading...', 'labels', 'Admin'); + this.notify('Please wait...'); + this.textNotification(msg); + + $.ajax({ + url: 'Admin/action/runUpgrade', + type: 'POST', + data: JSON.stringify({ + id: id + }), + error: function (xhr) { + this.$el.find('.panel.upload').removeClass('hidden'); + var msg = xhr.getResponseHeader('X-Status-Reason'); + this.textNotification(this.translate('Error') + ': ' + msg); + }.bind(this) + }).done(function () { + var cache = this.getCache(); + if (cache) { + cache.clear(); + } + this.createView('popup', 'Admin.Upgrade.Done', { + version: version + }, function (view) { + this.notify(false); + view.render(); + }.bind(this)); + }.bind(this)); + }, - }); + }); }); diff --git a/frontend/client/src/views/admin/upgrade/ready.js b/frontend/client/src/views/admin/upgrade/ready.js index bd2c2dade0..7d51b8dd36 100644 --- a/frontend/client/src/views/admin/upgrade/ready.js +++ b/frontend/client/src/views/admin/upgrade/ready.js @@ -21,53 +21,53 @@ Espo.define('Views.Admin.Upgrade.Ready', 'Views.Modal', function (Dep) { - return Dep.extend({ - - cssName: 'ready-modal', - - header: false, - - template: 'admin.upgrade.ready', - - createButton: true, - - data: function () { - return { - version: this.upgradeData.version, - text: this.translate('upgradeVersion', 'messages', 'Admin').replace('{version}', this.upgradeData.version) - }; - }, - - setup: function () { - - this.buttons = [ - { - name: 'run', - label: this.translate('Run Upgrade', 'labels', 'Admin'), - style: 'danger', - onClick: function (dialog) { - this.run(); - }.bind(this) - }, - { - name: 'cancel', - label: 'Cancel', - onClick: function (dialog) { - dialog.close(); - } - } - ]; - - this.upgradeData = this.options.upgradeData; - - this.header = this.getLanguage().translate('Ready for upgrade', 'labels', 'Admin'); - - }, - - run: function () { - this.trigger('run'); - this.remove(); - } - }); + return Dep.extend({ + + cssName: 'ready-modal', + + header: false, + + template: 'admin.upgrade.ready', + + createButton: true, + + data: function () { + return { + version: this.upgradeData.version, + text: this.translate('upgradeVersion', 'messages', 'Admin').replace('{version}', this.upgradeData.version) + }; + }, + + setup: function () { + + this.buttons = [ + { + name: 'run', + label: this.translate('Run Upgrade', 'labels', 'Admin'), + style: 'danger', + onClick: function (dialog) { + this.run(); + }.bind(this) + }, + { + name: 'cancel', + label: 'Cancel', + onClick: function (dialog) { + dialog.close(); + } + } + ]; + + this.upgradeData = this.options.upgradeData; + + this.header = this.getLanguage().translate('Ready for upgrade', 'labels', 'Admin'); + + }, + + run: function () { + this.trigger('run'); + this.remove(); + } + }); }); diff --git a/frontend/client/src/views/admin/user-interface.js b/frontend/client/src/views/admin/user-interface.js index 26ffcdbbdb..86ee9e39dd 100644 --- a/frontend/client/src/views/admin/user-interface.js +++ b/frontend/client/src/views/admin/user-interface.js @@ -19,25 +19,25 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ -Espo.define('Views.Admin.UserInterface', 'Views.Settings.Record.Edit', function (Dep) { +Espo.define('Views.Admin.UserInterface', 'Views.Settings.Record.Edit', function (Dep) { - return Dep.extend({ - - layoutName: 'userInterface', - - setup: function () { - Dep.prototype.setup.call(this); - - this.model.defs.fields.tabList.options = Object.keys(this.getMetadata().get('scopes')).filter(function (scope) { - return this.getMetadata().get('scopes.' + scope + '.tab'); - }, this); - - this.model.defs.fields.quickCreateList.options = Object.keys(this.getMetadata().get('scopes')).filter(function (scope) { - return this.getMetadata().get('scopes.' + scope + '.entity') && this.getMetadata().get('scopes.' + scope + '.tab'); - }, this); - }, - - }); - + return Dep.extend({ + + layoutName: 'userInterface', + + setup: function () { + Dep.prototype.setup.call(this); + + this.model.defs.fields.tabList.options = Object.keys(this.getMetadata().get('scopes')).filter(function (scope) { + return this.getMetadata().get('scopes.' + scope + '.tab'); + }, this); + + this.model.defs.fields.quickCreateList.options = Object.keys(this.getMetadata().get('scopes')).filter(function (scope) { + return this.getMetadata().get('scopes.' + scope + '.entity') && this.getMetadata().get('scopes.' + scope + '.tab'); + }, this); + }, + + }); + }); diff --git a/frontend/client/src/views/base.js b/frontend/client/src/views/base.js index f0c41b27ae..5383a89fb0 100644 --- a/frontend/client/src/views/base.js +++ b/frontend/client/src/views/base.js @@ -19,8 +19,8 @@ * along with EspoCRM. If not, see http://www.gnu.org/licenses/. ************************************************************************/ Espo.define('Views.Base', 'View', function (Dep) { - - return Dep.extend({ - }); + + return Dep.extend({ + }); }); diff --git a/frontend/client/src/views/dashboard.js b/frontend/client/src/views/dashboard.js index 05cbaec82e..8f4efc3a74 100644 --- a/frontend/client/src/views/dashboard.js +++ b/frontend/client/src/views/dashboard.js @@ -21,146 +21,146 @@ Espo.define('Views.Dashboard', 'View', function (Dep) { - return Dep.extend({ - - template: 'dashboard', - - dashboardLayout: null, - - events: { - 'click button.add-dashlet': function () { - this.createView('addDashlet', 'Modals.AddDashlet', {}, function (view) { - view.render(); - }); - }, - }, - - getDashletsLayout: function (callback) { - var dashboardLayout = this.dashboardLayout = this.getPreferences().get('dashboardLayout') || [[],[]]; - - if (this.dashboardLayout.length == 0) { - this.dashboardLayout = dashboardLayout = [[], []]; - } - - var layout = { - type: 'columns-2', - layout: [], - }; - dashboardLayout.forEach(function (col) { - var c = []; - col.forEach(function (defs) { - if (defs && defs.name && defs.id) { - var o = { - name: 'dashlet-' + defs.id, - id: 'dashlet-container-' + defs.id, - view: 'Dashlet', - options: { - name: defs.name, - id: defs.id, - } - }; - c.push(o); - } - }); - layout.layout.push(c); - }); - callback(layout); - }, - - setup: function () { - }, - - afterRender: function () { - this.getDashletsLayout(function (layout) { - this.createView('dashlets', 'Base', { - _layout: layout, - el: '#dashlets', - noCache: true, - }, function (view) { - - view.once('after:render', function () { - this.makeSortable(); - }.bind(this)); - view.render(); - }.bind(this)); - }.bind(this)); - }, - - makeSortable: function () { - $('#dashlets > div').css('min-height', '100px'); - $('#dashlets > div').sortable({ - handle: '.dashlet .panel-heading', - connectWith: '#dashlets > div', - forcePlaceholderSize: true, - placeholder: 'dashlet-placeholder', - start: function (e, ui) { - $(ui.placeholder).css('height', $(ui.item).height()); - }, - stop: function (e, ui) { - this.updateDom(); - this.updateDashletsLayout(); - }.bind(this) - }); - }, - - updateDom: function () { - var layout = []; - $('#dashlets > div').each(function (i, col) { - var c = []; - $(col).children().each(function (i, cell) { - var name = $(cell).find('.dashlet').data('name'); - var id = $(cell).find('.dashlet').data('id'); - c.push({ - name: name, - id: id, - }); - }); - layout.push(c); - }); - this.dashboardLayout = layout; - }, - - updateDashletsLayout: function () { - this.getPreferences().set('dashboardLayout', this.dashboardLayout); - this.getPreferences().save({patch: true}); - this.getPreferences().trigger('update'); - }, - - removeDashlet: function (id) { - this.dashboardLayout.forEach(function (col, i) { - col.forEach(function (o, j) { - if (o.id == id) { - col.splice(j, 1); - return; - } - }); - }); - - this.getPreferences().unsetDashletOptions(id); - this.updateDashletsLayout(); - }, - - addDashlet: function (name) { - var id = 'd' + (Math.floor(Math.random() * 1000001)).toString(); - - this.dashboardLayout[0].unshift({ - name: name, - id: id - }); - - this.updateDashletsLayout(); - - $('#dashlets').children().first().prepend('
    '); - - this.getView('dashlets').createView('dashlet-' + id, 'Dashlet', { - label: name, - name: name, - id: id, - el: '#dashlet-container-' + id - }, function (view) { - view.render(); - }); - }, - }); + return Dep.extend({ + + template: 'dashboard', + + dashboardLayout: null, + + events: { + 'click button.add-dashlet': function () { + this.createView('addDashlet', 'Modals.AddDashlet', {}, function (view) { + view.render(); + }); + }, + }, + + getDashletsLayout: function (callback) { + var dashboardLayout = this.dashboardLayout = this.getPreferences().get('dashboardLayout') || [[],[]]; + + if (this.dashboardLayout.length == 0) { + this.dashboardLayout = dashboardLayout = [[], []]; + } + + var layout = { + type: 'columns-2', + layout: [], + }; + dashboardLayout.forEach(function (col) { + var c = []; + col.forEach(function (defs) { + if (defs && defs.name && defs.id) { + var o = { + name: 'dashlet-' + defs.id, + id: 'dashlet-container-' + defs.id, + view: 'Dashlet', + options: { + name: defs.name, + id: defs.id, + } + }; + c.push(o); + } + }); + layout.layout.push(c); + }); + callback(layout); + }, + + setup: function () { + }, + + afterRender: function () { + this.getDashletsLayout(function (layout) { + this.createView('dashlets', 'Base', { + _layout: layout, + el: '#dashlets', + noCache: true, + }, function (view) { + + view.once('after:render', function () { + this.makeSortable(); + }.bind(this)); + view.render(); + }.bind(this)); + }.bind(this)); + }, + + makeSortable: function () { + $('#dashlets > div').css('min-height', '100px'); + $('#dashlets > div').sortable({ + handle: '.dashlet .panel-heading', + connectWith: '#dashlets > div', + forcePlaceholderSize: true, + placeholder: 'dashlet-placeholder', + start: function (e, ui) { + $(ui.placeholder).css('height', $(ui.item).height()); + }, + stop: function (e, ui) { + this.updateDom(); + this.updateDashletsLayout(); + }.bind(this) + }); + }, + + updateDom: function () { + var layout = []; + $('#dashlets > div').each(function (i, col) { + var c = []; + $(col).children().each(function (i, cell) { + var name = $(cell).find('.dashlet').data('name'); + var id = $(cell).find('.dashlet').data('id'); + c.push({ + name: name, + id: id, + }); + }); + layout.push(c); + }); + this.dashboardLayout = layout; + }, + + updateDashletsLayout: function () { + this.getPreferences().set('dashboardLayout', this.dashboardLayout); + this.getPreferences().save({patch: true}); + this.getPreferences().trigger('update'); + }, + + removeDashlet: function (id) { + this.dashboardLayout.forEach(function (col, i) { + col.forEach(function (o, j) { + if (o.id == id) { + col.splice(j, 1); + return; + } + }); + }); + + this.getPreferences().unsetDashletOptions(id); + this.updateDashletsLayout(); + }, + + addDashlet: function (name) { + var id = 'd' + (Math.floor(Math.random() * 1000001)).toString(); + + this.dashboardLayout[0].unshift({ + name: name, + id: id + }); + + this.updateDashletsLayout(); + + $('#dashlets').children().first().prepend('
    '); + + this.getView('dashlets').createView('dashlet-' + id, 'Dashlet', { + label: name, + name: name, + id: id, + el: '#dashlet-container-' + id + }, function (view) { + view.render(); + }); + }, + }); }); diff --git a/frontend/client/src/views/dashlet.js b/frontend/client/src/views/dashlet.js index 8f2337aead..097da6128a 100644 --- a/frontend/client/src/views/dashlet.js +++ b/frontend/client/src/views/dashlet.js @@ -21,80 +21,80 @@ Espo.define('Views.Dashlet', 'View', function (Dep) { - return Dep.extend({ + return Dep.extend({ - name: null, + name: null, - id: null, + id: null, - elId: null, + elId: null, - template: 'dashlet', + template: 'dashlet', - data: function () { - return { - name: this.name, - id: this.id, - title: this.getOption('title'), - isDoubleHeight: this.getOption('isDoubleHeight') - }; - }, + data: function () { + return { + name: this.name, + id: this.id, + title: this.getOption('title'), + isDoubleHeight: this.getOption('isDoubleHeight') + }; + }, - setup: function () { - this.events = this.events || {}; - this.name = this.options.name; - this.id = this.options.id; + setup: function () { + this.events = this.events || {}; + this.name = this.options.name; + this.id = this.options.id; - this.events['click [data-action="refresh"]'] = function (e) { - this.actionRefresh(); - }.bind(this); - this.events['click [data-action="options"]'] = function (e) { - this.actionOptions(); - }; - this.events['click [data-action="remove"]'] = function (e) { - this.actionRemove(); - }; + this.events['click [data-action="refresh"]'] = function (e) { + this.actionRefresh(); + }.bind(this); + this.events['click [data-action="options"]'] = function (e) { + this.actionOptions(); + }; + this.events['click [data-action="remove"]'] = function (e) { + this.actionRemove(); + }; - var bodySelector = '#dashlet-' + this.id + ' .dashlet-body'; - var view = this.getMetadata().get('dashlets.' + this.name + '.view') || 'Dashlets.' + this.name; - - this.createView('body', view, {el: bodySelector, id: this.id}); - }, - - refresh: function () { - this.getView('body').actionRefresh(); - }, + var bodySelector = '#dashlet-' + this.id + ' .dashlet-body'; + var view = this.getMetadata().get('dashlets.' + this.name + '.view') || 'Dashlets.' + this.name; + + this.createView('body', view, {el: bodySelector, id: this.id}); + }, + + refresh: function () { + this.getView('body').actionRefresh(); + }, - actionRefresh: function () { - this.refresh(); - }, + actionRefresh: function () { + this.refresh(); + }, - actionOptions: function () { - var optionsView = this.getView('body').optionsView; - this.createView('options', optionsView, { - name: this.name, - optionsData: this.getOptionsData(), - fields: this.getView('body').optionsFields, - }, function (view) { - view.render(); - }); - }, + actionOptions: function () { + var optionsView = this.getView('body').optionsView; + this.createView('options', optionsView, { + name: this.name, + optionsData: this.getOptionsData(), + fields: this.getView('body').optionsFields, + }, function (view) { + view.render(); + }); + }, - getOptionsData: function () { - return this.getView('body').optionsData; - }, + getOptionsData: function () { + return this.getView('body').optionsData; + }, - getOption: function (key) { - return this.getView('body').getOption(key); - }, + getOption: function (key) { + return this.getView('body').getOption(key); + }, - actionRemove: function () { - var dashboard = this.getParentView().getParentView(); - dashboard.removeDashlet(this.options.id); - this.$el.remove(); - this.remove(); - }, - }); + actionRemove: function () { + var dashboard = this.getParentView().getParentView(); + dashboard.removeDashlet(this.options.id); + this.$el.remove(); + this.remove(); + }, + }); }); diff --git a/frontend/client/src/views/dashlets/abstract/base.js b/frontend/client/src/views/dashlets/abstract/base.js index d467405ab7..01d282658a 100644 --- a/frontend/client/src/views/dashlets/abstract/base.js +++ b/frontend/client/src/views/dashlets/abstract/base.js @@ -21,73 +21,73 @@ Espo.define('Views.Dashlets.Abstract.Base', 'View', function (Dep) { - return Dep.extend({ + return Dep.extend({ - optionsView: 'Dashlets.Options.Base', + optionsView: 'Dashlets.Options.Base', - defaultOptions: null, + defaultOptions: null, - optionsData: null, + optionsData: null, - actionRefresh: function () { - this.setup(); - this.render(); - }, + actionRefresh: function () { + this.setup(); + this.render(); + }, - actionOptions: function () {}, + actionOptions: function () {}, - optionsFields: { - 'title': { - type: 'varchar', - required: true, - }, - 'autorefreshInterval': { - type: 'enumFloat', - options: [0, 0.5, 1, 2, 5, 10], - }, - }, + optionsFields: { + 'title': { + type: 'varchar', + required: true, + }, + 'autorefreshInterval': { + type: 'enumFloat', + options: [0, 0.5, 1, 2, 5, 10], + }, + }, - init: function () { - this.defaultOptions = _.extend({ - title: this.getLanguage().translate(this.name, 'dashlets'), - }, this.defaultOptions || {}); - - - var options = _.clone(this.defaultOptions); - - for (var key in options) { - if (typeof options[key] == 'function') { - options[key] = options[key].call(this); - } - } + init: function () { + this.defaultOptions = _.extend({ + title: this.getLanguage().translate(this.name, 'dashlets'), + }, this.defaultOptions || {}); + + + var options = _.clone(this.defaultOptions); + + for (var key in options) { + if (typeof options[key] == 'function') { + options[key] = options[key].call(this); + } + } - var storedOptions = this.getPreferences().getDashletOptions(this.options.id) || {}; - - this.optionsData = _.extend(options, storedOptions); - - if (this.optionsData.autorefreshInterval || false) { - var interval = this.optionsData.autorefreshInterval * 60000; - - var t; - var process = function () { - t = setTimeout(function () { - this.actionRefresh(); - process(); - }.bind(this), interval); - }.bind(this); - - process(); - - this.once('remove', function () { - clearTimeout(t); - }, this); - } - }, + var storedOptions = this.getPreferences().getDashletOptions(this.options.id) || {}; + + this.optionsData = _.extend(options, storedOptions); + + if (this.optionsData.autorefreshInterval || false) { + var interval = this.optionsData.autorefreshInterval * 60000; + + var t; + var process = function () { + t = setTimeout(function () { + this.actionRefresh(); + process(); + }.bind(this), interval); + }.bind(this); + + process(); + + this.once('remove', function () { + clearTimeout(t); + }, this); + } + }, - getOption: function (key) { - return this.optionsData[key]; - }, - }); + getOption: function (key) { + return this.optionsData[key]; + }, + }); }); diff --git a/frontend/client/src/views/dashlets/abstract/record-list.js b/frontend/client/src/views/dashlets/abstract/record-list.js index 48a6636a4b..e691b86d3c 100644 --- a/frontend/client/src/views/dashlets/abstract/record-list.js +++ b/frontend/client/src/views/dashlets/abstract/record-list.js @@ -21,70 +21,70 @@ Espo.define('Views.Dashlets.Abstract.RecordList', 'Views.Dashlets.Abstract.Base', function (Dep) { - return Dep.extend({ + return Dep.extend({ - name: 'Leads', + name: 'Leads', - scope: null, + scope: null, - listViewColumn: 'Record.List', + listViewColumn: 'Record.List', - listViewExpanded: 'Record.ListExpanded', + listViewExpanded: 'Record.ListExpanded', - _template: '
    {{{list}}}
    ', + _template: '
    {{{list}}}
    ', - layoutType: 'expanded', - - optionsFields: _.extend(_.clone(Dep.prototype.optionsFields), { - 'displayRecords': { - type: 'enumInt', - options: [3,4,5,10,15], - }, - 'isDoubleHeight': { - type: 'bool', - } - }), + layoutType: 'expanded', + + optionsFields: _.extend(_.clone(Dep.prototype.optionsFields), { + 'displayRecords': { + type: 'enumInt', + options: [3,4,5,10,15], + }, + 'isDoubleHeight': { + type: 'bool', + } + }), - afterRender: function () { - this.getCollectionFactory().create(this.scope, function (collection) { - var searchManager = new Espo.SearchManager(collection, 'list', null, this.getDateTime(), this.getOption('searchData')); - - if (!this.getAcl().check(this.scope, 'read')) { - this.$el.find('.list-container').html(this.translate('No Access')); - return; - } + afterRender: function () { + this.getCollectionFactory().create(this.scope, function (collection) { + var searchManager = new Espo.SearchManager(collection, 'list', null, this.getDateTime(), this.getOption('searchData')); + + if (!this.getAcl().check(this.scope, 'read')) { + this.$el.find('.list-container').html(this.translate('No Access')); + return; + } - this.collection = collection; - collection.sortBy = this.getOption('sortBy') || this.collection.sortBy; - collection.asc = this.getOption('asc') || this.collection.asc; - collection.maxSize = this.getOption('displayRecords'); - collection.where = searchManager.getWhere(); - - var viewName = (this.layoutType == 'expanded') ? this.listViewExpanded : this.listViewColumn; + this.collection = collection; + collection.sortBy = this.getOption('sortBy') || this.collection.sortBy; + collection.asc = this.getOption('asc') || this.collection.asc; + collection.maxSize = this.getOption('displayRecords'); + collection.where = searchManager.getWhere(); + + var viewName = (this.layoutType == 'expanded') ? this.listViewExpanded : this.listViewColumn; - this.listenToOnce(collection, 'sync', function () { - this.createView('list', viewName, { - collection: collection, - el: this.$el.selector + ' .list-container', - pagination: this.getOption('pagination') ? 'bottom' : false, - type: 'listDashlet', - rowActionsView: false, - checkboxes: false, - showMore: true, - listLayout: this.getOption(this.layoutType + 'Layout') - }, function (view) { - view.render(); - }); - }, this); - - collection.fetch(); + this.listenToOnce(collection, 'sync', function () { + this.createView('list', viewName, { + collection: collection, + el: this.$el.selector + ' .list-container', + pagination: this.getOption('pagination') ? 'bottom' : false, + type: 'listDashlet', + rowActionsView: false, + checkboxes: false, + showMore: true, + listLayout: this.getOption(this.layoutType + 'Layout') + }, function (view) { + view.render(); + }); + }, this); + + collection.fetch(); - }, this); - }, - - actionRefresh: function () { - this.collection.fetch(); - }, - }); + }, this); + }, + + actionRefresh: function () { + this.collection.fetch(); + }, + }); }); diff --git a/frontend/client/src/views/dashlets/options/base.js b/frontend/client/src/views/dashlets/options/base.js index e9779b0029..5889ee82aa 100644 --- a/frontend/client/src/views/dashlets/options/base.js +++ b/frontend/client/src/views/dashlets/options/base.js @@ -21,132 +21,132 @@ Espo.define('Views.Dashlets.Options.Base', ['Views.Modal', 'Views.Record.Detail'], function (Dep, Detail) { - var self; + var self; - return Dep.extend({ + return Dep.extend({ - name: null, + name: null, - template: 'dashlets.options.base', + template: 'dashlets.options.base', - cssName: 'options-modal', + cssName: 'options-modal', - fieldsMode: 'edit', + fieldsMode: 'edit', - data: function () { - return { - options: this.optionsData, - }; - }, + data: function () { + return { + options: this.optionsData, + }; + }, - buttons: [ - { - name: 'save', - label: 'Save', - style: 'primary', - onClick: function (dialog) { - self.save(dialog); - }, - }, - { - name: 'cancel', - label: 'Cancel', - onClick: function (dialog) { - dialog.close(); - } - } - ], + buttons: [ + { + name: 'save', + label: 'Save', + style: 'primary', + onClick: function (dialog) { + self.save(dialog); + }, + }, + { + name: 'cancel', + label: 'Cancel', + onClick: function (dialog) { + dialog.close(); + } + } + ], - getDetailLayout: function () { - var layout = [{rows: []}]; - var i = 0; - var a = []; - for (var field in this.fields) { + getDetailLayout: function () { + var layout = [{rows: []}]; + var i = 0; + var a = []; + for (var field in this.fields) { - if (!(i % 2)) { - a = []; - layout[0].rows.push(a); - } - a.push({name: field}); - i++; - } - return layout; - }, + if (!(i % 2)) { + a = []; + layout[0].rows.push(a); + } + a.push({name: field}); + i++; + } + return layout; + }, - init: function () { - Dep.prototype.init.call(this); - this.fields = this.options.fields; - this.fieldList = Object.keys(this.fields); - this.optionsData = this.options.optionsData; - }, + init: function () { + Dep.prototype.init.call(this); + this.fields = this.options.fields; + this.fieldList = Object.keys(this.fields); + this.optionsData = this.options.optionsData; + }, - setup: function (dialog) { - this.id = 'dashlet-options'; - - self = this; - var model = this.model = new Espo.Model(); - model.name = 'DashletOptions'; - model.defs = { - fields: this.fields - }; - model.set(this.optionsData); + setup: function (dialog) { + this.id = 'dashlet-options'; + + self = this; + var model = this.model = new Espo.Model(); + model.name = 'DashletOptions'; + model.defs = { + fields: this.fields + }; + model.set(this.optionsData); - this.createView('record', 'Base', { - model: model, - _layout: { - type: 'record', - layout: Detail.prototype.convertDetailLayout.call(this, this.getDetailLayout()) - }, - el: this.id + ' .record', - layoutData: { - model: model, - columnCount: 2, - }, - }); + this.createView('record', 'Base', { + model: model, + _layout: { + type: 'record', + layout: Detail.prototype.convertDetailLayout.call(this, this.getDetailLayout()) + }, + el: this.id + ' .record', + layoutData: { + model: model, + columnCount: 2, + }, + }); - this.header = this.getLanguage().translate('Dashlet Options') + ': ' + this.getLanguage().translate(this.name, 'dashlets'); - }, - - save: function (dialog) { - var attributes = {}; - this.fieldList.forEach(function (field) { - var fieldView = this.getView('record').getView(field); - _.extend(attributes, fieldView.fetch()); - }, this); - - this.model.set(attributes, {silent: true}); - - var valid = true; - this.fieldList.forEach(function (field) { - var fieldView = this.getView('record').getView(field); - valid = !fieldView.validate() && valid; - }, this); - - if (!valid) { - this.notify('Not Valid', 'error'); - return; - } - - var id = this.getParentView().id; - - this.notify('Saving...'); - this.getPreferences().setDashletOptions(id, attributes); - - this.getPreferences().once('sync', function () { - this.notify(false); - var dashlet = this.getParentView(); - - this.close(); - - dashlet.setup(); - dashlet.render(); - - }, this); - - this.getPreferences().save(); - this.getPreferences().trigger('update'); - }, - }); + this.header = this.getLanguage().translate('Dashlet Options') + ': ' + this.getLanguage().translate(this.name, 'dashlets'); + }, + + save: function (dialog) { + var attributes = {}; + this.fieldList.forEach(function (field) { + var fieldView = this.getView('record').getView(field); + _.extend(attributes, fieldView.fetch()); + }, this); + + this.model.set(attributes, {silent: true}); + + var valid = true; + this.fieldList.forEach(function (field) { + var fieldView = this.getView('record').getView(field); + valid = !fieldView.validate() && valid; + }, this); + + if (!valid) { + this.notify('Not Valid', 'error'); + return; + } + + var id = this.getParentView().id; + + this.notify('Saving...'); + this.getPreferences().setDashletOptions(id, attributes); + + this.getPreferences().once('sync', function () { + this.notify(false); + var dashlet = this.getParentView(); + + this.close(); + + dashlet.setup(); + dashlet.render(); + + }, this); + + this.getPreferences().save(); + this.getPreferences().trigger('update'); + }, + }); }); diff --git a/frontend/client/src/views/dashlets/stream.js b/frontend/client/src/views/dashlets/stream.js index eaf9901428..f6619c1157 100644 --- a/frontend/client/src/views/dashlets/stream.js +++ b/frontend/client/src/views/dashlets/stream.js @@ -21,56 +21,56 @@ Espo.define('Views.Dashlets.Stream', 'Views.Dashlets.Abstract.Base', function (Dep) { - return Dep.extend({ - - name: 'Stream', + return Dep.extend({ + + name: 'Stream', - defaultOptions: { - displayRecords: 5, - autorefreshInterval: 0.5, - isDoubleHeight: false - }, - - _template: '
    {{{list}}}
    ', - - optionsFields: _.extend(_.clone(Dep.prototype.optionsFields), { - 'displayRecords': { - type: 'enumInt', - options: [3,4,5,10,15] - }, - 'isDoubleHeight': { - type: 'bool', - }, - }), - - actionRefresh: function () { - this.getView('list').showNewRecords(); - }, - - afterRender: function () { - - this.getCollectionFactory().create('Note', function (collection) { - this.collection = collection; - - collection.url = 'Stream'; - collection.maxSize = this.getOption('displayRecords'); - - this.listenToOnce(collection, 'sync', function () { - this.createView('list', 'Stream.List', { - el: this.options.el + ' > .list-container', - collection: collection, - isUserStream: true, - }, function (view) { - view.render(); - }); - }.bind(this)); - collection.fetch(); - - }, this); - }, - + defaultOptions: { + displayRecords: 5, + autorefreshInterval: 0.5, + isDoubleHeight: false + }, + + _template: '
    {{{list}}}
    ', + + optionsFields: _.extend(_.clone(Dep.prototype.optionsFields), { + 'displayRecords': { + type: 'enumInt', + options: [3,4,5,10,15] + }, + 'isDoubleHeight': { + type: 'bool', + }, + }), + + actionRefresh: function () { + this.getView('list').showNewRecords(); + }, + + afterRender: function () { + + this.getCollectionFactory().create('Note', function (collection) { + this.collection = collection; + + collection.url = 'Stream'; + collection.maxSize = this.getOption('displayRecords'); + + this.listenToOnce(collection, 'sync', function () { + this.createView('list', 'Stream.List', { + el: this.options.el + ' > .list-container', + collection: collection, + isUserStream: true, + }, function (view) { + view.render(); + }); + }.bind(this)); + collection.fetch(); + + }, this); + }, + - }); + }); }); diff --git a/frontend/client/src/views/detail.js b/frontend/client/src/views/detail.js index afda3ec48b..9dfe3f2f53 100644 --- a/frontend/client/src/views/detail.js +++ b/frontend/client/src/views/detail.js @@ -21,270 +21,270 @@ Espo.define('Views.Detail', 'Views.Main', function (Dep) { - return Dep.extend({ + return Dep.extend({ - template: 'detail', + template: 'detail', - el: '#main', + el: '#main', - scope: null, + scope: null, - name: 'Detail', - - optionsToPass: [], + name: 'Detail', + + optionsToPass: [], - views: { - header: { - selector: '> .page-header', - view: 'Header' - }, - body: { - view: 'Record.Detail', - selector: '> .body', - } - }, - - addUnfollowButtonToMenu: function () { - this.menu.buttons.unshift({ - name: 'unfollow', - label: 'Followed', - style: 'success', - action: 'unfollow' - }); - - var index = -1; - this.menu.buttons.forEach(function (data, i) { - if (data.name == 'follow') { - var index = i; - return; - } - }, this); - if (~index) { - this.menu.buttons.splice(index, 1); - } - }, - - addFollowButtonToMenu: function () { - this.menu.buttons.unshift({ - name: 'follow', - label: 'Follow', - style: 'default', - icon: 'glyphicon glyphicon-share-alt', - action: 'follow' - }); - - var index = -1; - this.menu.buttons.forEach(function (data, i) { - if (data.name == 'unfollow') { - var index = i; - return; - } - }, this); - if (~index) { - this.menu.buttons.splice(index, 1); - } - }, - - setup: function () { - Dep.prototype.setup.call(this); - - if (this.getMetadata().get('scopes.' + this.scope + '.stream')) { - if (this.model.has('isFollowed')) { - if (this.model.get('isFollowed')) { - this.addUnfollowButtonToMenu(); - } else { - this.addFollowButtonToMenu(); - } - } else { - this.once('after:render', function () { - var proceed = function () { - if (this.model.get('isFollowed')) { - this.addUnfollowButton(); - this.addUnfollowButtonToMenu(); - } else { - this.addFollowButton(); - this.addFollowButtonToMenu(); - - } - }.bind(this); - - if (this.model.has('isFollowed')) { - proceed(); - } else { - this.listenToOnce(this.model, 'sync', function () { - if (this.model.has('isFollowed')) { - proceed(); - } - }.bind(this)); - } + views: { + header: { + selector: '> .page-header', + view: 'Header' + }, + body: { + view: 'Record.Detail', + selector: '> .body', + } + }, + + addUnfollowButtonToMenu: function () { + this.menu.buttons.unshift({ + name: 'unfollow', + label: 'Followed', + style: 'success', + action: 'unfollow' + }); + + var index = -1; + this.menu.buttons.forEach(function (data, i) { + if (data.name == 'follow') { + var index = i; + return; + } + }, this); + if (~index) { + this.menu.buttons.splice(index, 1); + } + }, + + addFollowButtonToMenu: function () { + this.menu.buttons.unshift({ + name: 'follow', + label: 'Follow', + style: 'default', + icon: 'glyphicon glyphicon-share-alt', + action: 'follow' + }); + + var index = -1; + this.menu.buttons.forEach(function (data, i) { + if (data.name == 'unfollow') { + var index = i; + return; + } + }, this); + if (~index) { + this.menu.buttons.splice(index, 1); + } + }, + + setup: function () { + Dep.prototype.setup.call(this); + + if (this.getMetadata().get('scopes.' + this.scope + '.stream')) { + if (this.model.has('isFollowed')) { + if (this.model.get('isFollowed')) { + this.addUnfollowButtonToMenu(); + } else { + this.addFollowButtonToMenu(); + } + } else { + this.once('after:render', function () { + var proceed = function () { + if (this.model.get('isFollowed')) { + this.addUnfollowButton(); + this.addUnfollowButtonToMenu(); + } else { + this.addFollowButton(); + this.addFollowButtonToMenu(); + + } + }.bind(this); + + if (this.model.has('isFollowed')) { + proceed(); + } else { + this.listenToOnce(this.model, 'sync', function () { + if (this.model.has('isFollowed')) { + proceed(); + } + }.bind(this)); + } - }, this); - } - } - }, - - addFollowButton: function () { - $el = $('