ref
This commit is contained in:
@@ -26,26 +26,22 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('views/webhook/fields/event', ['views/fields/varchar'], function (Dep) {
|
||||
import VarcharFieldView from 'views/fields/varchar';
|
||||
|
||||
return Dep.extend({
|
||||
export default class extends VarcharFieldView {
|
||||
|
||||
setupOptions: function () {
|
||||
var itemList = [];
|
||||
setupOptions() {
|
||||
const itemList = [];
|
||||
|
||||
var scopeList = this.getMetadata().getScopeObjectList();
|
||||
const scopeList = this.getMetadata().getScopeObjectList()
|
||||
.sort((v1, v2) => v1.localeCompare(v2));
|
||||
|
||||
scopeList = scopeList.sort(function (v1, v2) {
|
||||
return v1.localeCompare(v2);
|
||||
}.bind(this));
|
||||
scopeList.forEach(scope => {
|
||||
itemList.push(`${scope}.create`);
|
||||
itemList.push(`${scope}.update`);
|
||||
itemList.push(`${scope}.delete`);
|
||||
});
|
||||
|
||||
scopeList.forEach(function (scope) {
|
||||
itemList.push(scope + '.' + 'create');
|
||||
itemList.push(scope + '.' + 'update');
|
||||
itemList.push(scope + '.' + 'delete');
|
||||
}, this);
|
||||
|
||||
this.params.options = itemList;
|
||||
},
|
||||
});
|
||||
});
|
||||
this.params.options = itemList;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,11 +26,9 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('views/webhook/fields/user', ['views/fields/link'], function (Dep) {
|
||||
import LinkFieldView from 'views/fields/link';
|
||||
|
||||
return Dep.extend({
|
||||
export default class extends LinkFieldView {
|
||||
|
||||
selectPrimaryFilterName: 'activeApi',
|
||||
|
||||
});
|
||||
});
|
||||
selectPrimaryFilterName = 'activeApi';
|
||||
}
|
||||
|
||||
@@ -26,11 +26,9 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('views/webhook/record/list', ['views/record/list'], function (Dep) {
|
||||
import ListRecordView from 'views/record/list';
|
||||
|
||||
return Dep.extend({
|
||||
export default class extends ListRecordView {
|
||||
|
||||
massActionList: ['remove', 'massUpdate', 'export'],
|
||||
|
||||
});
|
||||
});
|
||||
massActionList = ['remove', 'massUpdate', 'export']
|
||||
}
|
||||
|
||||
@@ -26,319 +26,322 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('views/working-time-calendar/fields/time-ranges', ['views/fields/base'], function (Dep) {
|
||||
import BaseFieldView from 'views/fields/base';
|
||||
|
||||
export default class extends BaseFieldView {
|
||||
|
||||
// language=Handlebars
|
||||
listTemplateContent = `
|
||||
<div class="item-list">
|
||||
{{#each itemDataList}}
|
||||
<span class="item" data-key="{{key}}"
|
||||
>{{{var viewKey ../this}}}</span>{{#unless isLast}} · {{/unless}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{#unless itemDataList.length}}
|
||||
<span class="none-value">{{translate 'None'}}</span>
|
||||
{{/unless}}
|
||||
`
|
||||
|
||||
// language=Handlebars
|
||||
detailTemplateContent = `
|
||||
<div class="item-list">
|
||||
{{#each itemDataList}}
|
||||
<div class="item" data-key="{{key}}">
|
||||
{{{var viewKey ../this}}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{#unless itemDataList.length}}
|
||||
<span class="none-value">{{translate 'None'}}</span>
|
||||
{{/unless}}
|
||||
`
|
||||
|
||||
// language=Handlebars
|
||||
editTemplateContent = `
|
||||
<div class="item-list">
|
||||
{{#each itemDataList}}
|
||||
<div class="item" data-key="{{key}}">
|
||||
{{{var viewKey ../this}}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
<div class="add-item-container margin-top-sm">
|
||||
<a
|
||||
role="button"
|
||||
tabindex="0"
|
||||
class="add-item"
|
||||
title="{{translate 'Add'}}"
|
||||
><span class="fas fa-plus"></span></a>
|
||||
</div>
|
||||
`
|
||||
|
||||
// noinspection JSCheckFunctionSignatures
|
||||
data() {
|
||||
const data = super.data();
|
||||
|
||||
data.itemDataList = this.itemKeyList.map((key, i) => {
|
||||
return {
|
||||
key: key.toString(),
|
||||
viewKey: this.composeViewKey(key),
|
||||
isLast: i === this.itemKeyList.length - 1,
|
||||
};
|
||||
});
|
||||
|
||||
// noinspection JSValidateTypes
|
||||
return data;
|
||||
}
|
||||
|
||||
setup() {
|
||||
super.setup();
|
||||
|
||||
this.validations = [
|
||||
() => this.validateRequired(),
|
||||
() => this.validateValid(),
|
||||
];
|
||||
|
||||
this.addHandler('click', '.add-item', () => this.addItem());
|
||||
|
||||
this.addHandler('click', '.remove-item', (e, target) => {
|
||||
this.removeItem(parseInt(target.dataset.key));
|
||||
});
|
||||
}
|
||||
|
||||
prepare() {
|
||||
this.initItems();
|
||||
|
||||
return this.createItemViews();
|
||||
}
|
||||
|
||||
initItems() {
|
||||
this.itemKeyList = [];
|
||||
|
||||
this.getItemListFromModel().forEach((item, i) => {
|
||||
this.itemKeyList.push(i);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @name Class
|
||||
* @memberOf module:views/working-time-calendar/fields/time-ranges
|
||||
* @extends module:views/fields/base
|
||||
* @returns {Promise}
|
||||
*/
|
||||
return Dep.extend(/** @lends module:views/working-time-calendar/fields/time-ranges.Class# */{
|
||||
createItemView(item, key) {
|
||||
const viewName = this.isEditMode() ?
|
||||
'views/working-time-calendar/fields/time-ranges/item-edit' :
|
||||
'views/working-time-calendar/fields/time-ranges/item-detail';
|
||||
|
||||
listTemplateContent: `
|
||||
<div class="item-list">
|
||||
{{#each itemDataList}}
|
||||
<span class="item" data-key="{{key}}"
|
||||
>{{{var viewKey ../this}}}</span>{{#unless isLast}} · {{/unless}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{#unless itemDataList.length}}
|
||||
<span class="none-value">{{translate 'None'}}</span>
|
||||
{{/unless}}
|
||||
`,
|
||||
|
||||
detailTemplateContent: `
|
||||
<div class="item-list">
|
||||
{{#each itemDataList}}
|
||||
<div class="item" data-key="{{key}}">
|
||||
{{{var viewKey ../this}}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{#unless itemDataList.length}}
|
||||
<span class="none-value">{{translate 'None'}}</span>
|
||||
{{/unless}}
|
||||
`,
|
||||
|
||||
editTemplateContent: `
|
||||
<div class="item-list">
|
||||
{{#each itemDataList}}
|
||||
<div class="item" data-key="{{key}}">
|
||||
{{{var viewKey ../this}}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
<div class="add-item-container margin-top-sm">
|
||||
<a
|
||||
role="button"
|
||||
tabindex="0"
|
||||
class="add-item"
|
||||
title="{{translate 'Add'}}"
|
||||
><span class="fas fa-plus"></span></a>
|
||||
</div>
|
||||
`,
|
||||
|
||||
fetchEmptyAsNull: false,
|
||||
|
||||
validations: ['required', 'valid'],
|
||||
|
||||
events: {
|
||||
'click .add-item': function () {
|
||||
this.addItem();
|
||||
},
|
||||
'click .remove-item': function (e) {
|
||||
let key = parseInt($(e.currentTarget).attr('data-key'));
|
||||
|
||||
this.removeItem(key);
|
||||
},
|
||||
},
|
||||
|
||||
data: function () {
|
||||
let data = Dep.prototype.data.call(this);
|
||||
|
||||
data.itemDataList = this.itemKeyList.map((key, i) => {
|
||||
return {
|
||||
key: key.toString(),
|
||||
viewKey: this.composeViewKey(key),
|
||||
isLast: i === this.itemKeyList.length - 1,
|
||||
};
|
||||
});
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
prepare: function () {
|
||||
this.initItems();
|
||||
|
||||
return this.createItemViews();
|
||||
},
|
||||
|
||||
initItems: function () {
|
||||
this.itemKeyList = [];
|
||||
|
||||
this.getItemListFromModel().forEach((item, i) => {
|
||||
this.itemKeyList.push(i);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {Promise}
|
||||
*/
|
||||
createItemView: function (item, key) {
|
||||
let viewName = this.isEditMode() ?
|
||||
'views/working-time-calendar/fields/time-ranges/item-edit' :
|
||||
'views/working-time-calendar/fields/time-ranges/item-detail';
|
||||
|
||||
return this.createView(
|
||||
this.composeViewKey(key),
|
||||
viewName,
|
||||
{
|
||||
value: item,
|
||||
selector: '.item[data-key="' + key + '"]',
|
||||
key: key,
|
||||
}
|
||||
)
|
||||
.then(view => {
|
||||
this.listenTo(view, 'change', () => {
|
||||
this.trigger('change');
|
||||
});
|
||||
|
||||
return view;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {Promise}
|
||||
*/
|
||||
createItemViews: function () {
|
||||
this.itemKeyList.forEach(key => {
|
||||
this.clearView(this.composeViewKey(key));
|
||||
});
|
||||
|
||||
if (!this.model.has(this.name)) {
|
||||
return Promise.resolve();
|
||||
return this.createView(
|
||||
this.composeViewKey(key),
|
||||
viewName,
|
||||
{
|
||||
value: item,
|
||||
selector: `.item[data-key="${key}"]`,
|
||||
key: key,
|
||||
}
|
||||
|
||||
let itemList = this.getItemListFromModel();
|
||||
|
||||
let promiseList = [];
|
||||
|
||||
this.itemKeyList.forEach((key, i) => {
|
||||
let item = itemList[i];
|
||||
|
||||
let promise = this.createItemView(item, key);
|
||||
|
||||
promiseList.push(promise);
|
||||
)
|
||||
.then(view => {
|
||||
this.listenTo(view, 'change', () => {
|
||||
this.trigger('change');
|
||||
});
|
||||
|
||||
return Promise.all(promiseList);
|
||||
},
|
||||
|
||||
getItemView: function (key) {
|
||||
return this.getView(this.composeViewKey(key));
|
||||
},
|
||||
|
||||
composeViewKey: function (key) {
|
||||
return 'item-' + key;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {[string|null, string|null][]}
|
||||
*/
|
||||
getItemListFromModel: function () {
|
||||
return Espo.Utils.cloneDeep(this.model.get(this.name) || []);
|
||||
},
|
||||
|
||||
addItem: function () {
|
||||
let itemList = this.getItemListFromModel();
|
||||
|
||||
let value = null;
|
||||
|
||||
if (itemList.length) {
|
||||
value = itemList[itemList.length - 1][1];
|
||||
}
|
||||
|
||||
let item = [value, null];
|
||||
|
||||
itemList.push(item);
|
||||
|
||||
let key = this.itemKeyList[this.itemKeyList.length - 1];
|
||||
|
||||
if (typeof key === 'undefined') {
|
||||
key = 0;
|
||||
}
|
||||
|
||||
key++;
|
||||
|
||||
this.itemKeyList.push(key);
|
||||
|
||||
this.$el.find('.item-list').append(
|
||||
$('<div>')
|
||||
.addClass('item')
|
||||
.attr('data-key', key)
|
||||
);
|
||||
|
||||
this.createItemView(item, key)
|
||||
.then(view => view.render())
|
||||
.then(() => {
|
||||
this.trigger('change');
|
||||
});
|
||||
},
|
||||
|
||||
removeItem: function (key) {
|
||||
let index = this.itemKeyList.indexOf(key);
|
||||
|
||||
if (key === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
let itemList = this.getItemListFromModel();
|
||||
|
||||
this.itemKeyList.splice(index, 1);
|
||||
itemList.splice(index, 1);
|
||||
|
||||
this.model.set(this.name, itemList, {ui: true});
|
||||
return view;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise}
|
||||
*/
|
||||
createItemViews() {
|
||||
this.itemKeyList.forEach(key => {
|
||||
this.clearView(this.composeViewKey(key));
|
||||
});
|
||||
|
||||
this.$el.find(`.item[data-key="${key}"`).remove();
|
||||
if (!this.model.has(this.name)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
this.trigger('change');
|
||||
},
|
||||
const itemList = this.getItemListFromModel();
|
||||
|
||||
fetch: function () {
|
||||
let itemList = [];
|
||||
const promiseList = [];
|
||||
|
||||
this.itemKeyList.forEach(key => {
|
||||
itemList.push(
|
||||
this.getItemView(key).fetch()
|
||||
);
|
||||
this.itemKeyList.forEach((key, i) => {
|
||||
const item = itemList[i];
|
||||
|
||||
const promise = this.createItemView(item, key);
|
||||
|
||||
promiseList.push(promise);
|
||||
});
|
||||
|
||||
return Promise.all(promiseList);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @return {import('./time-ranges/item-edit').default}
|
||||
*/
|
||||
getItemView(key) {
|
||||
// noinspection JSValidateTypes
|
||||
return this.getView(this.composeViewKey(key));
|
||||
}
|
||||
|
||||
composeViewKey(key) {
|
||||
return `item-${key}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {[string|null, string|null][]}
|
||||
*/
|
||||
getItemListFromModel() {
|
||||
return Espo.Utils.cloneDeep(this.model.get(this.name) || []);
|
||||
}
|
||||
|
||||
addItem() {
|
||||
const itemList = this.getItemListFromModel();
|
||||
|
||||
let value = null;
|
||||
|
||||
if (itemList.length) {
|
||||
value = itemList[itemList.length - 1][1];
|
||||
}
|
||||
|
||||
const item = [value, null];
|
||||
|
||||
itemList.push(item);
|
||||
|
||||
let key = this.itemKeyList[this.itemKeyList.length - 1];
|
||||
|
||||
if (typeof key === 'undefined') {
|
||||
key = 0;
|
||||
}
|
||||
|
||||
key++;
|
||||
|
||||
this.itemKeyList.push(key);
|
||||
|
||||
this.$el.find('.item-list').append(
|
||||
$('<div>')
|
||||
.addClass('item')
|
||||
.attr('data-key', key)
|
||||
);
|
||||
|
||||
this.createItemView(item, key)
|
||||
.then(view => view.render())
|
||||
.then(() => {
|
||||
this.trigger('change');
|
||||
});
|
||||
}
|
||||
|
||||
let data = {};
|
||||
removeItem(key) {
|
||||
const index = this.itemKeyList.indexOf(key);
|
||||
|
||||
data[this.name] = Espo.Utils.cloneDeep(itemList);
|
||||
if (key === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data[this.name].length === 0) {
|
||||
data[this.name] = null;
|
||||
}
|
||||
const itemList = this.getItemListFromModel();
|
||||
|
||||
return data;
|
||||
},
|
||||
this.itemKeyList.splice(index, 1);
|
||||
itemList.splice(index, 1);
|
||||
|
||||
validateRequired: function () {
|
||||
if (!this.isRequired()) {
|
||||
return false;
|
||||
}
|
||||
this.model.set(this.name, itemList, {ui: true});
|
||||
|
||||
if (this.getItemListFromModel().length) {
|
||||
return false;
|
||||
}
|
||||
this.clearView(this.composeViewKey(key));
|
||||
|
||||
let msg = this.translate('fieldIsRequired', 'messages')
|
||||
.replace('{field}', this.getLabelText());
|
||||
this.$el.find(`.item[data-key="${key}"`).remove();
|
||||
|
||||
this.showValidationMessage(msg, '.add-item-container');
|
||||
this.trigger('change');
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
fetch() {
|
||||
const itemList = [];
|
||||
|
||||
validateValid: function () {
|
||||
if (!this.isRangesInvalid()) {
|
||||
return false;
|
||||
}
|
||||
this.itemKeyList.forEach(key => {
|
||||
itemList.push(
|
||||
this.getItemView(key).fetch()
|
||||
);
|
||||
});
|
||||
|
||||
let msg = this.translate('fieldInvalid', 'messages')
|
||||
.replace('{field}', this.getLabelText());
|
||||
const data = {};
|
||||
|
||||
this.showValidationMessage(msg, '.add-item-container');
|
||||
data[this.name] = Espo.Utils.cloneDeep(itemList);
|
||||
|
||||
return true;
|
||||
},
|
||||
if (data[this.name].length === 0) {
|
||||
data[this.name] = null;
|
||||
}
|
||||
|
||||
isRangesInvalid: function () {
|
||||
let itemList = this.getItemListFromModel();
|
||||
|
||||
for (let i = 0; i < itemList.length; i++) {
|
||||
let item = itemList[i];
|
||||
|
||||
if (this.isRangeInvalid(item[0], item[1], true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (i === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let prevItem = item[i - 1];
|
||||
|
||||
if (this.isRangeInvalid(prevItem[1], item[0])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
validateRequired() {
|
||||
if (!this.isRequired()) {
|
||||
return false;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|null} from
|
||||
* @param {string|null} to
|
||||
* @param {boolean} [noEmpty]
|
||||
*/
|
||||
isRangeInvalid: function (from, to, noEmpty) {
|
||||
if (from === null || to === null) {
|
||||
if (this.getItemListFromModel().length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const msg = this.translate('fieldIsRequired', 'messages')
|
||||
.replace('{field}', this.getLabelText());
|
||||
|
||||
this.showValidationMessage(msg, '.add-item-container');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
validateValid() {
|
||||
if (!this.isRangesInvalid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const msg = this.translate('fieldInvalid', 'messages')
|
||||
.replace('{field}', this.getLabelText());
|
||||
|
||||
this.showValidationMessage(msg, '.add-item-container');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
isRangesInvalid() {
|
||||
const itemList = this.getItemListFromModel();
|
||||
|
||||
for (let i = 0; i < itemList.length; i++) {
|
||||
const item = itemList[i];
|
||||
|
||||
if (this.isRangeInvalid(item[0], item[1], true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let fromNumber = parseFloat(from.replace(':', '.'));
|
||||
let toNumber = parseFloat(to.replace(':', '.'));
|
||||
|
||||
if (noEmpty && fromNumber === toNumber) {
|
||||
return true;
|
||||
if (i === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return fromNumber > toNumber;
|
||||
},
|
||||
});
|
||||
});
|
||||
const prevItem = item[i - 1];
|
||||
|
||||
if (this.isRangeInvalid(prevItem[1], item[0])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|null} from
|
||||
* @param {string|null} to
|
||||
* @param {boolean} [noEmpty]
|
||||
*/
|
||||
isRangeInvalid(from, to, noEmpty) {
|
||||
if (from === null || to === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const fromNumber = parseFloat(from.replace(':', '.'));
|
||||
const toNumber = parseFloat(to.replace(':', '.'));
|
||||
|
||||
if (noEmpty && fromNumber === toNumber) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return fromNumber > toNumber;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,45 +26,39 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('views/working-time-calendar/fields/time-ranges/item-detail', ['view', 'lib!moment'],
|
||||
(Dep, /** @param {moment} */moment) => {
|
||||
import View from 'view';
|
||||
import moment from 'moment';
|
||||
|
||||
/**
|
||||
* @extends module:view
|
||||
*/
|
||||
class Class extends Dep
|
||||
{
|
||||
templateContent = `
|
||||
{{start}}
|
||||
–
|
||||
{{end}}
|
||||
`
|
||||
export default class extends View {
|
||||
|
||||
data() {
|
||||
return {
|
||||
start: this.convertTimeToDisplay(this.value[0]),
|
||||
end: this.convertTimeToDisplay(this.value[1]),
|
||||
};
|
||||
}
|
||||
templateContent = `
|
||||
{{start}}
|
||||
–
|
||||
{{end}}
|
||||
`
|
||||
|
||||
setup() {
|
||||
this.value = this.options.value;
|
||||
}
|
||||
|
||||
convertTimeToDisplay(value) {
|
||||
if (!value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let m = moment(value, 'HH:mm');
|
||||
|
||||
if (!m.isValid()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return m.format(this.getDateTime().timeFormat);
|
||||
}
|
||||
data() {
|
||||
return {
|
||||
start: this.convertTimeToDisplay(this.value[0]),
|
||||
end: this.convertTimeToDisplay(this.value[1]),
|
||||
};
|
||||
}
|
||||
|
||||
return Class;
|
||||
});
|
||||
setup() {
|
||||
this.value = this.options.value;
|
||||
}
|
||||
|
||||
convertTimeToDisplay(value) {
|
||||
if (!value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const m = moment(value, 'HH:mm');
|
||||
|
||||
if (!m.isValid()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return m.format(this.getDateTime().timeFormat);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,144 +26,144 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('views/working-time-calendar/fields/time-ranges/item-edit', ['view', 'lib!moment'], function (Dep, moment) {
|
||||
import View from 'view';
|
||||
import moment from 'moment';
|
||||
|
||||
return Dep.extend({
|
||||
export default class extends View {
|
||||
|
||||
// language=Handlebars
|
||||
templateContent: `
|
||||
<div class="row">
|
||||
<div class="start-container col-xs-5">
|
||||
<input
|
||||
class="form-control"
|
||||
type="text"
|
||||
data-name="start"
|
||||
value="{{start}}"
|
||||
autocomplete="espo-start"
|
||||
spellcheck="false"
|
||||
>
|
||||
</div>
|
||||
<div class="start-container col-xs-1 center-align">
|
||||
<span class="field-row-text-item"> – </span>
|
||||
</div>
|
||||
<div class="end-container col-xs-5">
|
||||
<input
|
||||
class="form-control"
|
||||
type="text"
|
||||
data-name="end"
|
||||
value="{{end}}"
|
||||
autocomplete="espo-end"
|
||||
spellcheck="false"
|
||||
>
|
||||
</div>
|
||||
<div class="col-xs-1 center-align">
|
||||
<a
|
||||
role="button"
|
||||
tabindex="0"
|
||||
class="remove-item field-row-text-item"
|
||||
data-key="{{key}}"
|
||||
title="{{translate 'Remove'}}"
|
||||
><span class="fas fa-times"></span></a>
|
||||
</div>
|
||||
|
||||
// language=Handlebars
|
||||
templateContent = `
|
||||
<div class="row">
|
||||
<div class="start-container col-xs-5">
|
||||
<input
|
||||
class="form-control"
|
||||
type="text"
|
||||
data-name="start"
|
||||
value="{{start}}"
|
||||
autocomplete="espo-start"
|
||||
spellcheck="false"
|
||||
>
|
||||
</div>
|
||||
`,
|
||||
<div class="start-container col-xs-1 center-align">
|
||||
<span class="field-row-text-item"> – </span>
|
||||
</div>
|
||||
<div class="end-container col-xs-5">
|
||||
<input
|
||||
class="form-control"
|
||||
type="text"
|
||||
data-name="end"
|
||||
value="{{end}}"
|
||||
autocomplete="espo-end"
|
||||
spellcheck="false"
|
||||
>
|
||||
</div>
|
||||
<div class="col-xs-1 center-align">
|
||||
<a
|
||||
role="button"
|
||||
tabindex="0"
|
||||
class="remove-item field-row-text-item"
|
||||
data-key="{{key}}"
|
||||
title="{{translate 'Remove'}}"
|
||||
><span class="fas fa-times"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
|
||||
timeFormatMap: {
|
||||
'HH:mm': 'H:i',
|
||||
'hh:mm A': 'h:i A',
|
||||
'hh:mm a': 'h:i a',
|
||||
'hh:mmA': 'h:iA',
|
||||
'hh:mma': 'h:ia',
|
||||
},
|
||||
timeFormatMap = {
|
||||
'HH:mm': 'H:i',
|
||||
'hh:mm A': 'h:i A',
|
||||
'hh:mm a': 'h:i a',
|
||||
'hh:mmA': 'h:iA',
|
||||
'hh:mma': 'h:ia',
|
||||
}
|
||||
|
||||
minuteStep: 30,
|
||||
minuteStep = 30
|
||||
|
||||
data: function () {
|
||||
let data = {};
|
||||
data () {
|
||||
const data = {};
|
||||
|
||||
data.start = this.convertTimeToDisplay(this.value[0]);
|
||||
data.end = this.convertTimeToDisplay(this.value[1]);
|
||||
data.start = this.convertTimeToDisplay(this.value[0]);
|
||||
data.end = this.convertTimeToDisplay(this.value[1]);
|
||||
|
||||
data.key = this.key;
|
||||
data.key = this.key;
|
||||
|
||||
return data;
|
||||
},
|
||||
return data;
|
||||
}
|
||||
|
||||
setup: function () {
|
||||
this.value = this.options.value || [null, null];
|
||||
this.key = this.options.key;
|
||||
},
|
||||
setup () {
|
||||
this.value = this.options.value || [null, null];
|
||||
this.key = this.options.key;
|
||||
}
|
||||
|
||||
convertTimeToDisplay: function (value) {
|
||||
if (!value) {
|
||||
return '';
|
||||
}
|
||||
convertTimeToDisplay(value) {
|
||||
if (!value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let m = moment(value, 'HH:mm');
|
||||
const m = moment(value, 'HH:mm');
|
||||
|
||||
if (!m.isValid()) {
|
||||
return '';
|
||||
}
|
||||
if (!m.isValid()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return m.format(this.getDateTime().timeFormat);
|
||||
},
|
||||
return m.format(this.getDateTime().timeFormat);
|
||||
}
|
||||
|
||||
convertTimeFromDisplay: function (value) {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
convertTimeFromDisplay(value) {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let m = moment(value, this.getDateTime().timeFormat);
|
||||
const m = moment(value, this.getDateTime().timeFormat);
|
||||
|
||||
if (!m.isValid()) {
|
||||
return null;
|
||||
}
|
||||
if (!m.isValid()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return m.format('HH:mm');
|
||||
},
|
||||
return m.format('HH:mm');
|
||||
}
|
||||
|
||||
afterRender: function () {
|
||||
this.$start = this.$el.find('[data-name="start"]');
|
||||
this.$end = this.$el.find('[data-name="end"]');
|
||||
afterRender() {
|
||||
this.$start = this.$el.find('[data-name="start"]');
|
||||
this.$end = this.$el.find('[data-name="end"]');
|
||||
|
||||
this.initTimepicker(this.$start);
|
||||
this.initTimepicker(this.$end);
|
||||
this.initTimepicker(this.$start);
|
||||
this.initTimepicker(this.$end);
|
||||
|
||||
this.setMinTime();
|
||||
this.setMinTime();
|
||||
|
||||
this.$start.on('change', () => this.setMinTime());
|
||||
},
|
||||
this.$start.on('change', () => this.setMinTime());
|
||||
}
|
||||
|
||||
setMinTime: function () {
|
||||
let value = this.$start.val();
|
||||
setMinTime() {
|
||||
const value = this.$start.val();
|
||||
|
||||
this.$end.timepicker('option', 'maxTime', this.convertTimeToDisplay('23:59'));
|
||||
this.$end.timepicker('option', 'maxTime', this.convertTimeToDisplay('23:59'));
|
||||
|
||||
if (!value) {
|
||||
this.$end.timepicker('option', 'minTime', null);
|
||||
if (!value) {
|
||||
this.$end.timepicker('option', 'minTime', null);
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.$end.timepicker('option', 'minTime', value);
|
||||
},
|
||||
this.$end.timepicker('option', 'minTime', value);
|
||||
}
|
||||
|
||||
initTimepicker: function ($el) {
|
||||
$el.timepicker({
|
||||
step: this.minuteStep,
|
||||
timeFormat: this.timeFormatMap[this.getDateTime().timeFormat],
|
||||
});
|
||||
initTimepicker($el) {
|
||||
$el.timepicker({
|
||||
step: this.minuteStep,
|
||||
timeFormat: this.timeFormatMap[this.getDateTime().timeFormat],
|
||||
});
|
||||
|
||||
$el.on('change', () => this.trigger('change'));
|
||||
$el.on('change', () => this.trigger('change'));
|
||||
$el.attr('autocomplete', 'espo-time-range-item');
|
||||
}
|
||||
|
||||
$el.attr('autocomplete', 'espo-time-range-item');
|
||||
},
|
||||
|
||||
fetch: function () {
|
||||
return [
|
||||
this.convertTimeFromDisplay(this.$start.val()),
|
||||
this.convertTimeFromDisplay(this.$end.val()),
|
||||
];
|
||||
},
|
||||
});
|
||||
});
|
||||
fetch() {
|
||||
return [
|
||||
this.convertTimeFromDisplay(this.$start.val()),
|
||||
this.convertTimeFromDisplay(this.$end.val()),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user