Files
ERP/sophal/js/widget/widget.update.js

474 lines
13 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.directive('uiDeleteButton', [function () {
return {
link: function (scope, element, attrs) {
},
replace: true,
template:
"<div class='btn-group delete-button'>" +
"<button class='btn' ng-click='onDelete()' ng-if='hasButton(\"delete\")' ng-disabled='!canDelete()' title='{{ \"Delete\" | t}}'>" +
"<i class='fa fa-trash-o'></i> <span ng-if='::!tbTitleHide' x-translate>Delete</span>" +
"</button>" +
"<button class='btn dropdown-toggle' data-toggle='dropdown' ng-if='hasButton(\"archive\")' ng-disabled='!canArchive()'>" +
"<i class='fa fa-caret-down'></i>" +
"</button>" +
"<ul class='dropdown-menu' ng-if='hasButton(\"archive\")'>" +
"<li><a href='' ng-click='onArchive()' x-translate>Archive</a></li>" +
"<li><a href='' ng-click='onUnarchive()' x-translate>Unarchive</a></li>" +
"</ul>" +
"</div>"
};
}]);
ui.directive('uiUpdateButton', ['$compile', function ($compile) {
return {
scope: {
handler: '='
},
link: function (scope, element, attrs) {
var menu = element.find('.update-menu'),
toggleButton = null;
scope.visible = false;
scope.onMassUpdate = function (e) {
if (menu && menu.is(':visible')) {
hideMenu();
return;
}
toggleButton = $(e.currentTarget);
toggleButton.addClass("active");
scope.onShow(e, menu);
$(document).on('mousedown.update-menu', onMouseDown);
scope.$applyAsync(function () {
scope.visible = true;
});
};
scope.onCancel = function () {
hideMenu();
};
scope.canMassUpdate = function () {
return true;
};
if (scope.handler && scope.handler.canMassUpdate) {
scope.canMassUpdate = scope.handler.canMassUpdate;
}
function hideMenu() {
$(document).off('mousedown.update-menu', onMouseDown);
if (toggleButton) {
toggleButton.removeClass("active");
}
scope.$applyAsync(function () {
scope.visible = false;
});
return menu.hide();
}
function onMouseDown(e) {
var all = $(menu).add(toggleButton);
if (all.is(e.target) || all.has(e.target).length > 0) {
return;
}
all = $('.ui-widget-overlay,.ui-datepicker:visible,.ui-dialog:visible,.ui-menu:visible');
if (all.is(e.target) || all.has(e.target).length > 0) {
return;
}
if(menu){
hideMenu();
}
}
// append box after the button
scope.$timeout(function () {
element.parents('.view-container').after(menu);
});
scope.$on('$destroy', function() {
$(document).off('mousedown.update-menu', onMouseDown);
if (menu) {
menu.remove();
menu = null;
}
});
},
replace: true,
template:
"<button class='btn update-menu-button' ng-click='onMassUpdate($event)' ng-disabled='!canMassUpdate()' >" +
"<i class='fa fa-caret-down'></i>" +
"<div ui-update-menu x-handler='handler' x-visible='visible'></div>" +
"</button>"
};
}]);
ui.directive('uiUpdateDummy', function () {
return {
require: '^uiUpdateForm',
scope: {
record: '='
},
controller: ['$scope', '$element', 'DataSource', 'ViewService', function($scope, $element, DataSource, ViewService) {
var parent = $scope.$parent;
var handler = parent.handler;
$scope._viewParams = {
model: handler._model,
views: []
};
ui.ViewCtrl($scope, DataSource, ViewService);
ui.FormViewCtrl.call(this, $scope, $element);
function prepare(fields) {
var schema = {
cols: 1,
type: 'form',
items: _.values(fields)
};
$scope.fields = fields;
$scope.schema = schema;
$scope.schema.loaded = true;
}
var initialized = false;
$scope.show = function () {
if (initialized) return;
initialized = true;
var unwatch = parent.$watch('fields', function massFieldsWatch(fields) {
if (_.isEmpty(fields)) return;
unwatch();
prepare(fields);
});
};
$scope.setEditable();
$scope.show();
}],
link: function (scope, element, attrs) {
element.hide();
},
template: "<div class='hide' ui-view-form x-handler='true'></div>"
};
});
ui.directive('uiUpdateForm', function () {
function findFields(fields, items) {
var all = {};
var accept = function (field) {
var name = field.name;
if (!field.massUpdate) return;
if (/^(id|version|selected|archived|((updated|created)(On|By)))$/.test(name)) return;
if (field.large || field.unique) return;
switch (field.type) {
case 'one-to-many':
case 'many-to-many':
case 'binary':
return;
}
if (field.target) {
field.canNew = false;
field.canEdit = false;
}
field.hidden = false;
field.required = false;
field.readonly = false;
field.onChange = null;
field.placeholder = field.placeholder || field.title;
all[name] = field;
};
_.each(fields, function (field, name) { accept(field); });
_.each(items, function (item) {
var field = fields[item.name];
if (field) {
accept(_.extend({}, field, item, { type: field.type }));
}
});
return all;
}
return {
replace: true,
controller: ['$scope', 'ViewService', function ($scope, ViewService) {
$scope.filters = [{}];
$scope.options = [];
$scope.onInit = _.once(function (view) {
var handler = $scope.handler;
var promise = ViewService.getFields(handler._model);
promise.success(function (fields) {
$scope.fields = findFields(fields, view.items);
$scope.options = _.sortBy(_.values($scope.fields), 'title');
$scope.record = {};
});
});
$scope.addFilter = function (filter) {
var all = $scope.filters;
var last = _.last(all);
if (last && !last.field) return;
if (all.length > 0 && all.length === $scope.options.length) return;
$scope.filters.push(filter || {});
$scope.updateSelection();
};
$scope.removeFilter = function(filter) {
var index = $scope.filters.indexOf(filter);
if (index > -1) {
$scope.filters.splice(index, 1);
}
if ($scope.filters.length === 0) {
$scope.addFilter();
}
};
$scope.notSelected = function (filter) {
return function (opt) {
return filter.field === opt.name || !opt.selected;
};
};
var values = null;
var canUpdate = false;
function updateValues(record) {
var keys = _.pluck($scope.filters, 'field'),
vals = {};
_.each(keys, function (key) {
if (key) {
vals[key] = (record || {})[key];
if (vals[key] === undefined) {
vals[key] = null;
}
}
});
values = vals;
canUpdate = !_.isEmpty(values);
}
$scope.updateSelection = function updateSelection () {
var selected = _.pluck($scope.filters, 'field');
_.each($scope.options, function (opt) {
opt.selected = selected.indexOf(opt.name) > -1;
});
updateValues($scope.record);
};
$scope.$watch('record', updateValues, true);
$scope.canUpdate = function () {
return canUpdate;
};
$scope.updateAll = false;
$scope.applyUpdate = function () {
var handler = $scope.handler;
var ds = handler._dataSource;
function doUpdate() {
var promise, items;
items = _.map(handler.selection, function(index) {
return handler.dataView.getItem(index);
});
items = _.pluck(items, "id");
if ($scope.updateAll) {
items = null;
} else if (items.length === 0) {
return $scope.onCancel();
}
promise = ds.updateMass(values, items);
promise.success(function () {
handler.onRefresh();
$scope.onCancel();
});
}
var count;
if ($scope.updateAll) {
count = ds._page.total;
} else if(handler.selection && handler.selection.length > 0) {
count = handler.selection.length;
} else {
return;
}
var message = _t('Do you really want to update all {0} record(s)?', count);
axelor.dialogs.confirm(message, function (confirmed) {
if (confirmed) {
doUpdate();
}
});
};
}],
link: function (scope, element, attrs) {
scope.onSelect = function (name) {
scope.updateSelection();
setTimeout(adjustEditors);
};
scope.clearFilter = function() {
scope.filters.length = 0;
scope.addFilter();
scope.record = {};
adjustEditors();
};
scope.remove = function(filter) {
scope.removeFilter(filter);
adjustEditors();
};
scope.onCancel = function () {
if (scope.$parent.onCancel) {
scope.$parent.onCancel();
}
};
function adjustEditors() {
element.find('[x-place-for] [x-field]').each(function () {
var editor = $(this);
var parent = editor.data('$parent');
editor.appendTo(parent);
});
_.each(scope.filters, function (filter) {
adjustEditor(filter.field);
});
}
function adjustEditor(name) {
var span = element.find('[x-place-for=' + name + ']');
var editor = element.find('[x-field=' + name + '].form-item-container,[x-field=' + name + '].boolean-item').first();
var parent = editor.data('$parent');
if (!parent) {
parent = editor.parent();
editor.data('$parent', parent);
}
editor.appendTo(span);
}
},
template:
"<form class='form-inline update-form filter-form'>" +
"<strong x-translate>Mass Update</strong> " +
"<hr>" +
"<table class='form-layout'>" +
"<tr ng-repeat='filter in filters' class='form-inline'>" +
"<td class='filter-remove'>" +
"<a href='' ng-click='remove(filter)'><i class='fa fa-times'></i></a>" +
"</td>" +
"<td class='form-item'>" +
"<span class='form-item-container'>" +
"<select ng-model='filter.field' ng-options='v.name as v.title for v in options | filter:notSelected(filter)' ng-change='onSelect(filter.field)'></select>" +
"</span>" +
"</td>" +
"<td class='form-item' x-place-for='{{filter.field}}'>" +
"</td>" +
"</tr>" +
"</table>" +
"<div class='links'>"+
"<a href='' ng-click='addFilter()' x-translate>Add Field</a>" +
"<span class='divider'>|</span>"+
"<a href='' ng-click='clearFilter()' x-translate>Clear</a>" +
"</div>" +
"<div ui-update-dummy x-record='record'></div>"+
"</form>"
};
});
ui.directive('uiUpdateMenu', function () {
return {
replace: true,
scope: {
handler: '='
},
link: function (scope, element, attrs) {
scope.$parent.onShow = function (event, menu) {
scope.handler._viewPromise.then(function (view) {
var elem = $(event.currentTarget);
if (scope.onInit) {
scope.onInit(view);
}
menu.show();
menu.position({
my: "left top",
at: "left bottom",
of: elem
});
});
};
},
template:
"<div class='update-menu filter-menu' ui-watch-if='$parent.visible'>" +
"<div ui-update-form></div>" +
"<hr>" +
"<div class='form-inline'>" +
"<button class='btn btn-small' ng-disabled='!canUpdate()' ng-click='applyUpdate()'><span x-translate>Update</span></button> " +
"<button class='btn btn-small' ng-click='onCancel()'><span x-translate>Cancel</span></button> " +
"<label class='checkbox update-all'>" +
"<input type='checkbox' ng-model='updateAll'> <span x-translate>Update all</span>" +
"</label> " +
"</div>" +
"</div>"
};
});
})();