/* * Axelor Business Solutions * * Copyright (C) 2005-2019 Axelor (). * * 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 . */ (function() { "use strict"; var ui = angular.module('axelor.ui'); var popoverElem = null; var popoverTimer = null; function canDisplayPopover(scope, details) { if (axelor.device.mobile) { return false; } if(!axelor.config['user.technical']) { return details ? false : scope.field && scope.field.help; } return true; } function makePopover(scope, element, callback, placement) { var mode = axelor.config['application.mode']; var tech = axelor.config['user.technical']; var doc = $(document); var table = null; function addRow(label, text, klass) { if (table === null) { table = $('
'); } var tr = $('').appendTo(table); if (label) { $('').text(label).appendTo(tr); } if (klass == null) { text = '' + text + ''; } var td = $('').html(text).addClass(klass).appendTo(tr); if (!label) { td.attr('colspan', 2); } return table; } element.popover({ html: true, delay: { show: 1000, hide: 100 }, animate: true, placement: function() { if (placement) return placement; var coord = $(element.get(0)).offset(), viewport = { height: window.innerHeight, width: window.innerWidth }; if(viewport.height < (coord.top + 100)) return 'top'; if(coord.left > (viewport.width / 2)) return 'left'; return 'right'; }, trigger: 'manual', container: 'body', title: function() { return element.text(); }, content: function() { if (table) { table.remove(); table = null; } callback(scope, addRow); if (table) return table; return ""; } }); element.on('mouseenter.popover', enter); element.on('mouseleave.popover', leave); function selectText(elem) { var el = $(elem).get(0); if (document.selection) { var range = document.body.createTextRange(); range.moveToElementText(el); range.select(); } else if (window.getSelection) { var range = document.createRange(); range.selectNodeContents(el); window.getSelection().removeAllRanges(); window.getSelection().addRange(range); } } function enter(e, show) { if (popoverTimer) { clearTimeout(popoverTimer); } popoverTimer = setTimeout(function () { if (popoverElem === null) { popoverElem = element; popoverElem.popover('show'); if (e.ctrlKey) { selectText(table.find('.field-name,.model-name').get(0)); } } var tip = element.data('popover').$tip; if (tip) { tip.attr('tabIndex', 0); tip.css('outline', 'none'); } }, (e.ctrlKey || show) ? 0 : 1000); } function leave(e) { if (e.ctrlKey) { doc.off('mousemove.popover'); doc.on('mousemove.popover', leave); return; } if (popoverTimer) { clearTimeout(popoverTimer); popoverTimer = null; } if (popoverElem) { popoverElem.popover('hide'); popoverElem = null; doc.off('mousemove.popover'); } } function destroy() { if (popoverTimer) { clearTimeout(popoverTimer); popoverTimer = null; } if (element) { element.off('mouseenter.popover'); element.off('mouseleave.popover'); element.popover('destroy'); element = null; } if (table) { table.remove(); table = null; } doc.off('mousemove.popover'); } element.on('$destroy', destroy); scope.$on('$destroy', destroy); } function setupPopover(scope, element, getHelp, placement) { if (!canDisplayPopover(scope, false)) { return; } var timer = null; element.on('mouseenter.help.setup', function (e) { if (timer) { clearTimeout(timer); } timer = setTimeout(function () { element.off('mouseenter.help.setup'); element.off('mouseleave.help.setup'); makePopover(scope, element, getHelp, placement); element.trigger('mouseenter.popover', true); }, e.ctrlKey ? 0 : 1000); }); element.on('mouseleave.help.setup $destroy', function () { if (timer) { clearTimeout(timer); timer = null; } }); } ui.directive('uiTabPopover', function() { function getHelp(scope, addRow) { var tab = scope.tab || {}; var type = tab.viewType; var view = _.findWhere(tab.views, {type: type}); var viewScope = tab.$viewScope; if (viewScope && viewScope.schema) { view = viewScope.schema; } if (tab.action) { addRow(_t('Action'), tab.action); } if (tab.model) { addRow(_t('Object'), '' + tab.model + '', 'model-name'); } if (tab.domain) { addRow(_t('Domain'), tab.domain); } if (view && view.name) { addRow(_t('View'), view.name); } } return function(scope, element, attrs) { setupPopover(scope, element, getHelp, 'bottom'); }; }); ui.directive('uiHelpPopover', function() { function getHelp(scope, addRow) { var field = scope.field; var text = field.help; if (text) { text = text.replace(/\\n/g, '
'); addRow(null, text, 'help-text'); } if(!canDisplayPopover(scope, true)) { return; } if (text) { addRow(null, '
', 'help-text'); } var model = scope._model; if (model === field.target) { model = scope._parentModel || scope.$parent._model; } addRow(_t('Object'), model); addRow(_t('Field Name'), '' + field.name + '', 'field-name'); addRow(_t('Field Type'), field.serverType); if (field.type === 'text') { return; } if (field.domain) { addRow(_t('Filter'), field.domain); } if (field.target) { addRow(_t('Reference'), field.target); } var value = scope.$eval('$$original.' + field.name); var length; if (value && /-one$/.test(field.serverType)) { value = _.compact([value.id, value[field.targetName]]).join(','); value = '(' + value + ')'; } if (value && field.type === "password") { value = _.str.repeat('*', value.length); } if (value && /^(string|image|binary)$/.test(field.type)) { length = value.length; value = _.first(value, 50); if (length > 50) { value.push('...'); } value = value.join(''); } if (value && /(panel-related|one-to-many|many-to-many)/.test(field.serverType)) { length = value.length; value = _.first(value, 5); value = _.map(value, function(v){ return v.id; }); if (length > 5) { value.push('...'); } value = value.join(', '); } addRow(_t('Orig. Value'), value); } function doLink(scope, element, attrs) { var field = scope.field; if (field == null) { return; } if (field.help && axelor.config['user.noHelp'] !== true) { if (element.parent('label').length) { element.parent('label').addClass('has-help'); } else { element.addClass('has-help'); } } setupPopover(scope, element, getHelp); } return function(scope, element, attrs) { var field = scope.field; if (!_.isEmpty(field)) { return doLink(scope, element, attrs); } var unwatch = scope.$watch('field', function popoverFieldWatch(field, old) { if (!field) { return; } unwatch(); doLink(scope, element, attrs); }, true); }; }); /** * The Label widget. * */ ui.formItem('Label', { css: 'label-item', cellCss: 'form-label', transclude: true, link: function(scope, element, attrs) { var field = scope.field; if (field && field.required) { element.addClass('required'); } }, template: "" }); ui.directive('uiTranslateIcon', ['$q', function ($q) { return { link: function (scope, element) { var icon = $("").attr('title', _t('Show translations.')).appendTo(element); var toggle = function () { icon.toggle(!scope.$$readonlyOrig); }; scope.$watch("$$readonlyOrig", toggle); scope.$on("on:new", toggle); scope.$on("on:edit", toggle); var myDs = scope._dataSource; var trDs = scope._dataSource._new("com.axelor.meta.db.MetaTranslation"); trDs._sortBy = ["id"]; function saveData(value, data, orig, callback) { var changed = []; var removed = []; data.forEach(function (item) { var found = _.findWhere(orig, { id: item.id }); if (!angular.equals(found, item)) { changed.push(item); } }); orig.forEach(function (item) { var found = _.findWhere(data, { id: item.id }); if (!found) { removed.push(item); } }); function saveTranslations() { var all = []; if (removed.length) { all.push(trDs.removeAll(removed)); } if (changed.length) { all.push(trDs.saveAll(changed)); } if (all.length) { $q.all(all).then(function () { var lang = axelor.config['user.lang'] || en; var key = 'value:' + scope.getValue(); var trKey = '$t:' + scope.field.name; return trDs.search({ domain: "self.key = :key and self.language = :lang", context: { key: key, lang: lang }, limit: 1 }).success(function (records) { var record = _.first(records); if (scope.record) { scope.record[trKey] = (record||{}).message; scope.$parent.$parent.text = scope.format(scope.getValue()); var rec = scope._dataSource.get(scope.record.id); if (rec) { rec[trKey] = scope.record[trKey]; } } }); }).then(callback, callback); } else { callback(); } } if (value !== scope.getValue()) { scope.$parent.$parent.setValue(value, true); scope.waitForActions(function () { scope.$parent.$parent.onSave().then(saveTranslations, callback); }); } else { saveTranslations(); } } function showPopup(data) { if (!data || data.length == 0) { data = []; } var value = scope.getValue(); var orig = angular.copy(data); var form = $("
"); var valueInput = (scope.field.multiline ? $("