First commit waiting for Budget Alert
This commit is contained in:
511
sophal/js/view/view.popup.js
Normal file
511
sophal/js/view/view.popup.js
Normal file
@ -0,0 +1,511 @@
|
||||
/*
|
||||
* 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");
|
||||
|
||||
EditorCtrl.$inject = ['$scope', '$element', 'DataSource', 'ViewService', '$q'];
|
||||
|
||||
function EditorCtrl($scope, $element, DataSource, ViewService, $q) {
|
||||
|
||||
var parent = $scope.$parent;
|
||||
|
||||
$scope._viewParams = parent._viewParams;
|
||||
$scope.editorCanSave = parent.editorCanSave;
|
||||
$scope.editorCanReload = parent.editorCanReload;
|
||||
|
||||
ui.ViewCtrl.call(this, $scope, DataSource, ViewService);
|
||||
ui.FormViewCtrl.call(this, $scope, $element);
|
||||
|
||||
var closeCallback = null;
|
||||
var originalEdit = $scope.edit;
|
||||
var originalShow = $scope.show;
|
||||
|
||||
var recordVersion = -1;
|
||||
var canClose = false;
|
||||
var isClosed = true;
|
||||
|
||||
$scope.show = function(record, callback) {
|
||||
originalShow();
|
||||
if (_.isFunction(record)) {
|
||||
callback = record;
|
||||
record = null;
|
||||
}
|
||||
closeCallback = callback;
|
||||
isClosed = false;
|
||||
recordVersion = record ? record.version : -1;
|
||||
if (recordVersion === undefined && record) {
|
||||
recordVersion = record.$version;
|
||||
}
|
||||
this.edit(record);
|
||||
};
|
||||
|
||||
function doEdit(record, fireOnLoad) {
|
||||
if (record && record.id > 0 && (!_.isNumber(record.version) || !record.$fetched)) {
|
||||
$scope.doRead(record.id).success(function(rec) {
|
||||
if (record.$dirty) {
|
||||
rec = _.extend({}, rec, record);
|
||||
}
|
||||
originalEdit(rec, fireOnLoad);
|
||||
});
|
||||
} else {
|
||||
originalEdit(record, fireOnLoad);
|
||||
}
|
||||
canClose = false;
|
||||
}
|
||||
|
||||
var parentCanEditTarget = null;
|
||||
|
||||
$scope.canEditTarget = function () {
|
||||
if (parentCanEditTarget === null) {
|
||||
var parent = $scope.$parent;
|
||||
var func = parent.canEditTarget;
|
||||
while (parent && func === $scope.canEditTarget) {
|
||||
parent = parent.$parent;
|
||||
func = parent.canEditTarget;
|
||||
}
|
||||
parentCanEditTarget = func || angular.noop;
|
||||
}
|
||||
return parentCanEditTarget() !== false;
|
||||
};
|
||||
|
||||
var isEditable = $scope.isEditable;
|
||||
$scope.isEditable = function () {
|
||||
var id = ($scope.record || {}).id;
|
||||
var perm = id > 0 ? 'write' : 'create';
|
||||
if (parent.isReadonly && parent.isReadonly()) return false;
|
||||
return $scope.hasPermission(perm)
|
||||
&& (id > 0 ? $scope.canEditTarget() : true)
|
||||
&& isEditable.call($scope);
|
||||
};
|
||||
|
||||
var canEdit = $scope.canEdit;
|
||||
$scope.canEdit = function() {
|
||||
return $scope.canEditTarget() && canEdit.call($scope);
|
||||
};
|
||||
|
||||
$scope.edit = function(record, fireOnLoad) {
|
||||
if (isClosed) return;
|
||||
$scope._viewPromise.then(function(){
|
||||
doEdit(record, fireOnLoad);
|
||||
$scope.setEditable(!$scope.$parent.$$readonly);
|
||||
});
|
||||
};
|
||||
|
||||
function isChanged() {
|
||||
if ($scope.isDirty()) return true;
|
||||
var record = $scope.record || {};
|
||||
var version = record.version;
|
||||
return recordVersion !== version || record.$forceDirty;
|
||||
}
|
||||
|
||||
function canOK() {
|
||||
if (isClosed) return false;
|
||||
return isChanged();
|
||||
}
|
||||
|
||||
function onOK() {
|
||||
|
||||
var record = $scope.record;
|
||||
|
||||
function close(value, forceSelect) {
|
||||
if (value && (forceSelect || canOK())) {
|
||||
value.$fetched = true;
|
||||
value.selected = true;
|
||||
$scope.$parent.select(value);
|
||||
}
|
||||
canClose = true;
|
||||
$element.dialog('close');
|
||||
if ($scope.editorCanReload) {
|
||||
$scope.$parent.parentReload();
|
||||
}
|
||||
if (closeCallback && value) {
|
||||
closeCallback(value);
|
||||
}
|
||||
closeCallback = null;
|
||||
isClosed = true;
|
||||
}
|
||||
|
||||
var event = $scope.$broadcast('on:before-save', record);
|
||||
if (event.defaultPrevented) {
|
||||
if (event.error) {
|
||||
axelor.dialogs.error(event.error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// wait for onChange actions
|
||||
$scope.waitForActions(function() {
|
||||
if ($scope.editorCanSave && isChanged()) {
|
||||
if (record.id < 0)
|
||||
record.id = null;
|
||||
return $scope.onSave({force: true}).then(function(record, page) {
|
||||
// wait for onSave actions
|
||||
$scope.waitForActions(function(){
|
||||
close(record, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
if ($scope.isValid()) {
|
||||
close(record);
|
||||
} else if ($scope.showErrorNotice) {
|
||||
$scope.showErrorNotice();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
$scope.onOK = function() {
|
||||
$scope.$timeout(onOK, 10);
|
||||
};
|
||||
|
||||
$scope.onBeforeClose = function(event, ui) {
|
||||
|
||||
if (canClose || !$scope.isDirty()) {
|
||||
$scope.$evalAsync(function () {
|
||||
$scope.edit(null, false);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
$scope.confirmDirty(function(){
|
||||
canClose = true;
|
||||
$element.dialog('close');
|
||||
});
|
||||
};
|
||||
|
||||
$scope.onHotKey = function (e, action) {
|
||||
|
||||
if (action === "save") {
|
||||
$(e.target).blur().focus();
|
||||
$scope.onOK();
|
||||
}
|
||||
|
||||
$scope.$applyAsync();
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
SelectorCtrl.$inject = ['$scope', '$element', 'DataSource', 'ViewService'];
|
||||
function SelectorCtrl($scope, $element, DataSource, ViewService) {
|
||||
|
||||
var parent = $scope.$parent;
|
||||
|
||||
$scope._viewParams = parent._viewParams;
|
||||
$scope.getDomain = parent.getDomain;
|
||||
|
||||
ui.ViewCtrl.call(this, $scope, DataSource, ViewService);
|
||||
ui.GridViewCtrl.call(this, $scope, $element);
|
||||
|
||||
var searchLimit = (parent.field||{}).searchLimit || 0;
|
||||
if (searchLimit > 0) {
|
||||
$scope._dataSource._page.limit = searchLimit;
|
||||
}
|
||||
|
||||
function doFilter() {
|
||||
$scope.filter($scope.getDomain());
|
||||
}
|
||||
|
||||
var initialized = false;
|
||||
var origShow = $scope.show;
|
||||
$scope.show = function() {
|
||||
origShow();
|
||||
if (initialized) {
|
||||
doFilter();
|
||||
}
|
||||
};
|
||||
|
||||
var _getContext = $scope.getContext;
|
||||
$scope.getContext = function() {
|
||||
// selector popup should return parent's context
|
||||
if ($scope.$parent && $scope.$parent.getContext) {
|
||||
return $scope.$parent.getContext();
|
||||
}
|
||||
return _getContext();
|
||||
};
|
||||
|
||||
$scope.onItemClick = function(e, args) {
|
||||
$scope.$applyAsync($scope.onOK.bind($scope));
|
||||
};
|
||||
|
||||
var origOnShow = $scope.onShow;
|
||||
$scope.onShow = function(viewPromise) {
|
||||
|
||||
viewPromise.then(function(){
|
||||
var view = $scope.schema;
|
||||
var field = $scope.field || $scope.$parent.field;
|
||||
if (field) {
|
||||
view.orderBy = field.orderBy || view.orderBy;
|
||||
}
|
||||
$element.dialog('open');
|
||||
initialized = true;
|
||||
origOnShow(viewPromise);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.onOK = function() {
|
||||
|
||||
var selection = _.map($scope.selection, function(index){
|
||||
return $scope.dataView.getItem(index);
|
||||
});
|
||||
|
||||
if (!_.isEmpty(selection)) {
|
||||
$scope.$applyAsync(function () {
|
||||
$scope.$parent.select(selection);
|
||||
$scope.selection = [];
|
||||
});
|
||||
}
|
||||
|
||||
$element.dialog('close');
|
||||
};
|
||||
|
||||
$scope.onCreate = function () {
|
||||
$element.dialog('close');
|
||||
$scope.$parent.onNew();
|
||||
};
|
||||
|
||||
$scope.canNew = function () {
|
||||
return $scope.hasPermission('create') && $scope.$parent.canNew();
|
||||
};
|
||||
}
|
||||
|
||||
ui.directive('uiDialogSize', function() {
|
||||
|
||||
return function (scope, element, attrs) {
|
||||
|
||||
// use only with dialogs
|
||||
if (attrs.uiDialog === undefined && !element.hasClass('ui-dialog-content')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var loaded = false;
|
||||
var addMaximizeButton = _.once(function () {
|
||||
var elemDialog = element.parent();
|
||||
var elemTitle = elemDialog.find('.ui-dialog-title');
|
||||
var elemButton = $('<a href="#" class="ui-dialog-titlebar-max"><i class="fa fa-expand"></i></a>')
|
||||
.click(function (e) {
|
||||
$(this).children('i').toggleClass('fa-expand fa-compress');
|
||||
elemDialog.toggleClass('maximized');
|
||||
axelor.$adjustSize();
|
||||
setTimeout(function () {
|
||||
scope.$broadcast('grid:adjust-columns');
|
||||
}, 350);
|
||||
return false;
|
||||
}).insertAfter(elemTitle);
|
||||
|
||||
// remove maximized state on close
|
||||
element.on('dialogclose', function(e, ui) {
|
||||
elemTitle.parent().find('i.fa-compress').toggleClass('fa-expand fa-compress');
|
||||
elemDialog.removeClass('maximized');
|
||||
});
|
||||
|
||||
var params = (scope._viewParams || {}).params || {};
|
||||
if (params['popup.maximized']) {
|
||||
elemButton.click();
|
||||
}
|
||||
});
|
||||
var addCollapseButton = _.once(function () {
|
||||
var elemDialog = element.parent();
|
||||
var elemTitle = elemDialog.find('.ui-dialog-title');
|
||||
$('<a href="#" class="ui-dialog-titlebar-collapse"><i class="fa fa-chevron-up"></i></a>')
|
||||
.click(function (e) {
|
||||
$(this).children('i').toggleClass('fa-chevron-up fa-chevron-down');
|
||||
elemDialog.toggleClass('collapsed');
|
||||
axelor.$adjustSize();
|
||||
return false;
|
||||
}).insertAfter(elemTitle);
|
||||
|
||||
// remove maximized and collapsed states on close
|
||||
element.on('dialogclose', function(e, ui) {
|
||||
elemTitle.parent().find('i.fa-compress').toggleClass('fa-expand fa-compress');
|
||||
elemTitle.parent().find('i.fa-chevron-down').toggleClass('fa-chevron-down fa-chevron-up');
|
||||
elemDialog.removeClass('maximized collapsed');
|
||||
});
|
||||
});
|
||||
|
||||
function doAdjust() {
|
||||
element.dialog('open');
|
||||
element.scrollTop(0);
|
||||
setTimeout(doFocus);
|
||||
if (scope._afterPopupShow) {
|
||||
scope._afterPopupShow();
|
||||
}
|
||||
}
|
||||
|
||||
function doShow() {
|
||||
addMaximizeButton();
|
||||
addCollapseButton();
|
||||
if (loaded) {
|
||||
return setTimeout(doAdjust);
|
||||
}
|
||||
loaded = true;
|
||||
scope.waitForActions(doAdjust);
|
||||
}
|
||||
|
||||
function doFocus() {
|
||||
var container = element.is('[ui-selector-popup]')
|
||||
? element.find('.slick-headerrow')
|
||||
: element;
|
||||
var focusElem = container.find('input:tabbable');
|
||||
if (focusElem.length == 0) {
|
||||
focusElem = element.parent().find('.ui-dialog-buttonset').find(':tabbable');
|
||||
}
|
||||
if (focusElem[0]) {
|
||||
focusElem[0].focus();
|
||||
}
|
||||
|
||||
//XXX: ui-dialog issue
|
||||
element.find('.slick-headerrow-column,.slickgrid,[ui-embedded-editor]').zIndex(element.zIndex());
|
||||
element.find('.record-toolbar .btn').zIndex(element.zIndex()+1);
|
||||
}
|
||||
|
||||
// a flag used by evalScope to detect popup (see form.base.js)
|
||||
scope._isPopup = true;
|
||||
scope._doShow = function(viewPromise) {
|
||||
if (viewPromise && viewPromise.then) {
|
||||
viewPromise.then(doShow);
|
||||
} else {
|
||||
doShow();
|
||||
}
|
||||
};
|
||||
|
||||
scope._setTitle = function (title) {
|
||||
if (title) {
|
||||
element.closest('.ui-dialog').find('.ui-dialog-title').text(title);
|
||||
}
|
||||
};
|
||||
|
||||
scope.adjustSize = function() {
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
ui.directive('uiEditorPopup', function() {
|
||||
|
||||
return {
|
||||
restrict: 'EA',
|
||||
controller: EditorCtrl,
|
||||
scope: {},
|
||||
link: function(scope, element, attrs) {
|
||||
|
||||
scope.onShow = function(viewPromise) {
|
||||
scope._doShow(viewPromise);
|
||||
};
|
||||
|
||||
scope.$watch('schema.title', function popupTitleWatch(title) {
|
||||
scope._setTitle(title);
|
||||
});
|
||||
|
||||
element.scroll(function (e) {
|
||||
$(document).trigger('adjust:scroll', element);
|
||||
});
|
||||
|
||||
var onNewHandler = scope.onNewHandler;
|
||||
scope.onNewHandler = function (event) {
|
||||
if (scope.isPopupOpen) {
|
||||
return onNewHandler.apply(scope, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
scope.isPopupOpen = true;
|
||||
setTimeout(function () {
|
||||
var isOpen = false;
|
||||
element.on('dialogclose', function (e) {
|
||||
isOpen = false;
|
||||
scope.waitForActions(function () {
|
||||
scope.isPopupOpen = isOpen;
|
||||
scope.$$popupStack.pop(1);
|
||||
}, 2000); // delay couple of seconds to that popup can cleanup
|
||||
});
|
||||
element.on('dialogopen', function (e) {
|
||||
scope.isPopupOpen = isOpen = true;
|
||||
scope.$$popupStack.push(1);
|
||||
scope.$applyAsync();
|
||||
});
|
||||
});
|
||||
},
|
||||
replace: true,
|
||||
template:
|
||||
'<div ui-dialog ui-dialog-size x-on-ok="onOK" x-on-before-close="onBeforeClose" ui-watch-if="isPopupOpen">'+
|
||||
'<div ui-view-form x-handler="this"></div>'+
|
||||
'</div>'
|
||||
};
|
||||
});
|
||||
|
||||
ui.directive('uiSelectorPopup', function(){
|
||||
|
||||
return {
|
||||
restrict: 'EA',
|
||||
controller: SelectorCtrl,
|
||||
scope: {
|
||||
selectMode: "@"
|
||||
},
|
||||
link: function(scope, element, attrs) {
|
||||
|
||||
var onShow = scope.onShow;
|
||||
scope.onShow = function (viewPromise) {
|
||||
if (scope.clearFilters) {
|
||||
scope.clearFilters();
|
||||
scope.selection = [];
|
||||
}
|
||||
onShow(viewPromise);
|
||||
scope._doShow(viewPromise);
|
||||
};
|
||||
|
||||
scope.$watch('schema.title', function popupTitleWatch(title){
|
||||
scope._setTitle(title);
|
||||
});
|
||||
|
||||
var btnOK = null;
|
||||
|
||||
function buttonState(count) {
|
||||
if (btnOK === null) {
|
||||
btnOK = element.siblings('.ui-dialog-buttonpane').find('.btn:last');
|
||||
}
|
||||
return btnOK.attr('disabled', !count || count <= 0);
|
||||
}
|
||||
|
||||
scope.$watch('selection.length', buttonState);
|
||||
|
||||
setTimeout(function(){
|
||||
var footer = element.closest('.ui-dialog').find('.ui-dialog-buttonpane'),
|
||||
header = element.closest('.ui-dialog').find('.ui-dialog-titlebar'),
|
||||
pager = element.find('.record-pager'),
|
||||
buttons = element.find('.ui-dialog-buttonset-left');
|
||||
header.find('.ui-dialog-title').after(pager);
|
||||
footer.prepend(buttons);
|
||||
footer.find('.button-ok').html(_t("Select"));
|
||||
});
|
||||
},
|
||||
replace: true,
|
||||
template:
|
||||
'<div ui-dialog ui-dialog-size x-on-ok="onOK">'+
|
||||
'<div ui-view-grid x-view="schema" x-data-view="dataView" x-handler="this" x-editable="false" x-selector="{{selectMode}}"></div>'+
|
||||
'<div ui-record-pager></div>'+
|
||||
'<div class="ui-dialog-buttonset-left pull-left" ng-show="canNew()">'+
|
||||
'<button class="btn" ng-click="onCreate()" x-translate>Create</button>'+
|
||||
'</div>'+
|
||||
'</div>'
|
||||
};
|
||||
});
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user