Forked from
clients / Cesium-grp / Cesium
348 commits behind the upstream repository.
-
Benoit Lavenier authoredBenoit Lavenier authored
directives.js 15.17 KiB
angular.module('cesium.directives', [])
// Add new compare-to directive (need for form validation)
.directive("compareTo", function() {
return {
require: "?ngModel",
link: function(scope, element, attributes, ngModel) {
if (ngModel && attributes.compareTo) {
ngModel.$validators.compareTo = function(modelValue) {
return modelValue == scope.$eval(attributes.compareTo);
};
scope.$watch(attributes.compareTo, function() {
ngModel.$validate();
});
}
}
};
})
// Add new different-to directive (need for form validation)
.directive("differentTo", function() {
return {
require: "?ngModel",
link: function(scope, element, attributes, ngModel) {
if (ngModel && attributes.differentTo) {
ngModel.$validators.differentTo = function(modelValue) {
return modelValue != scope.$eval(attributes.differentTo);
};
scope.$watch(attributes.differentTo, function() {
ngModel.$validate();
});
}
}
};
})
.directive('numberFloat', function() {
var NUMBER_REGEXP = new RegExp('^[0-9]+([.,][0-9]+)?$');
return {
require: '?ngModel',
link: function(scope, element, attributes, ngModel) {
if (ngModel) {
ngModel.$validators.numberFloat = function(value) {
return ngModel.$isEmpty(value) || NUMBER_REGEXP.test(value);
};
}
}
};
})
.directive('numberInt', function() {
var INT_REGEXP = new RegExp('^[0-9]+$');
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
if (ngModel) {
ngModel.$validators.numberInt = function (value) {
return ngModel.$isEmpty(value) || INT_REGEXP.test(value);
};
}
}
};
})
.directive('email', function() {
var EMAIL_REGEXP = new RegExp('^[a-z0-9!#$%&\'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&\'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$');
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
if (ngModel) {
ngModel.$validators.email = function (value) {
return ngModel.$isEmpty(value) || EMAIL_REGEXP.test(value);
};
}
}
};
})
.directive('requiredIf', function() {
return {
require: '?ngModel',
link: function(scope, element, attributes, ngModel) {
if (ngModel && attributes.requiredIf) {
ngModel.$validators.required = function(value) {
return !(scope.$eval(attributes.requiredIf)) || !ngModel.$isEmpty(value);
};
scope.$watch(attributes.requiredIf, function() {
ngModel.$validate();
});
}
}
};
})
.directive('geoPoint', function() {
return {
require: '?ngModel',
link: function(scope, element, attributes, ngModel) {
if (ngModel) {
ngModel.$validators.geoPoint = function(value) {
return ngModel.$isEmpty(value) ||
// twice are defined
(angular.isDefined(value.lat) && angular.isDefined(value.lon)) ||
// or twice are NOT defined (=empty object - can be useful to override data in ES node)
(angular.isUndefined(value.lat) && angular.isUndefined(value.lon));
};
}
}
};
})
// Add a copy-on-click directive
.directive('copyOnClick', function ($window, Device, UIUtils) {
'ngInject';
return {
restrict: 'A',
link: function (scope, element, attrs) {
var showCopyPopover = function (event) {
var value = attrs.copyOnClick;
if (value === undefined || value === null) return; // Skip if no value
if (Device.clipboard.enable) {
// copy to clipboard, using cordova
Device.clipboard.copy(value)
.then(function(){
UIUtils.toast.show('INFO.COPY_TO_CLIPBOARD_DONE');
})
.catch(UIUtils.onError('ERROR.COPY_CLIPBOARD'));
}
else {
var rows = value && value.indexOf('\n') >= 0 ? value.split('\n').length : 1;
UIUtils.popover.show(event, {
scope: scope,
templateUrl: 'templates/common/popover_copy.html',
bindings: {
value: attrs.copyOnClick,
rows: rows,
copied: false
},
autoselect: '.popover-copy ' + (rows <= 1 ? 'input' : 'textarea'),
// After popover, try to copy the selection
afterShow: document.execCommand ? function(popover) {
try {
document.execCommand("copy");
UIUtils.toast.show('INFO.COPY_TO_CLIPBOARD_DONE', 1000);
} catch (err) {
console.error("[copy-on-click] Failed to copy using document.execCommand('copy')", err);
}
} : undefined
});
}
};
element.bind('click', showCopyPopover);
element.bind('hold', showCopyPopover);
}
};
})
// Add a select-on-click directive
.directive('selectOnClick', function ($window) {
'ngInject';
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.bind('click', function () {
if ($window.getSelection && !$window.getSelection().toString() && this.value) {
this.setSelectionRange(0, this.value.length);
}
});
}
};
})
.directive('activeLink', function ($location) {
'ngInject';
return {
restrict: 'A',
link: function(scope, element, attrs, controller) {
var clazz = attrs.activeLink;
var path;
if (attrs.activeLinkPathPrefix) {
path = attrs.activeLinkPathPrefix.substring(1); //hack because path does not return including hashbang
scope.location = $location;
scope.$watch('location.path()', function (newPath) {
if (newPath && newPath.indexOf(path) === 0) {
element.addClass(clazz);
} else {
element.removeClass(clazz);
}
});
}
else if (attrs.href) {
path = attrs.href.substring(1); //hack because path does not return including hashbang
scope.location = $location;
scope.$watch('location.path()', function (newPath) {
if (newPath && newPath == path) {
element.addClass(clazz);
} else {
element.removeClass(clazz);
}
});
}
}
};
})
// All this does is allow the message
// to be sent when you tap return
.directive('input', function($timeout) {
return {
restrict: 'E',
scope: {
'returnClose': '=',
'onReturn': '&',
'onFocus': '&',
'onBlur': '&'
},
link: function(scope, element, attr) {
element.bind('focus', function(e) {
if (scope.onFocus) {
$timeout(function() {
scope.onFocus();
});
}
});
element.bind('blur', function(e) {
if (scope.onBlur) {
$timeout(function() {
scope.onBlur();
});
}
});
element.bind('keydown', function(e) {
if (e.which == 13) {
if (scope.returnClose) element[0].blur();
if (scope.onReturn) {
$timeout(function() {
scope.onReturn();
});
}
}
});
}
};
})
.directive('trustAsHtml', ['$sce', '$compile', '$parse', function($sce, $compile, $parse){
return {
restrict: 'A',
compile: function (tElement, tAttrs) {
var ngBindHtmlGetter = $parse(tAttrs.trustAsHtml);
var ngBindHtmlWatch = $parse(tAttrs.trustAsHtml, function getStringValue(value) {
return (value || '').toString();
});
$compile.$$addBindingClass(tElement);
return function ngBindHtmlLink(scope, element, attr) {
$compile.$$addBindingInfo(element, attr.trustAsHtml);
scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
// we re-evaluate the expr because we want a TrustedValueHolderType
// for $sce, not a string
element.html($sce.getTrustedHtml($sce.trustAsHtml(ngBindHtmlGetter(scope))) || '');
$compile(element.contents())(scope);
});
};
}
};
}])
/**
* Close the current modal
*/
.directive('modalClose', ['$ionicHistory', '$timeout', function($ionicHistory, $timeout) {
return {
restrict: 'AC',
link: function($scope, $element) {
$element.bind('click', function() {
if ($scope.closeModal) {
$ionicHistory.nextViewOptions({
historyRoot: true,
disableAnimate: true,
expire: 300
});
// if no transition in 300ms, reset nextViewOptions
// the expire should take care of it, but will be cancelled in some
// cases. This directive is an exception to the rules of history.js
$timeout( function() {
$ionicHistory.nextViewOptions({
historyRoot: false,
disableAnimate: false
});
}, 300);
$scope.closeModal();
}
});
}
};
}])
/**
* Plugin extension point (see services/plugin-services.js)
*/
.directive('csExtensionPoint', function ($state, $compile, $controller, $templateCache, PluginService) {
var getTemplate = function(extensionPoint) {
var template = extensionPoint.templateUrl ? $templateCache.get(extensionPoint.templateUrl) : extensionPoint.template;
if (!template) {
console.error('[plugin] Could not found template for extension :' + (extensionPoint.templateUrl ? extensionPoint.templateUrl : extensionPoint.template));
return '';
}
if (extensionPoint.controller) {
template = '<ng-controller ng-controller="'+extensionPoint.controller+'">' + template + '</div>';
}
return template;
};
var compiler = function(tElement, tAttributes) {
if (angular.isDefined(tAttributes.name)) {
var extensionPoints = PluginService.extensions.points.getActivesByName(tAttributes.name);
if (extensionPoints.length > 0) {
tElement.html("");
_.forEach(extensionPoints, function(extensionPoint){
tElement.append(getTemplate(extensionPoint));
});
}
}
return {
pre: function(scope, iElement, iAttrs){
PluginService.extensions.points.current.set(iAttrs.name);
},
post: function(){
PluginService.extensions.points.current.set();
}
};
};
return {
restrict: "E",
compile: compiler,
scope: {
content:'='
}
};
})
.directive('onReadFile', function ($parse) {
return {
restrict: 'A',
scope: false,
link: function(scope, element, attrs) {
var fn = $parse(attrs.onReadFile);
element.on('change', function(onChangeEvent) {
var reader = new FileReader();
var fileData = {
name: this.files[0].name,
size: this.files[0].size,
type: this.files[0].type
};
reader.onload = function(onLoadEvent) {
scope.$applyAsync(function() {
fn(scope, {
file: {
fileContent: onLoadEvent.target.result,
fileData : fileData}
});
});
};
reader.readAsText((onChangeEvent.srcElement || onChangeEvent.target).files[0]);
});
}
};
})
.directive("dropZone", function($parse) {
return {
restrict: 'A',
scope: false,
link: function(scope, elem, attrs) {
var fn = $parse(attrs.dropZone);
elem.bind('dragover', function (e) {
e.stopPropagation();
e.preventDefault();
});
elem.bind('dragenter', function(e) {
e.stopPropagation();
e.preventDefault();
});
elem.bind('dragleave', function(e) {
e.stopPropagation();
e.preventDefault();
});
elem.bind('drop', function(e) {
e.stopPropagation();
e.preventDefault();
var file = e.dataTransfer.files[0];
var fileData = {
name: file.name,
size: file.size,
type: file.type
};
var reader = new FileReader();
reader.onload = function(onLoadEvent) {
scope.$apply(function () {
fn(scope, {
file: {
file: file,
fileContent: onLoadEvent.target.result,
fileData : fileData}
});
});
};
reader.readAsText(e.dataTransfer.files[0]);
});
}
};
})
// See http://embed.plnkr.co/2vgnFe/
.directive('fileSelect', function ($parse) {
'use strict';
return {
restrict: 'A',
scope: false,
template: '<input type="file" style="display: none;" />' +
'<ng-transclude></ng-transclude>',
transclude: true,
link: function (scope, element, attrs) {
var fn = $parse(attrs.fileSelect);
var fileInput = element.children('input[file]');
if (attrs.accept) {
fileInput[0].accept = attrs.accept;
}
fileInput.on('change', function (onChangeEvent) {
var reader = new FileReader();
var file = this.files[0];
var fileData = {
name: file.name,
size: file.size,
type: file.type
};
reader.onload = function(onLoadEvent) {
scope.$applyAsync(function() {
fn(scope, {
file: {
file: file,
fileContent: onLoadEvent.target.result,
fileData : fileData}
});
// Reset the input file
fileInput[0].value = '';
});
};
reader.readAsText((onChangeEvent.srcElement || onChangeEvent.target).files[0]);
});
element.on('click', function () {
fileInput[0].click();
});
}
};
})
// Un-authenticate when window closed
// see: https://stackoverflow.com/questions/28197316/javascript-or-angularjs-defer-browser-close-or-tab-close-between-refresh
.directive('windowExitUnauth', function($window, csSettings, csWallet) {
return {
restrict: 'AE',
link: function(element, attrs){
var myEvent = $window.attachEvent || $window.addEventListener,
chkevent = $window.attachEvent ? 'onunload' : 'unload'; /// make IE7, IE8 compatible
myEvent(chkevent, function (e) { // For >=IE7, Chrome, Firefox
if (csSettings.data && csSettings.data.keepAuthIdle != csSettings.constants.KEEP_AUTH_IDLE_SESSION) {
return csWallet.unauth();
}
});
}
};
});