This commit is contained in:
Yuri Kuznetsov
2023-07-30 16:45:40 +03:00
parent fcc990ac24
commit 2888e1fadd
26 changed files with 1213 additions and 1241 deletions
+10 -13
View File
@@ -26,23 +26,20 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
import Dep from 'views/fields/currency';
import CurrencyFieldView from 'views/fields/currency';
/**
* @class Class
* @extends module:views/fields/currency
*/
export default Dep.extend(/** @lends Class# */{
class CurrencyConvertedFieldView extends CurrencyFieldView {
data: function () {
let currencyValue = this.getConfig().get('defaultCurrency');
data() {
let data = super.data();
let data = Dep.prototype.data.call(this);
const currencyValue = this.getConfig().get('defaultCurrency');
data.currencyValue = currencyValue;
data.currencySymbol = this.getMetadata()
.get(['app', 'currency', 'symbolMap', currencyValue]) || '';
data.currencySymbol = this.getMetadata().get(['app', 'currency', 'symbolMap', currencyValue]) || '';
return data;
},
});
}
}
export default CurrencyConvertedFieldView;
+37 -36
View File
@@ -26,50 +26,51 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/foreign-array', ['views/fields/array'], function (Dep) {
import ArrayFieldView from 'views/fields/array';
return Dep.extend({
class ForeignArrayFieldView extends ArrayFieldView {
type: 'foreign',
type = 'foreign'
setupOptions: function () {
this.params.options = [];
setupOptions() {
this.params.options = [];
let field = this.params.field;
let link = this.params.link;
let field = this.params.field;
let link = this.params.link;
if (!field || !link) {
return;
}
if (!field || !link) {
return;
}
let scope = this.getMetadata().get(['entityDefs', this.model.entityType, 'links', link, 'entity']);
let scope = this.getMetadata().get(['entityDefs', this.model.entityType, 'links', link, 'entity']);
if (!scope) {
return;
}
if (!scope) {
return;
}
let {
optionsPath,
translation,
options,
isSorted,
displayAsLabel,
style,
} = this.getMetadata()
.get(['entityDefs', scope, 'fields', field]);
let {
optionsPath,
translation,
options,
isSorted,
displayAsLabel,
style,
} = this.getMetadata()
.get(['entityDefs', scope, 'fields', field]);
options = optionsPath ? this.getMetadata().get(optionsPath) : options;
options = optionsPath ? this.getMetadata().get(optionsPath) : options;
this.params.options = Espo.Utils.clone(options) || [];
this.params.translation = translation;
this.params.isSorted = isSorted || false;
this.params.displayAsLabel = displayAsLabel || false;
this.styleMap = style || {};
this.params.options = Espo.Utils.clone(options) || [];
this.params.translation = translation;
this.params.isSorted = isSorted || false;
this.params.displayAsLabel = displayAsLabel || false;
this.styleMap = style || {};
this.translatedOptions = Object.fromEntries(
this.params.options
.map(item => [item, this.getLanguage().translateOption(item, field, scope)])
);
},
});
});
this.translatedOptions = Object.fromEntries(
this.params.options
.map(item => [item, this.getLanguage().translateOption(item, field, scope)])
);
}
}
export default ForeignArrayFieldView;
+15 -14
View File
@@ -26,23 +26,24 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/foreign-bool', ['views/fields/bool', 'helpers/misc/foreign-field'], function (Dep, Helper) {
import BoolFieldView from 'views/fields/bool';
import Helper from 'helpers/misc/foreign-field';
return Dep.extend({
class ForeignBoolFieldView extends BoolFieldView {
type: 'foreign',
type = 'foreign'
setup: function () {
Dep.prototype.setup.call(this);
setup() {
super.setup();
/** @var {module:helpers/misc/foreign-field} */
let helper = new Helper(this);
let helper = new Helper(this);
let foreignParams = helper.getForeignParams();
let foreignParams = helper.getForeignParams();
for (let param in foreignParams) {
this.params[param] = foreignParams[param];
}
},
});
});
for (let param in foreignParams) {
this.params[param] = foreignParams[param];
}
}
}
export default ForeignBoolFieldView;
+26 -25
View File
@@ -26,38 +26,39 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/foreign-checklist', ['views/fields/checklist'], function (Dep) {
import ChecklistFieldView from 'views/fields/checklist';
return Dep.extend({
class ForeignChecklistFieldView extends ChecklistFieldView {
type: 'foreign',
type = 'foreign'
setupOptions: function () {
this.params.options = [];
setupOptions() {
this.params.options = [];
if (!this.params.field || !this.params.link) {
return;
}
if (!this.params.field || !this.params.link) {
return;
}
var scope = this.getMetadata()
.get(['entityDefs', this.model.entityType, 'links', this.params.link, 'entity']);
const scope = this.getMetadata()
.get(['entityDefs', this.model.entityType, 'links', this.params.link, 'entity']);
if (!scope) {
return;
}
if (!scope) {
return;
}
this.params.isSorted = this.getMetadata()
.get(['entityDefs', scope, 'fields', this.params.field, 'isSorted']) || false;
this.params.isSorted = this.getMetadata()
.get(['entityDefs', scope, 'fields', this.params.field, 'isSorted']) || false;
this.params.options = this.getMetadata()
.get(['entityDefs', scope, 'fields', this.params.field, 'options']) || [];
this.params.options = this.getMetadata()
.get(['entityDefs', scope, 'fields', this.params.field, 'options']) || [];
this.translatedOptions = {};
this.translatedOptions = {};
this.params.options.forEach(item => {
this.translatedOptions[item] = this.getLanguage()
.translateOption(item, this.params.field, scope);
});
},
});
});
this.params.options.forEach(item => {
this.translatedOptions[item] = this.getLanguage()
.translateOption(item, this.params.field, scope);
});
}
}
export default ForeignChecklistFieldView;
@@ -26,10 +26,11 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/foreign-currency-converted', ['views/fields/currency-converted'], function (Dep) {
import CurrencyConvertedFieldView from 'views/fields/currency-converted';
return Dep.extend({
class ForeignCurrencyConvertedFieldView extends CurrencyConvertedFieldView {
type: 'foreign',
});
});
type = 'foreign'
}
export default ForeignCurrencyConvertedFieldView;
+14 -14
View File
@@ -26,24 +26,24 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/foreign-date', ['views/fields/date', 'helpers/misc/foreign-field'], function (Dep, Helper) {
import DateFieldView from 'views/fields/date';
import Helper from 'helpers/misc/foreign-field';
return Dep.extend({
class ForeignDateFieldView extends DateFieldView {
type: 'foreign',
type = 'foreign'
setup: function () {
Dep.prototype.setup.call(this);
setup() {
super.setup();
/** @var {module:helpers/misc/foreign-field} */
let helper = new Helper(this);
const helper = new Helper(this);
let foreignParams = helper.getForeignParams();
const foreignParams = helper.getForeignParams();
for (let param in foreignParams) {
this.params[param] = foreignParams[param];
}
},
});
});
for (let param in foreignParams) {
this.params[param] = foreignParams[param];
}
}
}
export default ForeignDateFieldView;
+14 -15
View File
@@ -26,25 +26,24 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/foreign-datetime', ['views/fields/datetime', 'helpers/misc/foreign-field'],
function (Dep, Helper) {
import DatetimeFieldView from 'views/fields/datetime';
import Helper from 'helpers/misc/foreign-field';
return Dep.extend({
class ForeignDatetimeFieldView extends DatetimeFieldView {
type: 'foreign',
type = 'foreign'
setup: function () {
Dep.prototype.setup.call(this);
setup() {
super.setup();
/** @var {module:helpers/misc/foreign-field} */
let helper = new Helper(this);
const helper = new Helper(this);
let foreignParams = helper.getForeignParams();
const foreignParams = helper.getForeignParams();
for (let param in foreignParams) {
this.params[param] = foreignParams[param];
}
},
});
});
for (let param in foreignParams) {
this.params[param] = foreignParams[param];
}
}
}
export default ForeignDatetimeFieldView;
+6 -6
View File
@@ -26,12 +26,12 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/foreign-email', ['views/fields/email'], function (Dep) {
import EmailFieldView from 'views/fields/email';
return Dep.extend({
class ForeignEmailFieldView extends EmailFieldView {
type: 'foreign',
type = 'foreign'
readOnly = true
}
readOnly: true,
});
});
export default ForeignEmailFieldView;
+36 -36
View File
@@ -26,50 +26,50 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/foreign-enum', ['views/fields/enum'], function (Dep) {
import EnumFieldView from 'views/fields/enum';
return Dep.extend({
class ForeignEnumFieldView extends EnumFieldView {
type: 'foreign',
type = 'foreign'
setupOptions: function () {
this.params.options = [];
setupOptions() {
this.params.options = [];
let field = this.params.field;
let link = this.params.link;
let field = this.params.field;
let link = this.params.link;
if (!field || !link) {
return;
}
if (!field || !link) {
return;
}
let scope = this.getMetadata().get(['entityDefs', this.model.entityType, 'links', link, 'entity']);
let scope = this.getMetadata().get(['entityDefs', this.model.entityType, 'links', link, 'entity']);
if (!scope) {
return;
}
if (!scope) {
return;
}
let {
optionsPath,
translation,
options,
isSorted,
displayAsLabel,
style,
} = this.getMetadata()
.get(['entityDefs', scope, 'fields', field]);
let {
optionsPath,
translation,
options,
isSorted,
displayAsLabel,
style,
} = this.getMetadata().get(['entityDefs', scope, 'fields', field]);
options = optionsPath ? this.getMetadata().get(optionsPath) : options;
options = optionsPath ? this.getMetadata().get(optionsPath) : options;
this.params.options = Espo.Utils.clone(options) || [];
this.params.translation = translation;
this.params.isSorted = isSorted || false;
this.params.displayAsLabel = displayAsLabel || false;
this.styleMap = style || {};
this.params.options = Espo.Utils.clone(options) || [];
this.params.translation = translation;
this.params.isSorted = isSorted || false;
this.params.displayAsLabel = displayAsLabel || false;
this.styleMap = style || {};
this.translatedOptions = Object.fromEntries(
this.params.options
.map(item => [item, this.getLanguage().translateOption(item, field, scope)])
);
},
});
});
this.translatedOptions = Object.fromEntries(
this.params.options
.map(item => [item, this.getLanguage().translateOption(item, field, scope)])
);
}
}
export default ForeignEnumFieldView;
+15 -14
View File
@@ -26,23 +26,24 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/foreign-float', ['views/fields/float', 'helpers/misc/foreign-field'], function (Dep, Helper) {
import FloatFieldView from 'views/fields/float';
import Helper from 'helpers/misc/foreign-field';
return Dep.extend({
class ForeignFloatFieldView extends FloatFieldView {
type: 'foreign',
type = 'foreign'
setup: function () {
Dep.prototype.setup.call(this);
setup() {
super.setup();
/** @var {module:helpers/misc/foreign-field} */
let helper = new Helper(this);
const helper = new Helper(this);
let foreignParams = helper.getForeignParams();
const foreignParams = helper.getForeignParams();
for (let param in foreignParams) {
this.params[param] = foreignParams[param];
}
},
});
});
for (let param in foreignParams) {
this.params[param] = foreignParams[param];
}
}
}
export default ForeignFloatFieldView;
+16 -16
View File
@@ -26,27 +26,27 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/foreign-int',
['views/fields/int', 'helpers/misc/foreign-field'], function (Dep, Helper) {
import IntFieldView from 'views/fields/int';
import Helper from 'helpers/misc/foreign-field';
return Dep.extend({
class ForeignIntFieldView extends IntFieldView {
type: 'foreign',
type = 'foreign'
setup: function () {
Dep.prototype.setup.call(this);
setup() {
super.setup();
/** @var {module:helpers/misc/foreign-field} */
let helper = new Helper(this);
const helper = new Helper(this);
let foreignParams = helper.getForeignParams();
const foreignParams = helper.getForeignParams();
for (let param in foreignParams) {
this.params[param] = foreignParams[param];
}
for (let param in foreignParams) {
this.params[param] = foreignParams[param];
}
this.disableFormatting = foreignParams.disableFormatting;
},
});
});
this.disableFormatting = foreignParams.disableFormatting;
}
}
export default ForeignIntFieldView;
+10 -9
View File
@@ -26,15 +26,16 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/foreign-multi-enum', ['views/fields/multi-enum', 'views/fields/foreign-array'],
function (Dep, ForeignArray) {
import MultiEnumFieldView from 'views/fields/multi-enum';
import ForeignArrayFieldView from 'views/fields/foreign-array';
return Dep.extend({
class ForeignMultiEnumFieldView extends MultiEnumFieldView {
type: 'foreign',
type = 'foreign'
setupOptions: function () {
ForeignArray.prototype.setupOptions.call(this);
},
});
});
setupOptions() {
ForeignArrayFieldView.prototype.setupOptions.call(this);
}
}
export default ForeignMultiEnumFieldView;
+6 -6
View File
@@ -26,12 +26,12 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/foreign-phone', ['views/fields/phone'], function (Dep) {
import PhoneFieldView from 'views/fields/phone';
return Dep.extend({
class ForeignPhoneFieldView extends PhoneFieldView {
type: 'foreign',
type = 'foreign'
readOnly = true
}
readOnly: true,
});
});
export default ForeignPhoneFieldView;
+15 -14
View File
@@ -26,23 +26,24 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/foreign-text', ['views/fields/text', 'helpers/misc/foreign-field'], function (Dep, Helper) {
import TextFieldView from 'views/fields/text';
import Helper from 'helpers/misc/foreign-field';
return Dep.extend({
class ForeignTextFieldView extends TextFieldView {
type: 'foreign',
type = 'foreign'
setup: function () {
Dep.prototype.setup.call(this);
setup() {
super.setup();
/** @var {module:helpers/misc/foreign-field} */
let helper = new Helper(this);
const helper = new Helper(this);
let foreignParams = helper.getForeignParams();
const foreignParams = helper.getForeignParams();
for (let param in foreignParams) {
this.params[param] = foreignParams[param];
}
},
});
});
for (let param in foreignParams) {
this.params[param] = foreignParams[param];
}
}
}
export default ForeignTextFieldView;
+16 -15
View File
@@ -26,24 +26,25 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/foreign-url-multiple',
['views/fields/url-multiple', 'helpers/misc/foreign-field'], function (Dep, Helper) {
import UrlMultipleFieldView from 'views/fields/url-multiple';
import Helper from 'helpers/misc/foreign-field';
return Dep.extend({
class ForeignUrlMultipleFieldView extends UrlMultipleFieldView {
type: 'foreign',
type = 'foreign'
readOnly = true
setup: function () {
Dep.prototype.setup.call(this);
setup() {
super.setup();
/** @var {module:helpers/misc/foreign-field} */
let helper = new Helper(this);
const helper = new Helper(this);
let foreignParams = helper.getForeignParams();
const foreignParams = helper.getForeignParams();
for (let param in foreignParams) {
this.params[param] = foreignParams[param];
}
},
});
});
for (let param in foreignParams) {
this.params[param] = foreignParams[param];
}
}
}
export default ForeignUrlMultipleFieldView;
+15 -15
View File
@@ -26,25 +26,25 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/foreign-url', ['views/fields/url', 'helpers/misc/foreign-field'], function (Dep, Helper) {
import UrlFieldView from 'views/fields/url';
import Helper from 'helpers/misc/foreign-field';
return Dep.extend({
class ForeignUrlFieldView extends UrlFieldView {
type: 'foreign',
type = 'foreign'
readOnly = true
readOnly: true,
setup() {
super.setup();
setup: function () {
Dep.prototype.setup.call(this);
const helper = new Helper(this);
/** @var {module:helpers/misc/foreign-field.Class} */
let helper = new Helper(this);
const foreignParams = helper.getForeignParams();
let foreignParams = helper.getForeignParams();
for (let param in foreignParams) {
this.params[param] = foreignParams[param];
}
}
}
for (let param in foreignParams) {
this.params[param] = foreignParams[param];
}
},
});
});
export default ForeignUrlFieldView;
+15 -14
View File
@@ -26,23 +26,24 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/foreign-varchar', ['views/fields/varchar', 'helpers/misc/foreign-field'], function (Dep, Helper) {
import VarcharFieldView from 'views/fields/varchar';
import Helper from 'helpers/misc/foreign-field';
return Dep.extend({
class ForeignVarcharFieldView extends VarcharFieldView {
type: 'foreign',
type = 'foreign'
setup: function () {
Dep.prototype.setup.call(this);
setup() {
super.setup();
/** @var {module:helpers/misc/foreign-field.Class} */
let helper = new Helper(this);
const helper = new Helper(this);
let foreignParams = helper.getForeignParams();
const foreignParams = helper.getForeignParams();
for (let param in foreignParams) {
this.params[param] = foreignParams[param];
}
},
});
});
for (let param in foreignParams) {
this.params[param] = foreignParams[param];
}
}
}
export default ForeignVarcharFieldView;
+1
View File
@@ -29,6 +29,7 @@
import BaseFieldView from 'views/fields/base';
class ForeignFieldView extends BaseFieldView {
type = 'foreign'
}
+21 -25
View File
@@ -26,39 +26,35 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/json-object', ['views/fields/base'], function (Dep) {
import BaseFieldView from 'views/fields/base';
return Dep.extend({
class JsonObjectFieldView extends BaseFieldView {
type: 'jsonObject',
type = 'jsonObject'
listTemplate: 'fields/json-object/detail',
listTemplate = 'fields/json-object/detail'
detailTemplate = 'fields/json-object/detail'
detailTemplate: 'fields/json-object/detail',
data() {
const data = super.setup();
data: function () {
var data = Dep.prototype.data.call(this);
data.valueIsSet = this.model.has(this.name);
data.isNotEmpty = !!this.model.get(this.name);
data.valueIsSet = this.model.has(this.name);
data.isNotEmpty = !!this.model.get(this.name);
return data;
}
return data;
},
getValueForDisplay() {
const value = this.model.get(this.name);
getValueForDisplay: function () {
if (!this.model.get(this.name)) {
return null;
}
if (!value) {
return null;
}
var text = JSON.stringify(this.model.get(this.name), false, 2)
.replace(/(\r\n|\n|\r)/gm, '<br>').replace(/\s/g, '&nbsp;');
return JSON.stringify(value, null, 2)
.replace(/(\r\n|\n|\r)/gm, '<br>').replace(/\s/g, '&nbsp;');
}
}
return text;
},
afterRender: function () {
Dep.prototype.afterRender.call(this);
},
});
});
export default JsonObjectFieldView;
+27 -26
View File
@@ -26,37 +26,38 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/link-category-tree', ['views/fields/link'], function (Dep) {
import LinkFieldView from 'views/fields/link';
return Dep.extend({
class LinkCategoryTreeFieldView extends LinkFieldView {
selectRecordsView: 'views/modals/select-category-tree-records',
selectRecordsView = 'views/modals/select-category-tree-records'
autocompleteDisabled = false
autocompleteDisabled: false,
fetchSearch: function () {
var data = Dep.prototype.fetchSearch.call(this);
if (!data) {
return data;
}
if (data.typeFront === 'is') {
data.field = this.name;
data.type = 'inCategory';
}
fetchSearch() {
const data = super.fetchSearch();
if (!data) {
return data;
},
}
getUrl: function () {
let id = this.model.get(this.idName);
if (data.typeFront === 'is') {
data.field = this.name;
data.type = 'inCategory';
}
if (!id) {
return null;
}
return data;
}
return '#' + this.entityType + '/list/categoryId=' + id;
},
});
});
getUrl() {
const id = this.model.get(this.idName);
if (!id) {
return null;
}
return '#' + this.entityType + '/list/categoryId=' + id;
}
}
// noinspection JSUnusedGlobalSymbols
export default LinkCategoryTreeFieldView;
@@ -26,29 +26,30 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/link-multiple-category-tree', ['views/fields/link-multiple'], function (Dep) {
import LinkMultipleFieldView from 'views/fields/link-multiple';
return Dep.extend({
class LinkMultipleCategoryTreeFieldView extends LinkMultipleFieldView {
selectRecordsView: 'views/modals/select-category-tree-records',
selectRecordsView = 'views/modals/select-category-tree-records'
autocompleteDisabled = false
autocompleteDisabled: false,
getUrl(id) {
return '#' + this.entityType + '/list/categoryId=' + id;
}
getUrl: function (id) {
return '#' + this.entityType + '/list/categoryId=' + id;
},
fetchSearch: function () {
var data = Dep.prototype.fetchSearch.call(this);
if (!data) {
return data;
}
data.type = 'inCategory';
fetchSearch() {
const data = super.fetchSearch();
if (!data) {
return data;
},
});
});
}
data.type = 'inCategory';
return data;
}
}
// noinspection JSUnusedGlobalSymbols
export default LinkMultipleCategoryTreeFieldView;
@@ -26,186 +26,178 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define(
'views/fields/link-multiple-with-columns-with-primary',
['views/fields/link-multiple-with-columns', 'views/fields/link-multiple-with-primary'],
function (Dep, LinkMultipleWithPrimary) {
import LinkMultipleWithColumnsFieldView from 'views/fields/link-multiple-with-columns';
import LinkMultipleWithPrimaryFieldView from 'views/fields/link-multiple-with-primary';
/**
* A link-multiple field with columns and a primary.
*/
class LinkMultipleWithColumnsWithPrimaryFieldView extends LinkMultipleWithColumnsFieldView {
/**
* A link-multiple field with columns and a primary.
*
* @class
* @name Class
* @extends module:link-multiple-with-columns.Class
* @memberOf module:link-multiple-with-columns-with-primary
* @protected
* @type {string}
*/
return Dep.extend(/** @lends module:link-multiple-with-columns-with-primary.Class# */{
primaryLink
/**
* @protected
* @type {?string}
*/
primaryLink: null,
getAttributeList() {
let list = super.getAttributeList();
getAttributeList: function () {
let list = Dep.prototype.getAttributeList.call(this);
list.push(this.primaryIdAttribute);
list.push(this.primaryNameAttribute);
list.push(this.primaryIdAttribute);
list.push(this.primaryNameAttribute);
return list;
}
return list;
},
setup() {
this.primaryLink = this.primaryLink || this.model.getFieldParam(this.name, 'primaryLink');
setup: function () {
this.primaryLink = this.primaryLink || this.model.getFieldParam(this.name, 'primaryLink');
this.primaryIdAttribute = this.primaryLink + 'Id';
this.primaryNameAttribute = this.primaryLink + 'Name';
this.primaryIdAttribute = this.primaryLink + 'Id';
this.primaryNameAttribute = this.primaryLink + 'Name';
super.setup();
Dep.prototype.setup.call(this);
this.events['click [data-action="switchPrimary"]'] = e => {
let $target = $(e.currentTarget);
let id = $target.data('id');
this.events['click [data-action="switchPrimary"]'] = e => {
let $target = $(e.currentTarget);
let id = $target.data('id');
LinkMultipleWithPrimaryFieldView.prototype.switchPrimary.call(this, id);
};
LinkMultipleWithPrimary.prototype.switchPrimary.call(this, id);
};
this.primaryId = this.model.get(this.primaryIdAttribute);
this.primaryName = this.model.get(this.primaryNameAttribute);
this.listenTo(this.model, 'change:' + this.primaryIdAttribute, () => {
this.primaryId = this.model.get(this.primaryIdAttribute);
this.primaryName = this.model.get(this.primaryNameAttribute);
});
}
this.listenTo(this.model, 'change:' + this.primaryIdAttribute, () => {
this.primaryId = this.model.get(this.primaryIdAttribute);
this.primaryName = this.model.get(this.primaryNameAttribute);
});
},
setPrimaryId(id) {
this.primaryId = id;
setPrimaryId: function (id) {
this.primaryId = id;
this.primaryName = id ?
this.nameHash[id] : null;
if (id) {
this.primaryName = this.nameHash[id];
} else {
this.primaryName = null;
this.trigger('change');
}
renderLinks() {
if (this.primaryId) {
this.addLinkHtml(this.primaryId, this.primaryName);
}
this.ids.forEach(id => {
if (id !== this.primaryId) {
this.addLinkHtml(id, this.nameHash[id]);
}
});
}
this.trigger('change');
},
getValueForDisplay() {
if (this.isDetailMode() || this.isListMode()) {
let itemList = [];
renderLinks: function () {
if (this.primaryId) {
this.addLinkHtml(this.primaryId, this.primaryName);
itemList.push(
this.getDetailLinkHtml(this.primaryId, this.primaryName)
);
}
this.ids.forEach(id => {
if (!this.ids.length) {
return;
}
this.ids.forEach(id =>{
if (id !== this.primaryId) {
this.addLinkHtml(id, this.nameHash[id]);
}
});
},
getValueForDisplay: function () {
if (this.isDetailMode() || this.isListMode()) {
let itemList = [];
if (this.primaryId) {
itemList.push(
this.getDetailLinkHtml(this.primaryId, this.primaryName)
this.getDetailLinkHtml(id)
);
}
});
if (!this.ids.length) {
return;
}
return itemList
.map(item => $('<div>').append(item).get(0).outerHTML)
.join('');
}
}
this.ids.forEach(id =>{
if (id !== this.primaryId) {
itemList.push(
this.getDetailLinkHtml(id)
);
}
});
deleteLink(id) {
if (id === this.primaryId) {
this.setPrimaryId(null);
}
return itemList
.map(item => $('<div>').append(item).get(0).outerHTML)
.join('');
super.deleteLink(id);
}
deleteLinkHtml(id) {
super.deleteLinkHtml(id);
this.managePrimaryButton();
}
addLinkHtml(id, name) {
name = name || id;
if (this.isSearchMode()) {
return super.addLinkHtml(id, name);
}
if (this.skipRoles) {
return LinkMultipleWithPrimaryFieldView.prototype.addLinkHtml.call(this, id, name);
}
let $el = super.addLinkHtml(id, name);
let isPrimary = (id === this.primaryId);
let $star = $('<span>')
.addClass('fas fa-star fa-sm')
.addClass(!isPrimary ? 'text-muted' : '')
let $button = $('<button>')
.attr('type', 'button')
.addClass('btn btn-link btn-sm pull-right hidden')
.attr('title', this.translate('Primary'))
.attr('data-action', 'switchPrimary')
.attr('data-id', id)
.append($star);
$button.insertAfter($el.children().first().children().first());
this.managePrimaryButton();
return $el;
}
managePrimaryButton() {
let $primary = this.$el.find('button[data-action="switchPrimary"]');
if ($primary.length > 1) {
$primary.removeClass('hidden');
} else {
$primary.addClass('hidden');
}
if ($primary.filter('.active').length === 0) {
let $first = $primary.first();
if ($first.length) {
$first.addClass('active').children().removeClass('text-muted');
this.setPrimaryId($first.data('id'));
}
},
}
}
deleteLink: function (id) {
if (id === this.primaryId) {
this.setPrimaryId(null);
}
fetch() {
const data = super.fetch();
Dep.prototype.deleteLink.call(this, id);
},
data[this.primaryIdAttribute] = this.primaryId;
data[this.primaryNameAttribute] = this.primaryName;
deleteLinkHtml: function (id) {
Dep.prototype.deleteLinkHtml.call(this, id);
return data;
}
}
this.managePrimaryButton();
},
addLinkHtml: function (id, name) {
name = name || id;
if (this.isSearchMode()) {
return Dep.prototype.addLinkHtml.call(this, id, name);
}
if (this.skipRoles) {
return LinkMultipleWithPrimary.prototype.addLinkHtml.call(this, id, name);
}
let $el = Dep.prototype.addLinkHtml.call(this, id, name);
let isPrimary = (id === this.primaryId);
let $star = $('<span>')
.addClass('fas fa-star fa-sm')
.addClass(!isPrimary ? 'text-muted' : '')
let $button = $('<button>')
.attr('type', 'button')
.addClass('btn btn-link btn-sm pull-right hidden')
.attr('title', this.translate('Primary'))
.attr('data-action', 'switchPrimary')
.attr('data-id', id)
.append($star);
$button.insertAfter($el.children().first().children().first());
this.managePrimaryButton();
return $el;
},
managePrimaryButton: function () {
let $primary = this.$el.find('button[data-action="switchPrimary"]');
if ($primary.length > 1) {
$primary.removeClass('hidden');
} else {
$primary.addClass('hidden');
}
if ($primary.filter('.active').length === 0) {
let $first = $primary.first();
if ($first.length) {
$first.addClass('active').children().removeClass('text-muted');
this.setPrimaryId($first.data('id'));
}
}
},
fetch: function () {
let data = Dep.prototype.fetch.call(this);
data[this.primaryIdAttribute] = this.primaryId;
data[this.primaryNameAttribute] = this.primaryName;
return data;
},
});
});
// noinspection JSUnusedGlobalSymbols
export default LinkMultipleWithColumnsWithPrimaryFieldView;
@@ -26,256 +26,243 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/link-multiple-with-primary', ['views/fields/link-multiple'], function (Dep) {
import LinkMultipleFieldView from 'views/fields/link-multiple';
/**
* A link-multiple field with a primary.
*/
class LinkMultipleWithPrimaryFieldView extends LinkMultipleFieldView {
/**
* A link-multiple field with a primary.
*
* @class
* @name Class
* @extends module:views/fields/link-multiple.Class
* @memberOf module:views/fields/link-multiple-with-primary
* @protected
* @type {string}
*/
return Dep.extend(/** @lends module:views/fields/link-multiple-with-primary.Class# */{
primaryLink
/**
* @protected
* @type {?string}
*/
primaryLink: null,
switchPrimary(id) {
let $switch = this.$el.find(`[data-id="${id}"][data-action="switchPrimary"]`);
switchPrimary: function (id) {
let $switch = this.$el.find(`[data-id="${id}"][data-action="switchPrimary"]`);
if (!$switch.hasClass('active')) {
this.$el.find('button[data-action="switchPrimary"]')
.removeClass('active')
.children()
.addClass('text-muted');
if (!$switch.hasClass('active')) {
this.$el.find('button[data-action="switchPrimary"]')
.removeClass('active')
.children()
.addClass('text-muted');
$switch.addClass('active').children().removeClass('text-muted');
$switch.addClass('active').children().removeClass('text-muted');
this.setPrimaryId(id);
}
}
this.setPrimaryId(id);
}
},
/**
* @inheritDoc
*/
getAttributeList() {
const list = super.getAttributeList();
/**
* @inheritDoc
*/
getAttributeList: function () {
var list = Dep.prototype.getAttributeList.call(this);
list.push(this.primaryIdAttribute);
list.push(this.primaryNameAttribute);
list.push(this.primaryIdAttribute);
list.push(this.primaryNameAttribute);
return list;
}
return list;
},
setup() {
this.primaryLink = this.options.primaryLink || this.primaryLink ||
this.model.getFieldParam(this.name, 'primaryLink');
setup: function () {
this.primaryLink = this.options.primaryLink || this.primaryLink ||
this.model.getFieldParam(this.name, 'primaryLink');
this.primaryIdAttribute = this.primaryLink + 'Id';
this.primaryNameAttribute = this.primaryLink + 'Name';
this.primaryIdAttribute = this.primaryLink + 'Id';
this.primaryNameAttribute = this.primaryLink + 'Name';
super.setup();
Dep.prototype.setup.call(this);
this.primaryId = this.model.get(this.primaryIdAttribute);
this.primaryName = this.model.get(this.primaryNameAttribute);
this.listenTo(this.model, 'change:' + this.primaryIdAttribute, () => {
this.primaryId = this.model.get(this.primaryIdAttribute);
this.primaryName = this.model.get(this.primaryNameAttribute);
});
this.listenTo(this.model, 'change:' + this.primaryIdAttribute, () => {
this.primaryId = this.model.get(this.primaryIdAttribute);
this.primaryName = this.model.get(this.primaryNameAttribute);
});
this.events['click [data-action="switchPrimary"]'] = e => {
let $target = $(e.currentTarget);
let id = $target.data('id');
this.events['click [data-action="switchPrimary"]'] = e => {
let $target = $(e.currentTarget);
let id = $target.data('id');
this.switchPrimary(id);
};
}
this.switchPrimary(id);
};
},
/**
* @protected
* @param {string|null} id An ID.
*/
setPrimaryId(id) {
this.primaryId = id;
/**
* @protected
* @param {string} id An ID.
*/
setPrimaryId: function (id) {
this.primaryId = id;
this.primaryName = id ?
this.nameHash[id] : null;
if (id) {
this.primaryName = this.nameHash[id];
}
else {
this.primaryName = null;
this.trigger('change');
}
/**
* @protected
*/
renderLinks() {
if (this.primaryId) {
this.addLinkHtml(this.primaryId, this.primaryName);
}
this.ids.forEach(id => {
if (id !== this.primaryId) {
this.addLinkHtml(id, this.nameHash[id]);
}
});
}
this.trigger('change');
},
/**
* @inheritDoc
*/
getValueForDisplay() {
if (this.isDetailMode() || this.isListMode()) {
let itemList = [];
/**
* @protected
*/
renderLinks: function () {
if (this.primaryId) {
this.addLinkHtml(this.primaryId, this.primaryName);
itemList.push(this.getDetailLinkHtml(this.primaryId, this.primaryName));
}
this.ids.forEach((id) => {
if (!this.ids.length) {
return;
}
this.ids.forEach(id => {
if (id !== this.primaryId) {
this.addLinkHtml(id, this.nameHash[id]);
itemList.push(this.getDetailLinkHtml(id));
}
});
},
/**
* @inheritDoc
*/
getValueForDisplay: function () {
if (this.isDetailMode() || this.isListMode()) {
let itemList = [];
return itemList
.map(item => $('<div>').append(item).get(0).outerHTML)
.join('');
}
}
if (this.primaryId) {
itemList.push(this.getDetailLinkHtml(this.primaryId, this.primaryName));
}
/**
* @inheritDoc
*/
deleteLink(id) {
if (id === this.primaryId) {
this.setPrimaryId(null);
}
if (!this.ids.length) {
return;
}
super.deleteLink(id);
}
this.ids.forEach(id => {
if (id !== this.primaryId) {
itemList.push(this.getDetailLinkHtml(id));
}
});
/**
* @inheritDoc
*/
deleteLinkHtml(id) {
super.deleteLinkHtml(id);
return itemList
.map(item => $('<div>').append(item).get(0).outerHTML)
.join('');
this.managePrimaryButton();
}
/**
* @inheritDoc
*/
addLinkHtml(id, name) {
// Do not use the `html` method to avoid XSS.
name = name || id;
if (this.isSearchMode()) {
return super.addLinkHtml(id, name);
}
let $container = this.$el.find('.link-container');
let $el = $('<div>')
.addClass('form-inline clearfix ')
.addClass('list-group-item link-with-role link-group-item-with-primary')
.addClass('link-' + id)
.attr('data-id', id);
let $name = $('<div>').text(name).append('&nbsp;');
let $remove = $('<a>')
.attr('role', 'button')
.attr('tabindex', '0')
.attr('data-id', id)
.attr('data-action', 'clearLink')
.addClass('pull-right')
.append(
$('<span>').addClass('fas fa-times')
);
let $left = $('<div>');
let $right = $('<div>');
$left.append($name);
$right.append($remove);
$el.append($left);
$el.append($right);
let isPrimary = (id === this.primaryId);
let $star = $('<span>')
.addClass('fas fa-star fa-sm')
.addClass(!isPrimary ? 'text-muted' : '')
let $button = $('<button>')
.attr('type', 'button')
.addClass('btn btn-link btn-sm pull-right hidden')
.attr('title', this.translate('Primary'))
.attr('data-action', 'switchPrimary')
.attr('data-id', id)
.append($star);
$button.insertBefore($el.children().first().children().first());
$container.append($el);
this.managePrimaryButton();
return $el;
}
/**
* @protected
*/
managePrimaryButton() {
let $primary = this.$el.find('button[data-action="switchPrimary"]');
if ($primary.length > 1) {
$primary.removeClass('hidden');
}
else {
$primary.addClass('hidden');
}
if ($primary.filter('.active').length === 0) {
let $first = $primary.first();
if ($first.length) {
$first.addClass('active').children().removeClass('text-muted');
this.setPrimaryId($first.data('id'));
}
},
}
}
/**
* @inheritDoc
*/
deleteLink: function (id) {
if (id === this.primaryId) {
this.setPrimaryId(null);
}
fetch() {
const data = super.fetch();
Dep.prototype.deleteLink.call(this, id);
},
/**
* @inheritDoc
*/
deleteLinkHtml: function (id) {
Dep.prototype.deleteLinkHtml.call(this, id);
this.managePrimaryButton();
},
/**
* @inheritDoc
*/
addLinkHtml: function (id, name) {
// Do not use the `html` method to avoid XSS.
name = name || id;
if (this.isSearchMode()) {
return Dep.prototype.addLinkHtml.call(this, id, name);
}
let $container = this.$el.find('.link-container');
let $el = $('<div>')
.addClass('form-inline clearfix ')
.addClass('list-group-item link-with-role link-group-item-with-primary')
.addClass('link-' + id)
.attr('data-id', id);
let $name = $('<div>').text(name).append('&nbsp;');
let $remove = $('<a>')
.attr('role', 'button')
.attr('tabindex', '0')
.attr('data-id', id)
.attr('data-action', 'clearLink')
.addClass('pull-right')
.append(
$('<span>').addClass('fas fa-times')
);
let $left = $('<div>');
let $right = $('<div>');
$left.append($name);
$right.append($remove);
$el.append($left);
$el.append($right);
let isPrimary = (id === this.primaryId);
let $star = $('<span>')
.addClass('fas fa-star fa-sm')
.addClass(!isPrimary ? 'text-muted' : '')
let $button = $('<button>')
.attr('type', 'button')
.addClass('btn btn-link btn-sm pull-right hidden')
.attr('title', this.translate('Primary'))
.attr('data-action', 'switchPrimary')
.attr('data-id', id)
.append($star);
$button.insertBefore($el.children().first().children().first());
$container.append($el);
this.managePrimaryButton();
return $el;
},
afterRender: function () {
Dep.prototype.afterRender.call(this);
},
/**
* @protected
*/
managePrimaryButton: function () {
let $primary = this.$el.find('button[data-action="switchPrimary"]');
if ($primary.length > 1) {
$primary.removeClass('hidden');
}
else {
$primary.addClass('hidden');
}
if ($primary.filter('.active').length === 0) {
let $first = $primary.first();
if ($first.length) {
$first.addClass('active').children().removeClass('text-muted');
this.setPrimaryId($first.data('id'));
}
}
},
fetch: function () {
let data = Dep.prototype.fetch.call(this);
data[this.primaryIdAttribute] = this.primaryId;
data[this.primaryNameAttribute] = this.primaryName;
return data;
},
});
});
data[this.primaryIdAttribute] = this.primaryId;
data[this.primaryNameAttribute] = this.primaryName;
// noinspection JSValidateTypes
return data;
}
}
export default LinkMultipleWithPrimaryFieldView;
+297 -315
View File
@@ -26,359 +26,341 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/link-multiple-with-role', ['views/fields/link-multiple', 'ui/select'],
function (Dep, /** module:ui/select*/Select) {
import LinkMultipleFieldView from 'views/fields/link-multiple';
import Select from 'ui/select';
/**
* A link-multiple field with a relation column.
* @deprecated Prefer using `link-multiple-with-columns` instead.
*/
class LinkMultipleWithRoleFieldView extends LinkMultipleFieldView {
/**
* A link-multiple field with a relation column.
*
* @inheritDoc Prefer using `link-multiple-with-columns` instead.
*
* @class
* @name Class
* @extends module:views/fields/link-multiple.Class
* @extends module:views/fields/link-multiple.Class
* @memberOf module:views/fields/link-multiple-with-role
* A role field type.
*/
return Dep.extend(/** @lends module:views/fields/link-multiple-with-role.Class# */{
roleType = 'enum'
/**
* A relation column name.
*/
columnName = 'role'
/**
* The role field is defined in a foreign entity.
*/
roleFieldIsForeign = true
/**
* A value to fetch for an empty role.
*/
emptyRoleValue = null
/**
* A role placeholder text.
*/
rolePlaceholderText = null
/**
* A role value max length.
* @protected
*/
roleMaxLength = 50
/**
* A role field type.
*/
roleType: 'enum',
/** @const */
ROLE_TYPE_ENUM = 'enum'
// noinspection JSUnusedGlobalSymbols
/** @const */
ROLE_TYPE_VARCHAR = 'varchar'
/**
* A relation column name.
*/
columnName: 'role',
setup() {
super.setup();
/**
* The role field is defined in a foreign entity.
*/
roleFieldIsForeign: true,
this.columnsName = this.name + 'Columns';
this.columns = Espo.Utils.cloneDeep(this.model.get(this.columnsName) || {});
/**
* A value to fetch for an empty role.
*/
emptyRoleValue: null,
/**
* A role placeholder text.
*/
rolePlaceholderText: null,
/**
* A role value max length.
*
* @protected
*/
roleMaxLength: 50,
/**
* @const
*/
ROLE_TYPE_ENUM: 'enum',
/**
* @const
*/
ROLE_TYPE_VARCHAR: 'varchar',
setup: function () {
Dep.prototype.setup.call(this);
this.columnsName = this.name + 'Columns';
this.listenTo(this.model, 'change:' + this.columnsName, () => {
this.columns = Espo.Utils.cloneDeep(this.model.get(this.columnsName) || {});
});
this.listenTo(this.model, 'change:' + this.columnsName, () => {
this.columns = Espo.Utils.cloneDeep(this.model.get(this.columnsName) || {});
});
this.roleField = this.getMetadata()
.get(['entityDefs', this.model.entityType, 'fields', this.name, 'columns', this.columnName]);
this.roleField = this.getMetadata()
.get(['entityDefs', this.model.entityType, 'fields', this.name, 'columns', this.columnName]);
this.displayRoleAsLabel = this.getMetadata()
.get(['entityDefs', this.model.entityType, 'fields', this.roleField, 'displayAsLabel']);
this.displayRoleAsLabel = this.getMetadata()
.get(['entityDefs', this.model.entityType, 'fields', this.roleField, 'displayAsLabel']);
this.roleFieldScope = this.roleFieldIsForeign ? this.foreignScope : this.model.entityType;
this.roleFieldScope = this.roleFieldIsForeign ? this.foreignScope : this.model.entityType;
if (this.roleType === this.ROLE_TYPE_ENUM && !this.forceRoles) {
this.roleList = this.getMetadata()
.get(['entityDefs', this.roleFieldScope, 'fields', this.roleField, 'options']);
if (this.roleType === this.ROLE_TYPE_ENUM && !this.forceRoles) {
this.roleList = this.getMetadata()
.get(['entityDefs', this.roleFieldScope, 'fields', this.roleField, 'options']);
if (!this.roleList) {
this.roleList = [];
this.skipRoles = true;
}
if (!this.roleList) {
this.roleList = [];
this.skipRoles = true;
}
},
}
}
getAttributeList: function () {
let list = Dep.prototype.getAttributeList.call(this);
getAttributeList() {
const list = super.getAttributeList();
list.push(this.name + 'Columns');
list.push(this.name + 'Columns');
return list;
},
return list;
}
getDetailLinkHtml: function (id, name) {
// Do not use the `html` method to avoid XSS.
getDetailLinkHtml(id, name) {
// Do not use the `html` method to avoid XSS.
name = name || this.nameHash[id] || id;
name = name || this.nameHash[id] || id;
if (!name && id) {
name = this.translate(this.foreignScope, 'scopeNames');
}
if (!name && id) {
name = this.translate(this.foreignScope, 'scopeNames');
}
let role = (this.columns[id] || {})[this.columnName] || '';
let role = (this.columns[id] || {})[this.columnName] || '';
if (this.emptyRoleValue && role === this.emptyRoleValue) {
role = '';
}
if (this.emptyRoleValue && role === this.emptyRoleValue) {
role = '';
}
let $el = $('<div>')
.append(
$('<a>')
.attr('href', '#' + this.foreignScope + '/view/' + id)
.attr('data-id', id)
.text(name)
);
if (this.isDetailMode()) {
let iconHtml = this.getIconHtml(id);
if (iconHtml) {
$el.prepend(iconHtml);
}
}
if (role) {
let style = this.getMetadata()
.get(['entityDefs', this.model.entityType, 'fields', this.roleField, 'style', role]);
let className = 'text';
if (this.displayRoleAsLabel && style && style !== 'default') {
className = 'label label-sm label';
if (style === 'muted') {
style = 'default';
}
} else {
style = style || 'muted';
}
className = className + '-' + style;
let text = this.roleType === this.ROLE_TYPE_ENUM ?
this.getLanguage().translateOption(role, this.roleField, this.roleFieldScope) :
role;
$el.append(
$('<span>').text(' '),
$('<span>').addClass('text-muted chevron-right'),
$('<span>').text(' '),
$('<span>').text(text).addClass('small').addClass(className)
);
}
return $el.get(0).outerHTML;
},
getValueForDisplay: function () {
if (this.isDetailMode() || this.isListMode()) {
let names = [];
this.ids.forEach(id => {
names.push(
this.getDetailLinkHtml(id)
);
});
return names.join('');
}
},
deleteLink: function (id) {
this.trigger('delete-link', id);
this.trigger('delete-link:' + id);
this.deleteLinkHtml(id);
let index = this.ids.indexOf(id);
if (index > -1) {
this.ids.splice(index, 1);
}
delete this.nameHash[id];
delete this.columns[id];
this.afterDeleteLink(id);
this.trigger('change');
},
addLink: function (id, name) {
if (!~this.ids.indexOf(id)) {
this.ids.push(id);
this.nameHash[id] = name;
this.columns[id] = {};
this.columns[id][this.columnName] = null;
this.addLinkHtml(id, name);
this.trigger('add-link', id);
this.trigger('add-link:' + id);
}
this.trigger('change');
},
afterRender: function () {
Dep.prototype.afterRender.call(this);
},
/**
* Build a role select element.
*
* @param {string} id
* @param {string|null} roleValue
* @return {JQuery}
*/
getJQSelect: function (id, roleValue) {
// Do not use the `html` method to avoid XSS.
let $role = $('<select>')
.addClass('role form-control input-sm')
.attr('data-id', id);
this.roleList.forEach(role => {
let text = this.getLanguage().translateOption(role, this.roleField, this.roleFieldScope);
let $option = $('<option>')
.val(role)
.text(text);
if (role === (roleValue || '')) {
$option.attr('selected', 'selected');
}
$role.append($option);
});
return $role;
},
/**
* @inheritDoc
*/
addLinkHtml: function (id, name) {
// Do not use the `html` method to avoid XSS.
name = name || id;
if (this.isSearchMode() || this.skipRoles) {
return Dep.prototype.addLinkHtml.call(this, id, name);
}
let role = (this.columns[id] || {})[this.columnName];
let $container = this.$el.find('.link-container');
let $el = $('<div>')
.addClass('form-inline clearfix')
.addClass('list-group-item link-with-role link-group-item-with-columns')
.addClass('link-' + id);
let $remove = $('<a>')
.attr('role', 'button')
.attr('tabindex', '0')
.attr('data-id', id)
.attr('data-action', 'clearLink')
.addClass('pull-right')
.append(
$('<span>').addClass('fas fa-times')
);
let $left = $('<div>').addClass('pull-left');
let $right = $('<div>').append($remove);
let $name = $('<div>')
.addClass('link-item-name')
.text(name)
.append('&nbsp;')
let $role;
if (this.roleType === this.ROLE_TYPE_ENUM) {
$role = this.getJQSelect(id, role);
}
else {
let text = this.rolePlaceholderText || this.translate(this.roleField, 'fields', this.roleFieldScope);
$role = $('<input>')
.addClass('role form-control input-sm')
.attr('maxlength', this.roleMaxLength) // @todo Get the value from metadata.
.attr('placeholder', text)
let $el = $('<div>')
.append(
$('<a>')
.attr('href', '#' + this.foreignScope + '/view/' + id)
.attr('data-id', id)
.attr('value', role || '');
.text(name)
);
if (this.isDetailMode()) {
let iconHtml = this.getIconHtml(id);
if (iconHtml) {
$el.prepend(iconHtml);
}
}
if (role) {
let style = this.getMetadata()
.get(['entityDefs', this.model.entityType, 'fields', this.roleField, 'style', role]);
let className = 'text';
if (this.displayRoleAsLabel && style && style !== 'default') {
className = 'label label-sm label';
if (style === 'muted') {
style = 'default';
}
} else {
style = style || 'muted';
}
if ($role) {
$left.append($('<span>')
.addClass('link-item-column')
.addClass('link-item-column-' + $role.get(0).tagName.toLowerCase())
.append($role)
className = className + '-' + style;
let text = this.roleType === this.ROLE_TYPE_ENUM ?
this.getLanguage().translateOption(role, this.roleField, this.roleFieldScope) :
role;
$el.append(
$('<span>').text(' '),
$('<span>').addClass('text-muted chevron-right'),
$('<span>').text(' '),
$('<span>').text(text).addClass('small').addClass(className)
);
}
return $el.get(0).outerHTML;
}
getValueForDisplay() {
if (this.isDetailMode() || this.isListMode()) {
let names = [];
this.ids.forEach(id => {
names.push(
this.getDetailLinkHtml(id)
);
});
return names.join('');
}
}
deleteLink(id) {
this.trigger('delete-link', id);
this.trigger('delete-link:' + id);
this.deleteLinkHtml(id);
let index = this.ids.indexOf(id);
if (index > -1) {
this.ids.splice(index, 1);
}
delete this.nameHash[id];
delete this.columns[id];
this.afterDeleteLink(id);
this.trigger('change');
}
addLink(id, name) {
if (!~this.ids.indexOf(id)) {
this.ids.push(id);
this.nameHash[id] = name;
this.columns[id] = {};
this.columns[id][this.columnName] = null;
this.addLinkHtml(id, name);
this.trigger('add-link', id);
this.trigger('add-link:' + id);
}
this.trigger('change');
}
/**
* Build a role select element.
*
* @param {string} id
* @param {string|null} roleValue
* @return {JQuery}
*/
getJQSelect(id, roleValue) {
// Do not use the `html` method to avoid XSS.
let $role = $('<select>')
.addClass('role form-control input-sm')
.attr('data-id', id);
this.roleList.forEach(role => {
let text = this.getLanguage().translateOption(role, this.roleField, this.roleFieldScope);
let $option = $('<option>')
.val(role)
.text(text);
if (role === (roleValue || '')) {
$option.attr('selected', 'selected');
}
$left.append($name);
$el.append($left).append($right);
$container.append($el);
$role.append($option);
});
if ($role && $role.get(0).tagName === 'SELECT') {
Select.init($role);
}
return $role;
}
if (this.isEditMode() && $role) {
let fetch = ($target) => {
if (!$target || !$target.length) {
return;
}
/**
* @inheritDoc
*/
addLinkHtml(id, name) {
// Do not use the `html` method to avoid XSS.
if ($target.val() === null) {
return;
}
name = name || id;
let value = $target.val().toString().trim();
let id = $target.data('id');
if (this.isSearchMode() || this.skipRoles) {
return super.addLinkHtml(id, name);
}
if (value === '') {
value = null;
}
let role = (this.columns[id] || {})[this.columnName];
this.columns[id] = this.columns[id] || {};
this.columns[id][this.columnName] = value;
};
let $container = this.$el.find('.link-container');
$role.on('change', e => {
fetch($(e.currentTarget));
this.trigger('change');
});
let $el = $('<div>')
.addClass('form-inline clearfix')
.addClass('list-group-item link-with-role link-group-item-with-columns')
.addClass('link-' + id);
fetch($role);
}
let $remove = $('<a>')
.attr('role', 'button')
.attr('tabindex', '0')
.attr('data-id', id)
.attr('data-action', 'clearLink')
.addClass('pull-right')
.append(
$('<span>').addClass('fas fa-times')
);
return $el;
},
let $left = $('<div>').addClass('pull-left');
let $right = $('<div>').append($remove);
fetch: function () {
let data = Dep.prototype.fetch.call(this);
let $name = $('<div>')
.addClass('link-item-name')
.text(name)
.append('&nbsp;')
if (!this.skipRoles) {
data[this.columnsName] = Espo.Utils.cloneDeep(this.columns);
}
let $role;
return data;
},
});
});
if (this.roleType === this.ROLE_TYPE_ENUM) {
$role = this.getJQSelect(id, role);
}
else {
let text = this.rolePlaceholderText || this.translate(this.roleField, 'fields', this.roleFieldScope);
$role = $('<input>')
.addClass('role form-control input-sm')
.attr('maxlength', this.roleMaxLength) // @todo Get the value from metadata.
.attr('placeholder', text)
.attr('data-id', id)
.attr('value', role || '');
}
if ($role) {
$left.append($('<span>')
.addClass('link-item-column')
.addClass('link-item-column-' + $role.get(0).tagName.toLowerCase())
.append($role)
);
}
$left.append($name);
$el.append($left).append($right);
$container.append($el);
if ($role && $role.get(0).tagName === 'SELECT') {
Select.init($role);
}
if (this.isEditMode() && $role) {
let fetch = ($target) => {
if (!$target || !$target.length) {
return;
}
if ($target.val() === null) {
return;
}
let value = $target.val().toString().trim();
let id = $target.data('id');
if (value === '') {
value = null;
}
this.columns[id] = this.columns[id] || {};
this.columns[id][this.columnName] = value;
};
$role.on('change', e => {
fetch($(e.currentTarget));
this.trigger('change');
});
fetch($role);
}
return $el;
}
fetch() {
let data = super.data();
if (!this.skipRoles) {
data[this.columnsName] = Espo.Utils.cloneDeep(this.columns);
}
return data;
}
}
// noinspection JSDeprecatedSymbols
export default LinkMultipleWithRoleFieldView;
@@ -26,61 +26,63 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/fields/link-multiple-with-status', ['views/fields/link-multiple'], function (Dep) {
import LinkMultipleFieldView from 'views/fields/link-multiple';
return Dep.extend({
class LinkMultipleWithStatusFieldView extends LinkMultipleFieldView {
setup: function () {
Dep.prototype.setup.call(this);
setup() {
super.setup();
this.columnsName = this.name + 'Columns';
this.columnsName = this.name + 'Columns';
this.columns = Espo.Utils.cloneDeep(this.model.get(this.columnsName) || {});
this.listenTo(this.model, 'change:' + this.columnsName, () => {
this.columns = Espo.Utils.cloneDeep(this.model.get(this.columnsName) || {});
});
this.listenTo(this.model, 'change:' + this.columnsName, () => {
this.columns = Espo.Utils.cloneDeep(this.model.get(this.columnsName) || {});
});
this.statusField = this.getMetadata()
.get(['entityDefs', this.model.entityType, 'fields', this.name, 'columns', 'status']);
this.statusField = this.getMetadata()
.get(['entityDefs', this.model.entityType, 'fields', this.name, 'columns', 'status']);
this.styleMap = this.getMetadata()
.get(['entityDefs', this.foreignScope, 'fields', this.statusField, 'style']) || {};
}
this.styleMap = this.getMetadata()
.get(['entityDefs', this.foreignScope, 'fields', this.statusField, 'style']) || {};
},
getAttributeList() {
const list = super.getAttributeList();
getAttributeList: function () {
let list = Dep.prototype.getAttributeList.call(this);
list.push(this.name + 'Columns');
list.push(this.name + 'Columns');
return list;
}
return list;
},
getDetailLinkHtml(id, name) {
let status = (this.columns[id] || {}).status;
getDetailLinkHtml: function (id, name) {
let status = (this.columns[id] || {}).status;
if (!status) {
return super.getDetailLinkHtml(id, name);
}
if (!status) {
return Dep.prototype.getDetailLinkHtml.call(this, id, name);
}
let style = this.styleMap[status];
let style = this.styleMap[status];
let targetStyleList = ['success', 'danger'];
let targetStyleList = ['success', 'danger'];
if (!style || !~targetStyleList.indexOf(style)) {
return super.getDetailLinkHtml(id, name);
}
if (!style || !~targetStyleList.indexOf(style)) {
return Dep.prototype.getDetailLinkHtml.call(this, id, name);
}
let iconStyle = '';
let iconStyle = '';
if (style === 'success') {
iconStyle = 'fas fa-check text-success small';
}
else if (style === 'danger') {
iconStyle = 'fas fa-times text-danger small';
}
if (style === 'success') {
iconStyle = 'fas fa-check text-success small';
}
else if (style === 'danger') {
iconStyle = 'fas fa-times text-danger small';
}
return '<span class="' + iconStyle + '"></span> ' +
super.getDetailLinkHtml(id, name);
}
}
return '<span class="' + iconStyle + '"></span> ' +
Dep.prototype.getDetailLinkHtml.call(this, id, name);
},
});
});
// noinspection JSUnusedGlobalSymbols
export default LinkMultipleWithStatusFieldView;
+195 -190
View File
@@ -19,232 +19,237 @@
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
define('views/fields/map', ['views/fields/base'], function (Dep) {
import BaseFieldView from 'views/fields/base';
return Dep.extend({
class MapFieldView extends BaseFieldView {
type: 'map',
type = 'map'
detailTemplate: 'fields/map/detail',
detailTemplate = 'fields/map/detail'
listTemplate = 'fields/map/detail'
listTemplate: 'fields/map/detail',
addressField = null
provider = null
height = 300
addressField: null,
// noinspection JSCheckFunctionSignatures
data() {
const data = super.data();
provider: null,
data.hasAddress = this.hasAddress();
height: 300,
// noinspection JSValidateTypes
return data;
}
data: function () {
var data = Dep.prototype.data.call(this);
setup() {
this.addressField = this.name.slice(0, this.name.length - 3);
data.hasAddress = this.hasAddress();
this.provider = this.options.provider || this.params.provider;
this.height = this.options.height || this.params.height || this.height;
return data;
},
const addressAttributeList = Object.keys(this.getMetadata().get('fields.address.fields') || {})
.map(a => this.addressField + Espo.Utils.upperCaseFirst(a));
setup: function () {
this.addressField = this.name.substr(0, this.name.length - 3);
this.listenTo(this.model, 'sync', model => {
let isChanged = false;
this.provider = this.options.provider || this.params.provider;
this.height = this.options.height || this.params.height || this.height;
var addressAttributeList = Object.keys(this.getMetadata().get('fields.address.fields') || {})
.map(a => {
return this.addressField + Espo.Utils.upperCaseFirst(a);
});
this.listenTo(this.model, 'sync', model => {
let isChanged = false;
addressAttributeList.forEach(attribute => {
if (model.hasChanged(attribute)) {
isChanged = true;
}
});
if (isChanged && this.isRendered()) {
this.reRender();
addressAttributeList.forEach(attribute => {
if (model.hasChanged(attribute)) {
isChanged = true;
}
});
this.listenTo(this.model, 'after:save', () => {
if (this.isRendered()) {
this.reRender();
}
});
},
hasAddress: function () {
return !!this.model.get(this.addressField + 'City') ||
!!this.model.get(this.addressField + 'PostalCode');
},
onRemove: function () {
$(window).off('resize.' + this.cid);
},
afterRender: function () {
this.addressData = {
city: this.model.get(this.addressField + 'City'),
street: this.model.get(this.addressField + 'Street'),
postalCode: this.model.get(this.addressField + 'PostalCode'),
country: this.model.get(this.addressField + 'Country'),
state: this.model.get(this.addressField + 'State'),
};
this.$map = this.$el.find('.map');
if (this.hasAddress()) {
this.processSetHeight(true);
if (this.height === 'auto') {
$(window).off('resize.' + this.cid);
$(window).on('resize.' + this.cid, this.processSetHeight.bind(this));
}
let methodName = 'afterRender' + this.provider.replace(/\s+/g, '');
if (typeof this[methodName] === 'function') {
this[methodName]();
}
else {
let implClassName = this.getMetadata()
.get(['clientDefs', 'AddressMap', 'implementations', this.provider]);
if (implClassName) {
Espo.loader.require(implClassName, impl => {
impl.render(this);
});
}
}
if (isChanged && this.isRendered()) {
this.reRender();
}
},
});
afterRenderGoogle: function () {
if (window.google && window.google.maps) {
this.initMapGoogle();
return;
this.listenTo(this.model, 'after:save', () => {
if (this.isRendered()) {
this.reRender();
}
});
}
if (typeof window.mapapiloaded === 'function') {
let mapapiloaded = window.mapapiloaded;
hasAddress() {
return !!this.model.get(this.addressField + 'City') ||
!!this.model.get(this.addressField + 'PostalCode');
}
window.mapapiloaded = () => {
this.initMapGoogle();
mapapiloaded();
};
onRemove() {
$(window).off('resize.' + this.cid);
}
return;
}
afterRender() {
this.addressData = {
city: this.model.get(this.addressField + 'City'),
street: this.model.get(this.addressField + 'Street'),
postalCode: this.model.get(this.addressField + 'PostalCode'),
country: this.model.get(this.addressField + 'Country'),
state: this.model.get(this.addressField + 'State'),
};
window.mapapiloaded = () => {
this.initMapGoogle();
};
this.$map = this.$el.find('.map');
let src = 'https://maps.googleapis.com/maps/api/js?callback=mapapiloaded';
let apiKey = this.getConfig().get('googleMapsApiKey');
if (apiKey) {
src += '&key=' + apiKey;
}
let scriptElement = document.createElement('script');
scriptElement.setAttribute('async', 'async');
scriptElement.src = src;
document.head.appendChild(scriptElement);
},
processSetHeight: function (init) {
var height = this.height;
if (this.hasAddress()) {
this.processSetHeight(true);
if (this.height === 'auto') {
height = this.$el.parent().height();
$(window).off('resize.' + this.cid);
$(window).on('resize.' + this.cid, this.processSetHeight.bind(this));
}
if (init && height <= 0) {
setTimeout(() => {
this.processSetHeight(true);
}, 50);
let methodName = 'afterRender' + this.provider.replace(/\s+/g, '');
return;
if (typeof this[methodName] === 'function') {
this[methodName]();
}
else {
let implClassName = this.getMetadata()
.get(['clientDefs', 'AddressMap', 'implementations', this.provider]);
if (implClassName) {
Espo.loader.require(implClassName, impl => {
impl.render(this);
});
}
}
}
}
this.$map.css('height', height + 'px');
},
// noinspection JSUnusedGlobalSymbols
afterRenderGoogle() {
if (window.google && window.google.maps) {
this.initMapGoogle();
initMapGoogle: function () {
var geocoder = new google.maps.Geocoder();
return;
}
try {
var map = new google.maps.Map(this.$el.find('.map').get(0), {
zoom: 15,
center: {lat: 0, lng: 0},
scrollwheel: false,
});
}
catch (e) {
console.error(e.message);
// noinspection SpellCheckingInspection
if (typeof window.mapapiloaded === 'function') {
// noinspection SpellCheckingInspection
let mapapiloaded = window.mapapiloaded;
// noinspection SpellCheckingInspection
window.mapapiloaded = () => {
this.initMapGoogle();
mapapiloaded();
};
return;
}
// noinspection SpellCheckingInspection
window.mapapiloaded = () => {
this.initMapGoogle();
};
let src = 'https://maps.googleapis.com/maps/api/js?callback=mapapiloaded';
let apiKey = this.getConfig().get('googleMapsApiKey');
if (apiKey) {
src += '&key=' + apiKey;
}
let scriptElement = document.createElement('script');
scriptElement.setAttribute('async', 'async');
scriptElement.src = src;
document.head.appendChild(scriptElement);
}
processSetHeight(init) {
let height = this.height;
if (this.height === 'auto') {
height = this.$el.parent().height();
if (init && height <= 0) {
setTimeout(() => {
this.processSetHeight(true);
}, 50);
return;
}
}
let address = '';
this.$map.css('height', height + 'px');
}
if (this.addressData.street) {
address += this.addressData.street;
}
initMapGoogle() {
const geocoder = new google.maps.Geocoder();
let map;
if (this.addressData.city) {
if (address !== '') {
address += ', ';
}
address += this.addressData.city;
}
if (this.addressData.state) {
if (address !== '') {
address += ', ';
}
address += this.addressData.state;
}
if (this.addressData.postalCode) {
if (this.addressData.state || this.addressData.city) {
address += ' ';
}
else {
if (address) {
address += ', ';
}
}
address += this.addressData.postalCode;
}
if (this.addressData.country) {
if (address !== '') {
address += ', ';
}
address += this.addressData.country;
}
geocoder.geocode({'address': address}, (results, status) => {
if (status === google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
new google.maps.Marker({
map: map,
position: results[0].geometry.location,
});
}
try {
// noinspection SpellCheckingInspection
map = new google.maps.Map(this.$el.find('.map').get(0), {
zoom: 15,
center: {lat: 0, lng: 0},
scrollwheel: false,
});
},
});
});
}
catch (e) {
console.error(e.message);
return;
}
let address = '';
if (this.addressData.street) {
address += this.addressData.street;
}
if (this.addressData.city) {
if (address !== '') {
address += ', ';
}
address += this.addressData.city;
}
if (this.addressData.state) {
if (address !== '') {
address += ', ';
}
address += this.addressData.state;
}
if (this.addressData.postalCode) {
if (this.addressData.state || this.addressData.city) {
address += ' ';
}
else {
if (address) {
address += ', ';
}
}
address += this.addressData.postalCode;
}
if (this.addressData.country) {
if (address !== '') {
address += ', ';
}
address += this.addressData.country;
}
geocoder.geocode({'address': address}, (results, status) => {
if (status === google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
new google.maps.Marker({
map: map,
position: results[0].geometry.location,
});
}
});
}
}
export default MapFieldView;