@unclepaul/allcountjs
Version:
The open source framework for rapid business application development with Node.js
1,050 lines (911 loc) • 46.7 kB
JavaScript
var allcountModule = angular.module("allcount", ['ngAnimate', 'blueimp.fileupload', 'ui.bootstrap', 'allcount-base']);
window.allcountModule = allcountModule;
allcountModule.factory('track', function () {
return lc.track;
});
allcountModule.config(["$httpProvider", function ($httpProvider) {
$httpProvider.interceptors.push(['$q', 'track', function ($q, track) {
return {
responseError: function (rejection) {
if (rejection.status !== 403) {
track("allcount-rest-error", {
url: rejection.config.url,
req: rejection.config.data,
method: rejection.config.method,
status: rejection.status,
res: rejection.data
});
}
return $q.reject(rejection);
}
};
}]);
}]);
allcountModule.config(["$locationProvider", function ($locationProvider) {
$locationProvider.html5Mode({ enabled: true, requireBase: true });
}]);
/**
* Deprecated
*/
allcountModule.factory("rest", ["lcApi", function (lcApi) {
return lcApi;
}]);
allcountModule.config(["fieldRenderingServiceProvider", function (fieldRenderingServiceProvider) {
fieldRenderingServiceProvider.defineFields(["$timeout", "$filter", "$compile", "$locale", "lcApi", "messages", function ($timeout, $filter, $compile, $locale, rest, messages) {
var dateRegex = /^(\d{4})-(\d\d)-(\d\d)$/;
function textareaRenderer(value) {
var elem = $('<p></p>');
var escapedText = elem.text(value).html();
elem.addClass("textarea-field-paragraph");
const escapedHtml = escapedText.split("\n").join('<br>');
elem.html(escapedHtml);
return elem;
}
function parseDate(s) {
return s && moment(s, 'YYYY-MM-DD HH:mm:ss').toDate();
}
function parseDateToMoment(s) {
return moment(s, "YYYY-MM-DD HH:mm:ss");
}
function wireTextInputWithController(input, controller, updateValue) {
input.val(controller.$viewValue);
input.on('input', function () {
var value = $.trim($(this).val());
updateValue(value.length > 0 ? value : undefined);
});
return input;
}
function textInput(controller, updateValue) {
var input = $('<input type="text" class="form-control"/>'); //TODO remove form-control?
return wireTextInputWithController(input, controller, updateValue);
}
function textareaInput(controller, updateValue) {
var input = $('<textarea class="form-control"/>'); //TODO remove form-control?
return wireTextInputWithController(input, controller, updateValue);
}
function maskedInput(controller, updateValue, mask) {
var input = $('<input type="text" class="form-control"/>'); //TODO remove form-control?
$(input).inputmask(mask);
input.val(controller.$viewValue);
function listener() {
var value = $.trim($(this).val());
updateValue(value.length > 0 && $(input).inputmask("isComplete") ? value : undefined);
}
input.on('input', listener);
input.on('cleared', listener);
input.change(listener); //TODO triggers on blur but not always before save
return input;
}
var currencyConfig = { //TODO
'alias': 'numeric',
'radixPoint': $locale.NUMBER_FORMATS.DECIMAL_SEP,
'groupSeparator': $locale.NUMBER_FORMATS.GROUP_SEP,
'autoGroup': true,
'digits': 2, //$locale.NUMBER_FORMATS.PATTERNS[1].maxFrac, //TODO could be other than 2?
'digitsOptional': false,
'placeholder': '0'
};
function renderCurrency(viewValue) {
return viewValue && $.inputmask.format(viewValue.slice(0, viewValue.length - 2) + currencyConfig.radixPoint + viewValue.slice(viewValue.length - 2), currencyConfig) || undefined;
}
var referenceRenderer = function (value, fieldDescription) {
if (value) {
var link = $('<a></a>');
link.attr('href', '/entity/' + fieldDescription.fieldType.referenceEntityTypeId + '/' + value.id); //TODO base href
link.text(value.name);
return link;
}
return undefined;
};
var dateFormat = function (fieldDescription) {
return fieldDescription.fieldType.hasTime ? $locale.DATETIME_FORMATS.short : $locale.DATETIME_FORMATS.shortDate;
};
var toMomentDateFormat = function (angularDateFormat) {
return angularDateFormat.replace("yyyy", "YYYY").replace("yy", "YY").replace("y", "YYYY").replace("dd", "DD").replace("d", "D")
.replace('EEEE', 'dddd').replace('EEE', 'ddd')
.replace('ww', 'WW').replace('w', 'W')
.replace('sss', 'SSS');
};
return {
text: [function (value, fieldDescription) {
return fieldDescription.fieldType.isMultiline ? textareaRenderer(value) : value;
}, function (fieldDescription, controller, updateValue, clone, scope) {
if (fieldDescription.fieldType.isMultiline) {
return textareaInput(controller, updateValue);
} else if (fieldDescription.fieldType.mask) {
return maskedInput(controller, updateValue, fieldDescription.fieldType.mask);
} else {
return textInput(controller, updateValue)
}
}],
radio: [function (value, fieldDescription) {
return value;
}, function (fieldDescription, controller, updateValue, clone, scope) {
scope.radioValue = controller.$viewValue;
scope.$watch('radioValue', function (radioValue) {
controller.$setViewValue(radioValue);
});
var radioInputs = fieldDescription.fieldType.valuesArray.map(function (value) {
return '<input type="radio" ng-model="radioValue" value="{0}">{0}<br/>'.replace(/\{0\}/g, value);
}).join("\n");
return $compile(radioInputs)(scope);
}],
date: [function (value, fieldDescription) {
return $filter('date')(parseDate(value), dateFormat(fieldDescription));
}, function (fieldDescription, controller, updateValue, clone, scope) { //TODO
var input = $('<div class="input-group date"><input type="text" class="form-control"><span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span></div>');
input.datetimepicker({
locale: $locale.id.split("-")[0],
format: toMomentDateFormat(dateFormat(fieldDescription))
});
if (typeof controller.$viewValue != 'undefined') {
input.data("DateTimePicker").date(parseDate(controller.$viewValue) || null);
input.data("DateTimePicker").defaultDate(parseDateToMoment(controller.$viewValue) || null);
}
input.on('dp.change', function (e) {
updateValue(e.date ? e.date.format('YYYY-MM-DD HH:mm:ss') : undefined);
});
$('input', input).focus(function () {
input.data("DateTimePicker").show();
});
return input;
}],
integer: [function (value) {
return !isNaN(value) && value.toString() || "";
}, function (fieldDescription, controller, updateValue, clone, scope) {
scope.integerValue = controller.$viewValue;
scope.pattern = /\d+/;
scope.$watch('integerValue', function (integerValue) {
var x = integerValue && parseInt(integerValue, 10)
controller.$setViewValue(isNaN(x) ? undefined : x);
});
return $compile('<input ng-model="integerValue" class="form-control" ng-pattern="pattern">')(scope);
}],
number: [function (value) {
return !isNaN(value) && value.toString() || "";
}, function (fieldDescription, controller, updateValue, clone, scope) {
scope.numberValue = controller.$viewValue;
scope.pattern = /[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/;
scope.$watch('numberValue', function (numberValue) {
var x = numberValue && parseFloat(numberValue)
controller.$setViewValue(isNaN(x) ? undefined : x);
});
return $compile('<input ng-model="numberValue" class="form-control" ng-pattern="pattern">')(scope);
}],
money: [function (value) {
return renderCurrency(value);
}, function (fieldDescription, controller, updateValue, clone, scope) {
var input = $('<input type="text" class="form-control"/>'); //TODO remove form-control?
var viewValue = controller.$viewValue;
viewValue = renderCurrency(viewValue);
input.val(viewValue);
input.on('input', function () {
var value = $.trim($(this).val()).replace(/[^0-9]/g, '');
updateValue(value.length > 0 ? value : undefined);
});
$(input).inputmask(currencyConfig);
return input;
}],
checkbox: [function (value) {
return value ? messages("Yes") : messages("No");
}, function (fieldDescription, controller, updateValue, clone, scope) {
scope.checkboxValue = controller.$viewValue;
scope.$watch('checkboxValue', function (checkboxValue) {
controller.$setViewValue(checkboxValue);
});
return $compile('<div class="checkbox"><label><input type="checkbox" ng-model="checkboxValue"></label></div>')(scope);
}],
reference: [referenceRenderer, function (fieldDescription, controller, updateValue, clone, scope) {
if (fieldDescription.fieldType.render === 'fixed') {
rest.referenceValues(fieldDescription.fieldType.referenceEntityTypeId, function (referenceValues) {
scope.referenceValues = referenceValues;
scope.referenceIdToValue = {};
$(scope.referenceValues).each(function (index, item) {
scope.referenceIdToValue[item.id] = item;
});
scope.$watch('selectedReferenceId', function (referenceValueId) {
controller.$setViewValue(referenceValueId ? scope.referenceIdToValue[referenceValueId] : undefined);
});
});
scope.selectedReferenceId = controller.$viewValue ? controller.$viewValue.id : undefined;
return $compile('<select ng-model="selectedReferenceId" ng-options="r.id as r.name for r in referenceValues" class="form-control"></select>')(scope);
} else {
scope.referenceEntityTypeId = fieldDescription.fieldType.referenceEntityTypeId;
scope.$watch('selectedReference.value', function (referenceValue) {
controller.$setViewValue(referenceValue);
});
scope.selectedReference = { value: controller.$viewValue };
return $compile('<div ng-model="selectedReference.value" lc-reference="referenceEntityTypeId"></div>')(scope);
}
}],
multiReference: [function (value, fieldDescription) {
if (value) {
var container = $('<div></div>');
value.forEach(function (i) {
var wrapper = $('<div></div>');
wrapper.append(referenceRenderer(i, fieldDescription));
container.append(wrapper);
});
return container;
}
return undefined;
}, function (fieldDescription, controller, updateValue, clone, scope) {
scope.referenceEntityTypeId = fieldDescription.fieldType.referenceEntityTypeId;
scope.$watch('selectedReference.value', function (referenceValue) {
controller.$setViewValue(referenceValue);
});
scope.selectedReference = { value: controller.$viewValue };
return $compile('<div ng-model="selectedReference.value" lc-reference="referenceEntityTypeId" is-multiple="true"></div>')(scope);
}],
password: [function (value) {
return '';
}, function (fieldDescription, controller, updateValue, clone, scope) { //TODO doubling
var input = $('<input type="password" class="form-control"/>'); //TODO remove form-control?
input.val(controller.$viewValue);
input.on('input', function () {
var value = $.trim($(this).val());
updateValue(value.length > 0 ? value : undefined);
});
return input;
}],
relation: [false, function (fieldDescription, controller, updateValue, clone, scope) {
scope.entityCrudId = null;
scope.navigateToChild = function (entityId)
{
window.location = '/entity/' + fieldDescription.fieldType.relationEntityTypeId + '/' + entityId;
};
scope.$parent.$watch('entity', function (entity) {
scope.entityCrudId = entity && entity.id ? {
entityTypeId: scope.entityTypeId,
relationField: fieldDescription.field,
parentEntityId: entity.id
} : undefined;
});
return $compile('<div ng-if="entityCrudId" lc-grid="entityCrudId" navigate="navigateToChild($entityId)" paging="{}" edit-mode="isEditor"></div>')(scope);
}],
attachment: [function (value, fieldDescription) {
if (!value) {
return undefined;
}
var elem;
if (fieldDescription.fieldType.image) {
var link = $('<a data-gallery></a>');
link.attr('href', value.secure_url);
elem = $('<img>');
elem.attr('src', value.secure_url.replace(/\/v\d+/, '/w_100,h_100,c_fill'));
link.append(elem);
link.click(function (e) {
e.preventDefault();
blueimp.Gallery(link, { event: e });
});
if (!$('#blueimp-gallery').length) {
$('body').append('<div id="blueimp-gallery" class="blueimp-gallery"><div class="slides"></div><h3 class="title"></h3><a class="close">×</a></div>');
}
return link;
}
elem = $('<a></a>');
elem.attr('href', '/api/file/download/' + value.fileId);
elem.text(value.name);
return elem;
}, function (fieldDescription, controller, updateValue, clone, scope) {
scope.fieldValue = controller.$viewValue;
scope.$watch('fieldValue', function (value) {
controller.$setViewValue(value);
});
scope.provider = fieldDescription.fieldType.provider;
return $compile('<div lc-upload="fieldValue" provider="{{provider}}"></div>')(scope);
}],
link: [function (value, fieldDescription) {
var link = $('<a target="_blank"></a>');
link.attr('href', value);
link.text(value);
return link;
}, function (fieldDescription, controller, updateValue, clone, scope) {
scope.linkValue = controller.$viewValue;
scope.$watch('linkValue', function (linkValue) {
controller.$setViewValue(linkValue ? linkValue : undefined);
});
return $compile('<input type="url" ng-model="linkValue" class="form-control">')(scope);
}],
email: [function (value, fieldDescription) {
var link = $('<a></a>');
link.attr('href', 'mailto:' + value);
link.text(value);
return link;
}, function (fieldDescription, controller, updateValue, clone, scope) {
scope.emailValue = controller.$viewValue;
scope.$watch('emailValue', function (emailValue) {
controller.$setViewValue(emailValue ? emailValue : undefined);
});
return $compile('<input type="email" ng-model="emailValue" class="form-control">')(scope);
}],
json: [function (value, fieldDescription) {
JSONEditor.defaults.theme = 'bootstrap3';
JSONEditor.defaults.iconlib = 'fontawesome4';
var editorDiv = $('<div></div>');
const editorjq = editorDiv.jsoneditor({
schema: fieldDescription.schema,
ajax: true,
disable_edit_json: true,
disable_properties: true,
disable_array_add: true,
disable_array_delete: true,
disable_array_reorder: true
}).on('ready', () => {
var editor = editorjq.data('jsoneditor');
editor.setValue(value);
editor.disable();
editorDiv.find(".form-group").css("margin-right", "0").css("margin-left", "0");
});
return editorDiv;
}, function (fieldDescription, controller, updateValue, clone, scope) {
JSONEditor.defaults.theme = 'bootstrap3';
JSONEditor.defaults.iconlib = 'fontawesome4';
var editorDiv = $('<div style="padding:2px"></div>');
const editorjq = editorDiv.jsoneditor({
schema: fieldDescription.schema,
ajax: true,
}).on('ready', () => {
var editor = editorjq.data('jsoneditor');
if (controller.$viewValue)
editor.setValue(controller.$viewValue);
editorDiv.find(".form-group").css("margin-right", "0").css("margin-left", "0");
}).on('change', () => {
var editor = editorjq.data('jsoneditor');
var errors = editor.validate();
if (errors.length) {
console.log(errors);
editorDiv.css({ border: '2px dashed red' });
}
else {
editorDiv.css({ border: '' });
var newVal = editor.getValue();
controller.$setViewValue(newVal);
}
});
return editorDiv;
}]
}
}]);
fieldRenderingServiceProvider.defineLayoutRenderers(function () {
return {
H: function (params, children) {
var container = $('<div class="row"/>');
var fraction = Math.floor(12.0 / children.length);
$(children).each(function (index, item) {
var elem = $('<div class="col-md-' + fraction + '"/>');
elem.append(item());
container.append(elem);
});
return container;
},
V: function (params, children) {
var container = $('<div class="row"/>');
$(children).each(function (index, item) {
var elem = $('<div class="col-md-12"/>');
elem.append(item());
container.append(elem);
});
return container;
},
Tabs: function (params, children, childrenObjs) {
var container = $('<div/>');
var tabContainer = $('<ul class="nav nav-tabs"/>');
$(childrenObjs).each(function (index, item) {
var elem = $('<li class="' + (index == 0 ? 'active' : '') + '"><a href="#">' + item.params.title + '</a></li>'); //TODO javascript injection? //TODO id generation
elem.click(function () {
$('.tab-pane', container).removeClass('active');
$('li', container).removeClass('active');
elem.addClass('active');
$('#tab-' + index, container).addClass('active');
});
tabContainer.append(elem);
});
container.append(tabContainer);
var paneContainer = $('<div class="tab-content"/>');
$(children).each(function (index, item) {
var elem = $('<div class="tab-pane ' + (index == 0 ? 'active' : '') + '" id="tab-' + index + '"></div>'); //TODO javascript injection? //TODO id generation
elem.append(item());
paneContainer.append(elem);
});
container.append(paneContainer);
return container;
}
}
});
fieldRenderingServiceProvider.setFormStaticTemplate(["$compile", function ($compile) {
return function (value, fieldScope) {
var elem;
if (value instanceof jQuery) {
elem = $compile('<div class="form-control-static"></div>')(fieldScope);
elem.append(value);
} else {
fieldScope.renderedText = value || '';
elem = $compile('<div class="form-control-static">{{renderedText}}</div>')(fieldScope);
}
return elem;
}
}])
}]);
function uploadDirective(directiveName) {
return ["rest", "fieldRenderingService", "$parse", "messages", function (rest, fieldRenderingService, $parse, messages) {
return {
restrict: 'A',
templateUrl: '/assets/template/upload.html',
scope: true,
link: function (scope, element, attrs) {
var fieldValueGetter = $parse(attrs[directiveName]);
attrs.$observe('provider', function (provider) {
scope.options = {
url: ('/api/file/upload/' + provider) || '/api/file/upload',
autoUpload: true,
handleResponse: function (e, data) {
var files = data.result && data.result.files;
if (files) {
fieldValueGetter.assign(scope.$parent, files[0]);
data.scope.replace(data.files, files);
} else if (data.errorThrown ||
data.textStatus === 'error') {
data.files[0].error = data.errorThrown || data.textStatus;
}
}
};
});
scope.isNoFile = function (queue) {
return !fieldValueGetter(scope.$parent) && queue.length === 0;
};
scope.fileName = function (queue) {
return fieldValueGetter(scope.$parent) && fieldValueGetter(scope.$parent).name || queue.length > 0 && queue[queue.length - 1].name || undefined;
};
scope.isUploading = function (queue) {
return queue.length > 0 && queue[queue.length - 1].$state && queue[queue.length - 1].$state() === 'pending';
};
scope.hasFile = function () {
return !!fieldValueGetter(scope.$parent);
};
scope.removeFile = function () {
if (!scope.hasFile()) {
return;
}
//TODO REST remove unused file call
fieldValueGetter.assign(scope.$parent, undefined);
}
}
}
}];
}
allcountModule.directive("aUpload", uploadDirective("aUpload")); //TODO deprecated
allcountModule.directive("lcUpload", uploadDirective("lcUpload"));
allcountModule.directive("aField", fieldDirective("aField")); //TODO deprecated
function layoutDirective(directiveName) {
return ["rest", "fieldRenderingService", function (rest, fieldRenderingService) {
return {
restrict: 'A',
scope: false,
priority: 1000,
transclude: 'element',
link: function (scope, element, attrs, controller, transclude) {
var currentLayout;
var mainScope;
function allocateFieldScope(field, parentScope) {
var childScope = parentScope.$new();
childScope[attrs.field] = field;
return childScope;
}
function allocateScope(params, parentScope) {
var childScope = parentScope.$new();
_.extend(childScope, params);
return childScope;
}
function renderChild(layoutElem, parentScope) {
var containerId = layoutElem.containerId;
if (containerId == 'field') {
return transclude(allocateFieldScope(layoutElem.params.field, parentScope), function (clone) { //TODO: compact field format
return clone;
});
}
return fieldRenderingService.layoutRenderer(
containerId,
layoutElem.params,
$(layoutElem.children).map(function (index, item) {
return function () {
return renderChild(item, allocateScope(layoutElem.params, parentScope));
}
}),
layoutElem.children,
parentScope
);
}
scope.$watch(attrs[directiveName], function (entityTypeId) {
rest.layout(entityTypeId, function (layout) {
if (mainScope) {
mainScope.$destroy();
}
mainScope = scope.$new();
if (currentLayout) {
currentLayout.remove();
}
currentLayout = renderChild(layout, mainScope);
element.after(currentLayout);
})
});
scope.labelWidthClass = function (labelWidth) {
return 'col-md-' + (labelWidth || 3);
};
scope.fieldWidthClass = function (labelWidth) {
return 'col-md-' + (12 - (labelWidth || 3));
}
}
}
}];
}
allcountModule.directive("aLayout", layoutDirective("aLayout")); //TODO deprecated
allcountModule.directive("lcLayout", layoutDirective("lcLayout"));
allcountModule.directive("aGrid", listDirective('aGrid', '/assets/template/grid.html')); //TODO deprecated
allcountModule.directive("lcGrid", listDirective('lcGrid', '/assets/template/grid.html'));
function pagingDirective(directiveName) {
return ["rest", "$parse", function (rest, $parse) {
return {
restrict: 'A',
templateUrl: '/assets/template/paging.html',
scope: true,
link: function (scope, element, attrs) {
if (attrs.publishMethods) {
var publishMethodsTo = $parse(attrs.publishMethods);
publishMethodsTo.assign(scope.$parent, {
refresh: function () {
scope.refresh()
}
})
}
scope.filtering = {};
scope.$parent.$watch(attrs.filtering, function (filtering) {
scope.filtering = filtering;
if (scope.reload) scope.reload();
}, true);
scope.$parent.$watch(attrs[directiveName], function (entityTypeId) {
scope.pageSize = 50;
scope.numPages = 10;
var pagingAssign;
if (attrs.paging) pagingAssign = $parse(attrs.paging).assign;
scope.refreshCount = function (onSuccess) {
rest.findCount({ entityTypeId: entityTypeId }, scope.filtering, function (countAndTotalRow) {
scope.count = countAndTotalRow.count;
var setTotalRow = attrs.totalRow && $parse(attrs.totalRow).assign;
if (setTotalRow) {
setTotalRow(scope.$parent, countAndTotalRow.totalRow);
}
onSuccess();
});
};
scope.refresh = function () {
scope.refreshCount(function () {
var start = Math.max(0, Math.min(scope.currentPaging.start, scope.count - 1));
scope.currentPaging = {
start: start,
count: Math.min(scope.pageSize, scope.count - start)
};
})
};
scope.reload = function () {
scope.refreshCount(function () {
scope.currentPaging = {
start: 0,
count: Math.min(scope.pageSize, scope.count)
};
});
};
scope.reload();
scope.updatePaging = function (paging) {
scope.pages = [];
for (
var i = Math.max(paging.start - scope.numPages * scope.pageSize, 0);
i < Math.min(paging.start + scope.numPages * scope.pageSize, scope.count);
i += scope.pageSize
) {
scope.pages.push({ start: i, count: Math.min(scope.count - i, scope.pageSize) });
}
};
scope.nextPage = function () {
var nextStart = Math.min(scope.currentPaging.start + scope.pageSize, scope.count);
scope.currentPaging = {
start: nextStart,
count: Math.min(scope.count - nextStart, scope.pageSize)
}
};
scope.hasNextPage = function () {
return scope.currentPaging && scope.currentPaging.start + scope.pageSize < scope.count;
};
scope.prevPage = function () {
var nextStart = Math.max(scope.currentPaging.start - scope.pageSize, 0);
scope.currentPaging = {
start: nextStart,
count: Math.min(scope.count - nextStart, scope.pageSize)
}
};
scope.hasPrevPage = function () {
return scope.currentPaging && scope.currentPaging.start - scope.pageSize >= 0;
};
scope.setCurrentPage = function (page) {
scope.currentPaging = page;
};
scope.$watch('currentPaging', function (paging) {
if (pagingAssign) pagingAssign(scope.$parent, paging);
if (paging)
scope.updatePaging(paging);
}, true);
});
}
}
}];
}
allcountModule.directive("aPaging", pagingDirective("aPaging")); //TODO deprecated
allcountModule.directive("lcPaging", pagingDirective("lcPaging"));
allcountModule.directive("lcFormDefault", [function () {
return {
restrict: 'C',
scope: false,
templateUrl: '/assets/template/form-default.html',
transclude: false
}
}]);
allcountModule.directive("lcFormCreate", [function () {
return {
restrict: 'C',
scope: false,
templateUrl: '/assets/template/form-create.html',
transclude: false
}
}]);
allcountModule.directive("aMessage", messageDirective("aMessage")); //TODO deprecated
allcountModule.directive("aMenu", menuDirective()); //TODO deprecated
allcountModule.directive("lcActions", ["rest", "messages", "$parse", "$modal", function (rest, messages, $parse, $modal) {
return {
restrict: 'A',
scope: true,
priority: 1100,
link: function (scope, element, attrs) {
scope.$parent.$watch(attrs.lcActions, function (entityTypeOrCrudId) {
scope.entityCrudId = toEntityCrudId(entityTypeOrCrudId);
refresh();
});
scope.$parent.$watch(attrs.actionTarget, function (actionTarget) {
scope.actionTarget = actionTarget;
refresh();
});
scope.selectedItems = [];
attrs.selectedItems && scope.$parent.$watch(attrs.selectedItems, function (selectedItems) {
scope.selectedItems = selectedItems;
refresh();
}, true);
refresh();
function refresh() {
if (!scope.entityCrudId || !scope.actionTarget) {
scope.actions = [];
} else {
var entityCrudId = scope.entityCrudId;
rest.actions(scope.entityCrudId, scope.actionTarget, scope.selectedItems).then(function (actions) {
scope.actions = _.map(actions, function (action) {
action.perform = function () {
action.isPerforming = true;
rest.performAction(entityCrudId, action.id, scope.selectedItems).then(function (actionResult) {
action.isPerforming = false;
if (actionResult.type === 'redirect') {
if (actionResult.newWindow && actionResult.newWindow === true) {
window.open(actionResult.url,'_blank');
}
else {
window.location = actionResult.url;
}
} else if (actionResult.type === 'refresh') {
if (attrs.onRefresh) {
scope.$eval(attrs.onRefresh);
} else {
throw new Error('on-refresh is not defined for lc-actions');
}
} else if (actionResult.type === 'modal') {
var modalScope = scope.$new();
modalScope.title = actionResult.title;
modalScope.message = actionResult.message;
$modal.open({
templateUrl: '/assets/template/modal.html',
scope: modalScope
});
if (attrs.onRefresh) {
scope.$eval(attrs.onRefresh);
} else {
throw new Error('on-refresh is not defined for lc-actions');
}
} else {
throw new Error('Unknown actionResult type "' + actionResult.type + '" for ' + JSON.stringify(actionResult));
}
}, function () {
action.isPerforming = false;
refresh();
});
};
action.name = messages(action.name);
return action;
});
});
}
}
if (attrs.publishMethods) {
var publishMethodsTo = $parse(attrs.publishMethods);
publishMethodsTo.assign(scope.$parent, {
refresh: refresh
})
}
}
}
}]);
allcountModule.directive("lcReference", ["rest", "messages", function (rest, messages) {
return {
restrict: 'A',
templateUrl: '/assets/template/reference.html',
scope: true,
require: 'ngModel',
link: function (scope, element, attrs, controller) {
scope.referenceViewState = {};
scope.entityTypeId = null;
scope.$parent.$watch(attrs.lcReference, function (entityTypeId) {
if (!entityTypeId) {
return;
}
scope.entityTypeId = entityTypeId;
var elem = $('.reference-input', element);
var isMultiple = attrs.isMultiple && scope.$eval(attrs.isMultiple);
var viewValueAndValEquals = function (element) {
if (!element.val()) {
return !controller.$viewValue;
}
return angular.equals(element.val().split(','), controller.$viewValue && _.map(controller.$viewValue, _.property('id')));
};
elem.select2({
ajax: {
url: "/api/entity/" + entityTypeId + '/reference-values',
dataType: 'json',
delay: 250,
data: function (term) {
return {
query: term
};
},
results: function (data, page) {
// parse the results into the format expected by Select2.
// since we are using custom formatting functions we do not need to
// alter the remote JSON data
return { results: data };
},
cache: true
},
tags: isMultiple,
text: function (item) {
return item && item.name;
},
initSelection: function (element, callback) {
if (isMultiple) {
if (element.val() && viewValueAndValEquals(element)) {
callback(controller.$viewValue);
}
} else {
if (element.val() === (controller.$viewValue && controller.$viewValue.id)) {
callback(controller.$viewValue);
}
}
}
});
function onChange() {
if (isMultiple) {
if (!viewValueAndValEquals(elem)) {
controller.$setViewValue(elem.val() && elem.select2('data') || null);
}
} else {
controller.$setViewValue(elem.val() && (controller.$viewValue && controller.$viewValue.id === elem.val() ? controller.$viewValue : elem.select2('data')) || null);
}
}
function phaseWrapper(func) {
return function () {
if (!scope.$$phase) {
scope.$apply(func);
} else {
func();
}
}
}
elem.on('change', phaseWrapper(onChange));
controller.$render = function () {
elem.select2('data', controller.$viewValue);
};
controller.$render();
function setValue(value) {
controller.$setViewValue(value);
controller.$render();
}
scope.clear = function () {
setValue(null);
};
scope.referenceViewState.onCreate = function () {
scope.referenceViewState.editForm.createEntity(function (entityId) { //TODO
rest.referenceValueByEntityId(entityTypeId, entityId).then(function (referenceValue) {
if (isMultiple) {
var v = _.clone(controller.$viewValue);
v.push(referenceValue);
setValue(v);
} else {
setValue(referenceValue);
}
});
scope.referenceViewState.isCreateModalShowing = false;
})
};
scope.createNewReferenceItem = function () {
scope.referenceViewState.isCreateModalShowing = true;
}
});
}
}
}]);
allcountModule.directive("lcModal", ["$parse", function ($parse) {
return {
restrict: 'A',
scope: true,
transclude: 'element',
link: function (scope, element, attrs, ctrl, transclude) {
transclude(scope, function (elem) {
var $element = $(elem);
var modal = $element.modal({ show: false });
scope.show = false;
var assignIsShowing = $parse(attrs.lcModal).assign;
scope.$parent.$watch(attrs.lcModal, function (show) {
if (scope.show !== !!show) {
scope.show = !!show;
if (scope.show) {
modal.modal('show');
} else {
modal.modal('hide');
}
}
}, true);
function fireIsShowing(isShowing) {
scope.show = isShowing;
var assign = function () {
assignIsShowing(scope.$parent, isShowing);
};
if (!scope.$$phase) {
scope.$apply(assign);
} else {
assign();
}
}
modal.on('show.bs.modal', function () { fireIsShowing(true) });
modal.on('hide.bs.modal', function () { fireIsShowing(false) });
})
}
}
}]);
allcountModule.directive("lcTooltip", ["$parse", "messages", function ($parse, messages) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
function isTouchDevice() {
return true == ("ontouchstart" in window || window.DocumentTouch && document instanceof DocumentTouch);
}
if (!isTouchDevice()) {
messages.messagePromise(attrs.lcTooltip).then(function (msg) {
$(element).tooltip({
placement: 'bottom',
title: msg
});
});
}
}
}
}]);
function toEntityCrudId(id) {
if (angular.isString(id)) {
return { entityTypeId: id };
} else {
return id;
}
}