diff --git a/app/assets/javascripts/directives/functional/autofocus.js b/app/assets/javascripts/directives/functional/autofocus.js deleted file mode 100644 index 46fc64ec1..000000000 --- a/app/assets/javascripts/directives/functional/autofocus.js +++ /dev/null @@ -1,16 +0,0 @@ -/* @ngInject */ -export function autofocus($timeout) { - return { - restrict: 'A', - scope: { - shouldFocus: '=' - }, - link: function($scope, $element) { - $timeout(function() { - if ($scope.shouldFocus) { - $element[0].focus(); - } - }); - } - }; -} diff --git a/app/assets/javascripts/directives/functional/autofocus.ts b/app/assets/javascripts/directives/functional/autofocus.ts new file mode 100644 index 000000000..a2173fc0d --- /dev/null +++ b/app/assets/javascripts/directives/functional/autofocus.ts @@ -0,0 +1,19 @@ +/* @ngInject */ +export function autofocus($timeout: ng.ITimeoutService) { + return { + restrict: 'A', + scope: { + shouldFocus: '=' + }, + link: function ( + $scope: ng.IScope, + $element: JQLite + ) { + $timeout(() => { + if (($scope as any).shouldFocus) { + $element[0].focus(); + } + }); + } + }; +} diff --git a/app/assets/javascripts/directives/functional/click-outside.js b/app/assets/javascripts/directives/functional/click-outside.ts similarity index 89% rename from app/assets/javascripts/directives/functional/click-outside.js rename to app/assets/javascripts/directives/functional/click-outside.ts index 15342c2bb..4f7d2e2c8 100644 --- a/app/assets/javascripts/directives/functional/click-outside.js +++ b/app/assets/javascripts/directives/functional/click-outside.ts @@ -1,9 +1,9 @@ /* @ngInject */ -export function clickOutside($document) { +export function clickOutside($document: ng.IDocumentService) { return { restrict: 'A', replace: false, - link: function ($scope, $element, attrs) { + link: function ($scope: ng.IScope, $element: JQLite, attrs: any) { // Causes memory leak as-is: // let didApplyClickOutside = false; diff --git a/app/assets/javascripts/directives/functional/delay-hide.js b/app/assets/javascripts/directives/functional/delay-hide.js deleted file mode 100644 index e03b54580..000000000 --- a/app/assets/javascripts/directives/functional/delay-hide.js +++ /dev/null @@ -1,44 +0,0 @@ -import angular from 'angular'; - -/* @ngInject */ -export function delayHide($timeout) { - return { - restrict: 'A', - scope: { - show: '=', - delay: '@' - }, - link: function(scope, elem, attrs) { - showElement(false); - - // This is where all the magic happens! - // Whenever the scope variable updates we simply - // show if it evaluates to 'true' and hide if 'false' - scope.$watch('show', function(newVal) { - newVal ? showSpinner() : hideSpinner(); - }); - - function showSpinner() { - if (scope.hidePromise) { - $timeout.cancel(scope.hidePromise); - scope.hidePromise = null; - } - showElement(true); - } - - function hideSpinner() { - scope.hidePromise = $timeout(showElement.bind(this, false), getDelay()); - } - - function showElement(show) { - show ? elem.css({ display: '' }) : elem.css({ display: 'none' }); - } - - function getDelay() { - var delay = parseInt(scope.delay); - - return angular.isNumber(delay) ? delay : 200; - } - } - }; -} diff --git a/app/assets/javascripts/directives/functional/delay-hide.ts b/app/assets/javascripts/directives/functional/delay-hide.ts new file mode 100644 index 000000000..8625c4c21 --- /dev/null +++ b/app/assets/javascripts/directives/functional/delay-hide.ts @@ -0,0 +1,45 @@ +import angular from 'angular'; + +/* @ngInject */ +export function delayHide($timeout: ng.ITimeoutService) { + return { + restrict: 'A', + scope: { + show: '=', + delay: '@' + }, + link: function (scope: ng.IScope, elem: JQLite) { + const scopeAny = scope as any; + const showSpinner = () => { + if (scopeAny.hidePromise) { + $timeout.cancel(scopeAny.hidePromise); + scopeAny.hidePromise = null; + } + showElement(true); + } + + const hideSpinner = () => { + scopeAny.hidePromise = $timeout( + showElement.bind(this as any, false), + getDelay() + ); + } + + const showElement = (show: boolean) => { + show ? elem.css({ display: '' }) : elem.css({ display: 'none' }); + } + + const getDelay = () => { + const delay = parseInt(scopeAny.delay); + return angular.isNumber(delay) ? delay : 200; + } + + showElement(false); + // Whenever the scope variable updates we simply + // show if it evaluates to 'true' and hide if 'false' + scope.$watch('show', function (newVal) { + newVal ? showSpinner() : hideSpinner(); + }); + } + }; +} diff --git a/app/assets/javascripts/directives/functional/elemReady.js b/app/assets/javascripts/directives/functional/elemReady.ts similarity index 64% rename from app/assets/javascripts/directives/functional/elemReady.js rename to app/assets/javascripts/directives/functional/elemReady.ts index 1b7809406..2387f0083 100644 --- a/app/assets/javascripts/directives/functional/elemReady.js +++ b/app/assets/javascripts/directives/functional/elemReady.ts @@ -1,8 +1,8 @@ /* @ngInject */ -export function elemReady($parse) { +export function elemReady($parse: ng.IParseService) { return { restrict: 'A', - link: function($scope, elem, attrs) { + link: function($scope: ng.IScope, elem: JQLite, attrs: any) { elem.ready(function() { $scope.$apply(function() { var func = $parse(attrs.elemReady); diff --git a/app/assets/javascripts/directives/functional/file-change.js b/app/assets/javascripts/directives/functional/file-change.js deleted file mode 100644 index 1cd82d284..000000000 --- a/app/assets/javascripts/directives/functional/file-change.js +++ /dev/null @@ -1,16 +0,0 @@ -/* @ngInject */ -export function fileChange() { - return { - restrict: 'A', - scope: { - handler: '&' - }, - link: function(scope, element) { - element.on('change', function(event) { - scope.$apply(function() { - scope.handler({ files: event.target.files }); - }); - }); - } - }; -} diff --git a/app/assets/javascripts/directives/functional/file-change.ts b/app/assets/javascripts/directives/functional/file-change.ts new file mode 100644 index 000000000..3f29bee6e --- /dev/null +++ b/app/assets/javascripts/directives/functional/file-change.ts @@ -0,0 +1,19 @@ +/* @ngInject */ +export function fileChange() { + return { + restrict: 'A', + scope: { + handler: '&' + }, + link: function (scope: ng.IScope, element: JQLite) { + element.on('change', (event) => { + scope.$apply(() => { + const files = (event.target as HTMLInputElement).files; + (scope as any).handler({ + files: files + }); + }); + }); + } + }; +} diff --git a/app/assets/javascripts/directives/functional/index.js b/app/assets/javascripts/directives/functional/index.ts similarity index 100% rename from app/assets/javascripts/directives/functional/index.js rename to app/assets/javascripts/directives/functional/index.ts diff --git a/app/assets/javascripts/directives/functional/infiniteScroll.js b/app/assets/javascripts/directives/functional/infiniteScroll.ts similarity index 63% rename from app/assets/javascripts/directives/functional/infiniteScroll.js rename to app/assets/javascripts/directives/functional/infiniteScroll.ts index d1057d842..e7aa91b50 100644 --- a/app/assets/javascripts/directives/functional/infiniteScroll.js +++ b/app/assets/javascripts/directives/functional/infiniteScroll.ts @@ -1,10 +1,11 @@ /* @ngInject */ export function infiniteScroll() { return { - link: function(scope, elem, attrs) { + link: function (scope: ng.IScope, elem: JQLite, attrs: any) { + const scopeAny = scope as any; const offset = parseInt(attrs.threshold) || 0; const e = elem[0]; - scope.onScroll = () => { + scopeAny.onScroll = () => { if ( scope.$eval(attrs.canLoad) && e.scrollTop + e.offsetHeight >= e.scrollHeight - offset @@ -12,9 +13,9 @@ export function infiniteScroll() { scope.$apply(attrs.infiniteScroll); } }; - elem.on('scroll', scope.onScroll); + elem.on('scroll', scopeAny.onScroll); scope.$on('$destroy', () => { - elem.off('scroll', scope.onScroll);; + elem.off('scroll', scopeAny.onScroll);; }); } }; diff --git a/app/assets/javascripts/directives/functional/lowercase.js b/app/assets/javascripts/directives/functional/lowercase.js deleted file mode 100644 index e4f7f9781..000000000 --- a/app/assets/javascripts/directives/functional/lowercase.js +++ /dev/null @@ -1,19 +0,0 @@ -/* @ngInject */ -export function lowercase() { - return { - require: 'ngModel', - link: function(scope, element, attrs, modelCtrl) { - var lowercase = function(inputValue) { - if (inputValue === undefined) inputValue = ''; - var lowercased = inputValue.toLowerCase(); - if (lowercased !== inputValue) { - modelCtrl.$setViewValue(lowercased); - modelCtrl.$render(); - } - return lowercased; - }; - modelCtrl.$parsers.push(lowercase); - lowercase(scope[attrs.ngModel]); - } - }; -} diff --git a/app/assets/javascripts/directives/functional/lowercase.ts b/app/assets/javascripts/directives/functional/lowercase.ts new file mode 100644 index 000000000..95b0a27a1 --- /dev/null +++ b/app/assets/javascripts/directives/functional/lowercase.ts @@ -0,0 +1,24 @@ +/* @ngInject */ +export function lowercase() { + return { + require: 'ngModel', + link: function ( + scope: ng.IScope, + _: JQLite, + attrs: any, + ctrl: ng.IController + ) { + const lowercase = (inputValue: string) => { + if (inputValue === undefined) inputValue = ''; + const lowercased = inputValue.toLowerCase(); + if (lowercased !== inputValue) { + ctrl.$setViewValue(lowercased); + ctrl.$render(); + } + return lowercased; + }; + ctrl.$parsers.push(lowercase); + lowercase((scope as any)[attrs.ngModel]); + } + }; +} diff --git a/app/assets/javascripts/directives/functional/selectOnClick.js b/app/assets/javascripts/directives/functional/selectOnClick.js deleted file mode 100644 index b657ba422..000000000 --- a/app/assets/javascripts/directives/functional/selectOnClick.js +++ /dev/null @@ -1,14 +0,0 @@ -/* @ngInject */ -export function selectOnClick($window) { - return { - restrict: 'A', - link: function(scope, element, attrs) { - element.on('focus', function() { - if (!$window.getSelection().toString()) { - /** Required for mobile Safari */ - this.setSelectionRange(0, this.value.length); - } - }); - } - }; -} diff --git a/app/assets/javascripts/directives/functional/selectOnClick.ts b/app/assets/javascripts/directives/functional/selectOnClick.ts new file mode 100644 index 000000000..25df0da1f --- /dev/null +++ b/app/assets/javascripts/directives/functional/selectOnClick.ts @@ -0,0 +1,15 @@ +/* @ngInject */ +export function selectOnClick($window: ng.IWindowService) { + return { + restrict: 'A', + link: function(scope: ng.IScope, element: JQLite) { + element.on('focus', function() { + if (!$window.getSelection()!.toString()) { + const input = element as any; + /** Required for mobile Safari */ + input.setSelectionRange(0, input.value.length); + } + }); + } + }; +} diff --git a/app/assets/javascripts/directives/functional/snEnter.js b/app/assets/javascripts/directives/functional/snEnter.ts similarity index 53% rename from app/assets/javascripts/directives/functional/snEnter.js rename to app/assets/javascripts/directives/functional/snEnter.ts index de91a89b1..5dd934756 100644 --- a/app/assets/javascripts/directives/functional/snEnter.js +++ b/app/assets/javascripts/directives/functional/snEnter.ts @@ -1,9 +1,13 @@ /* @ngInject */ export function snEnter() { - return function(scope, element, attrs) { - element.bind('keydown keypress', function(event) { + return function ( + scope: ng.IScope, + element: JQLite, + attrs: any + ) { + element.bind('keydown keypress', function (event) { if (event.which === 13) { - scope.$apply(function() { + scope.$apply(function () { scope.$eval(attrs.snEnter, { event: event }); });