432 lines
12 KiB
JavaScript
432 lines
12 KiB
JavaScript
/*
|
|
* Axelor Business Solutions
|
|
*
|
|
* Copyright (C) 2005-2019 Axelor (<http://axelor.com>).
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License, version 3,
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* This program 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 Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
(function() {
|
|
|
|
"use strict";
|
|
|
|
var ui = angular.module('axelor.ui');
|
|
|
|
ui.formWidget('PanelJson', {
|
|
showTitle: false,
|
|
transclude: true,
|
|
template: "<div class='panel-json' ui-transclude></div>"
|
|
});
|
|
|
|
ui.formInput('JsonField', 'String', {
|
|
showTitle: false,
|
|
link: function (scope, element, attrs, model) {
|
|
var field = scope.field;
|
|
var jsonFields = field.jsonFields || [];
|
|
var jsonNames = _.pluck(jsonFields, 'name');
|
|
var jsonFix = {};
|
|
|
|
jsonFields.forEach(function (item) {
|
|
if (item.widget && item.showTitle === undefined) {
|
|
var widget = ui.getWidgetDef(item.widget);
|
|
if (widget) {
|
|
item.showTitle = widget.showTitle;
|
|
}
|
|
}
|
|
});
|
|
|
|
var defaultValues = {};
|
|
var parentUnwatch = null;
|
|
var selfUnwatch = null;
|
|
|
|
scope.formPath = scope.formPath ? scope.formPath + "." + field.name : field.name;
|
|
scope.record = {};
|
|
|
|
jsonFields.forEach(function (item) {
|
|
if (item.target === 'com.axelor.meta.db.MetaJsonRecord' &&
|
|
item.targetName && item.targetName.indexOf('attrs.') === 0) {
|
|
jsonFix[item.name] = function (v) {
|
|
if (v) {
|
|
v[item.targetName.substring(6)] = v[item.targetName];
|
|
}
|
|
return v;
|
|
};
|
|
}
|
|
if (item.contextField && item.contextFieldValue) {
|
|
if (item.showIf === undefined && item.hideIf === undefined && item.hidden) {
|
|
return;
|
|
}
|
|
var condition = "($record." + item.contextField + ".id === " + item.contextFieldValue + ")";
|
|
if (item.showIf) condition += " && (" + item.showIf + ")";
|
|
if (item.hideIf) condition += " && !(" + item.hideIf + ")";
|
|
item.showIf = condition;
|
|
item.hideIf = null;
|
|
}
|
|
});
|
|
|
|
function getDefaultValues() {
|
|
jsonFields.forEach(function (item) {
|
|
if (item.defaultValue === undefined) return;
|
|
var value = item.defaultValue;
|
|
switch(item.type) {
|
|
case 'integer':
|
|
value = +(value);
|
|
break;
|
|
case 'date':
|
|
case 'datetime':
|
|
value = value === 'now' ? new Date() : moment(value).toDate();
|
|
break;
|
|
}
|
|
defaultValues[item.name] = value;
|
|
});
|
|
return angular.copy(defaultValues);
|
|
}
|
|
|
|
function unwatchParent() {
|
|
if (parentUnwatch) {
|
|
parentUnwatch();
|
|
parentUnwatch = null;
|
|
}
|
|
}
|
|
|
|
function unwatchSelf() {
|
|
if (selfUnwatch) {
|
|
selfUnwatch();
|
|
selfUnwatch = null;
|
|
}
|
|
}
|
|
|
|
function watchParent() {
|
|
unwatchParent();
|
|
parentUnwatch = scope.$watch('$parent.record.' + field.name, function jsonParentWatch(value, old) {
|
|
if (value === old) return;
|
|
onRender();
|
|
});
|
|
}
|
|
|
|
function watchSelf() {
|
|
unwatchSelf();
|
|
selfUnwatch = scope.$watch('record', function jsonRecordWatch(record, old) {
|
|
if (record !== old) {
|
|
onUpdate();
|
|
}
|
|
}, true);
|
|
}
|
|
|
|
function format(name, value) {
|
|
var func = jsonFix[name];
|
|
return func ? func(value) : value;
|
|
}
|
|
|
|
function onUpdate() {
|
|
var rec = null;
|
|
_.each(scope.record, function (v, k) {
|
|
if (k.indexOf('$') === 0 || v === null || v === undefined) return;
|
|
if (_.isArray(v)) {
|
|
if (v.length == 0) return;
|
|
v = v.map(function (x) {
|
|
return x.id ? { id: x.id } : x;
|
|
});
|
|
}
|
|
if (rec === null) {
|
|
rec = {};
|
|
}
|
|
rec[k] = format(k, v);
|
|
});
|
|
unwatchParent();
|
|
if (scope.$parent.record[field.name] || rec) {
|
|
scope.$parent.record[field.name] = rec ? angular.toJson(rec) : rec;
|
|
}
|
|
watchParent();
|
|
}
|
|
|
|
function onRender() {
|
|
var record = scope.$parent.record || {};
|
|
var value = record[field.name];
|
|
unwatchSelf();
|
|
if (value) {
|
|
scope.record = angular.fromJson(value);
|
|
} else {
|
|
scope.record = getDefaultValues();
|
|
if (!_.isEmpty(scope.record)) {
|
|
record[field.name] = angular.toJson(scope.record);
|
|
}
|
|
onUpdate();
|
|
}
|
|
scope._jsonContext = { '$record': record };
|
|
record['$' + field.name] = scope.record;
|
|
watchSelf();
|
|
}
|
|
|
|
scope.$on('on:new', onRender);
|
|
scope.$on('on:edit', function () {
|
|
if (scope.viewType === 'form' || (!scope.viewType && scope._isPopup)) onRender();
|
|
});
|
|
|
|
scope.updateJsonValues = function (values) {
|
|
var rec = null;
|
|
_.each(values, function (v, k) {
|
|
if (jsonNames.indexOf(k) === -1 && scope.fields[k]) {
|
|
scope.$parent.record[k] = v;
|
|
} else {
|
|
if (rec === null) {
|
|
rec = {};
|
|
}
|
|
rec[k] = v;
|
|
}
|
|
});
|
|
if (rec) {
|
|
scope.record = _.extend({}, scope.record, rec);
|
|
}
|
|
};
|
|
|
|
watchParent();
|
|
|
|
// hide parent panel if no jsonFields defined
|
|
scope.$evalAsync(function () {
|
|
var parent = scope.$parent.field || {};
|
|
if (parent.type === 'panel' && _.size(parent.items) === 1 && _.isEmpty(field.jsonFields)) {
|
|
element.parents('.panel:first').addClass('hide').hide();
|
|
}
|
|
});
|
|
|
|
scope.$on('on:update-context', function (e, context) {
|
|
if (context && !context[field.name]) {
|
|
context[field.name] = angular.toJson(scope.record || {});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
ui.formInput('JsonRaw', 'String', {
|
|
showTitle: false,
|
|
link: function (scope, element, attrs, model) {
|
|
|
|
scope.placeHolderKey = _t('name');
|
|
scope.placeHolderVal = _t('value');
|
|
|
|
scope.items = [];
|
|
|
|
scope.onAdd = function () {
|
|
var last = _.last(scope.items);
|
|
if (last && !(_.trim(last.name) && _.trim(last.value))) return;
|
|
scope.items.push({});
|
|
};
|
|
|
|
scope.onRemove = function (index) {
|
|
if (scope.items.length > 0) {
|
|
scope.items.splice(index, 1);
|
|
}
|
|
};
|
|
|
|
var unwatch = null;
|
|
|
|
function doWatch () {
|
|
if (unwatch) {
|
|
unwatch();
|
|
}
|
|
unwatch = scope.$watch('items', function jsonItemsWatch(items, old) {
|
|
if (items === old) return;
|
|
var record = null;
|
|
_.each(items, function (item) {
|
|
if (!_.trim(item.name) || !_.trim(item.value)) return;
|
|
if (record === null) {
|
|
record = {};
|
|
}
|
|
record[item.name] = item.value;
|
|
});
|
|
model.$setViewValue(record ? angular.toJson(record) : null);
|
|
}, true);
|
|
}
|
|
|
|
model.$render = function () {
|
|
var value = model.$viewValue;
|
|
if (value) {
|
|
value = angular.fromJson(value);
|
|
} else {
|
|
value = {};
|
|
}
|
|
scope.items = _.map(_.keys(value), function (name) {
|
|
return { name: name, value: value[name] || '' };
|
|
});
|
|
doWatch();
|
|
};
|
|
},
|
|
template_readonly:
|
|
"<div class='json-editor'>" +
|
|
"<table class='form-layout'>" +
|
|
"<tr ng-repeat='(i, item) in items'>" +
|
|
"<td class='form-label'>" +
|
|
"<strong class='display-text'>{{item.name}}</strong>:" +
|
|
"</td>" +
|
|
"<td class='form-item'>" +
|
|
"<span class='display-text'>{{item.value}}</span>" +
|
|
"</td>" +
|
|
"</tr>" +
|
|
"</table>" +
|
|
"</div>",
|
|
template_editable:
|
|
"<div class='json-editor'>" +
|
|
"<table class='form-layout'>" +
|
|
"<tr ng-repeat='(i, item) in items'>" +
|
|
"<td class='form-item'><span class='form-item-container'>" +
|
|
"<input type='text' placeholder='{{placeHolderKey}}' ng-model='item.name'></span>" +
|
|
"</td>" +
|
|
"<td class='form-item'><span class='form-item-container'>" +
|
|
"<input type='text' placeholder='{{placeHolderVal}}' ng-model='item.value'></span>" +
|
|
"</td>" +
|
|
"<td><a href='' ng-click='onRemove(i)'><i class='fa fa-minus'></i></a></td>" +
|
|
"</tr>" +
|
|
"</table>" +
|
|
"<a href='' ng-click='onAdd()'><i class='fa fa-plus'></i></a>" +
|
|
"</div>"
|
|
});
|
|
|
|
ui.formInput('JsonRefSelect', {
|
|
|
|
css: 'multi-object-select',
|
|
|
|
controller: ['$scope', 'ViewService', function($scope, ViewService) {
|
|
|
|
$scope.createElement = function(id, name, selectionList) {
|
|
|
|
var elemGroup = $('<div ui-group ui-table-layout cols="2" x-widths="150,*"></div>');
|
|
var elemSelect = $('<input ui-select showTitle="false">')
|
|
.attr("name", name + "$model")
|
|
.attr("x-for-widget", id)
|
|
.attr("ng-model", "record." + name + ".model");
|
|
|
|
var elemSelects = $('<div></div>').attr('ng-switch', "record." + name + ".model");
|
|
var elemItems = _.map(selectionList, function(s) {
|
|
return $('<input ui-json-ref-item ng-switch-when="' + s.value +'">')
|
|
.attr('ng-model', 'record.' + name)
|
|
.attr('name', name)
|
|
.attr('x-target', s.value);
|
|
});
|
|
|
|
elemGroup
|
|
.append($('<div></div>').append(elemSelect))
|
|
.append(elemSelects.append(elemItems));
|
|
|
|
return ViewService.compile(elemGroup)($scope);
|
|
};
|
|
}],
|
|
|
|
link: function(scope, element, attrs, model) {
|
|
this._super.apply(this, arguments);
|
|
|
|
var name = scope.field.name;
|
|
var selectionList = scope.field.selectionList;
|
|
|
|
scope.fieldsCache = {};
|
|
|
|
scope.refFireEvent = function (name) {
|
|
var handler = scope.$events[name];
|
|
if (handler) {
|
|
return handler();
|
|
}
|
|
};
|
|
|
|
var elem = scope.createElement(element.attr('id'), name, selectionList);
|
|
setTimeout(function() {
|
|
element.append(elem);
|
|
});
|
|
|
|
scope.$watch("record." + name + ".model", function jsonModelWatch(value, old) {
|
|
if (value === old || old === undefined) return;
|
|
if (scope.record && scope.record[name]) {
|
|
scope.record[name] = _.pick(scope.record[name], 'model');
|
|
if (!scope.record[name].model) {
|
|
delete scope.record[name];
|
|
}
|
|
}
|
|
});
|
|
},
|
|
template_editable: null,
|
|
template_readonly: null
|
|
});
|
|
|
|
ui.formInput('JsonRefItem', 'ManyToOne', {
|
|
|
|
showTitle: false,
|
|
|
|
link: function(scope, element, attrs, model) {
|
|
this._super.apply(this, arguments);
|
|
|
|
if (scope.field.targetName) {
|
|
return this._link.apply(this, arguments);
|
|
}
|
|
|
|
var self = this;
|
|
var target = element.attr('x-target');
|
|
var data = (_.findWhere(scope.$parent.field.selectionList, {value: target})||{}).data || {};
|
|
|
|
function doLink(fields) {
|
|
var name = false,
|
|
search = [];
|
|
|
|
_.each(fields, function(f) {
|
|
if (f.nameColumn) name = f.name;
|
|
if (f.name === "name") search.push("name");
|
|
if (f.name === "code") search.push("code");
|
|
});
|
|
|
|
if (!name && _.contains(search, "name")) {
|
|
name = "name";
|
|
}
|
|
|
|
_.extend(scope.field, {
|
|
target: scope._model,
|
|
targetName: name,
|
|
targetSearch: search,
|
|
domain: data.domain
|
|
});
|
|
|
|
self._link(scope, element, attrs, model);
|
|
}
|
|
|
|
if (scope.fieldsCache[scope._model]) {
|
|
doLink(scope.fieldsCache[scope._model]);
|
|
} else {
|
|
scope.loadFields().success(function (fields) {
|
|
scope.fieldsCache[scope._model] = fields;
|
|
doLink(fields);
|
|
});
|
|
}
|
|
},
|
|
|
|
_link: function(scope, element, attrs, model) {
|
|
var name = element.attr('name');
|
|
|
|
scope.getValue = function () {
|
|
return scope.record[name];
|
|
};
|
|
|
|
var __setValue = scope.setValue;
|
|
|
|
scope.setValue = function (value) {
|
|
var val = _.pick(scope.record[name], 'model');
|
|
val = _.extend(val, value);
|
|
__setValue.call(scope, val);
|
|
};
|
|
|
|
function doSelect() {
|
|
var value = (scope.record || {})[name];
|
|
scope.select(value);
|
|
}
|
|
|
|
scope.$watch("record", doSelect);
|
|
}
|
|
});
|
|
|
|
})();
|