diff --git a/services/web/app/views/_mixins/faq_search.pug b/services/web/app/views/_mixins/faq_search.pug
deleted file mode 100644
index ca51cb29c2..0000000000
--- a/services/web/app/views/_mixins/faq_search.pug
+++ /dev/null
@@ -1,32 +0,0 @@
-mixin faq_search(headerText, headerClass)
- if (typeof(settings.algolia) != "undefined" && typeof(settings.algolia.indexes) != "undefined" && typeof(settings.algolia.indexes.wiki) != "undefined")
- if headerText
- div(class=headerClass, ng-non-bindable) #{headerText}
- .wiki(ng-controller="SearchWikiController")
- form.project-search.form-horizontal(role="search")
- .form-group.has-feedback.has-feedback-left
- .col-sm-12
- input.form-control(type='text', ng-model='searchQueryText', ng-keyup='search()', placeholder="Search help library…")
- i.fa.fa-search.form-control-feedback-left(aria-hidden="true")
- i.fa.fa-times.form-control-feedback(
- ng-click="clearSearchText()",
- style="cursor: pointer;",
- ng-show="searchQueryText.length > 0"
- aria-hidden="true"
- )
- button.sr-only(
- type="button"
- ng-click="clearSearchText()",
- ng-show="searchQueryText.length > 0"
- ) #{translate('clear_search')}
-
- .row(role="region" aria-label="search results")
- .col-md-12(ng-cloak)
- span.sr-only(ng-show="searchQueryText.length > 0" aria-live="polite")
- span(ng-if="hits_total > config_hits_per_page") Showing first {{hits.length}} results of {{hits_total}} for {{searchQueryText}}
- span(ng-if="hits_total <= config_hits_per_page") {{hits.length}} results for {{searchQueryText}}
- a(ng-href='{{hit.url}}',ng-repeat='hit in hits').search-result.card.card-thin
- span(ng-bind-html='hit.name')
- div.search-result-content(ng-show="hit.content != ''", ng-bind-html='hit.content')
- .row-spaced-small.search-result.card.card-thin(ng-if="!processingSearch && searchQueryText.length > 1 && hits.length === 0")
- p #{translate("no_search_results")}
diff --git a/services/web/app/views/project/importing.pug b/services/web/app/views/project/importing.pug
deleted file mode 100644
index bd8e12e349..0000000000
--- a/services/web/app/views/project/importing.pug
+++ /dev/null
@@ -1,21 +0,0 @@
-extends ../layout
-
-block vars
- - var suppressNavbar = true
- - var suppressFooter = true
- - var suppressSkipToContent = true
- - var suppressCookieBanner = true
- - metadata.robotsNoindexNofollow = true
-
-block content
- .editor(ng-controller="ImportingController").full-size
- .loading-screen
- .loading-screen-brand-container
- .loading-screen-brand(
- style="height: 20%;"
- ng-style="{ 'height': state.load_progress + '%' }"
- )
- h3.loading-screen-label #{translate("importing")}
- span.loading-screen-ellip .
- span.loading-screen-ellip .
- span.loading-screen-ellip .
diff --git a/services/web/frontend/js/directives/asyncForm.js b/services/web/frontend/js/directives/asyncForm.js
deleted file mode 100644
index fb5c899987..0000000000
--- a/services/web/frontend/js/directives/asyncForm.js
+++ /dev/null
@@ -1,192 +0,0 @@
-import App from '../base'
-App.directive('asyncForm', [
- '$http',
- 'validateCaptcha',
- 'validateCaptchaV3',
- function ($http, validateCaptcha, validateCaptchaV3) {
- return {
- controller: [
- '$scope',
- '$location',
- function ($scope, $location) {
- this.getEmail = () => $scope.email
- this.getEmailFromQuery = () =>
- $location.search().email || $location.search().new_email
- return this
- },
- ],
- link(scope, element, attrs, ctrl) {
- let response
- const formName = attrs.asyncForm
-
- scope[attrs.name].response = response = {}
- scope[attrs.name].inflight = false
- scope.email =
- scope.email ||
- scope.usersEmail ||
- ctrl.getEmailFromQuery() ||
- attrs.newEmail
-
- const validateCaptchaIfEnabled = function (callback) {
- scope.$applyAsync(() => {
- scope[attrs.name].inflight = true
- })
-
- if (attrs.captchaActionName) {
- validateCaptchaV3(attrs.captchaActionName)
- }
- if (attrs.captcha != null) {
- validateCaptcha(callback)
- } else {
- callback()
- }
- }
-
- const _submitRequest = function (grecaptchaResponse) {
- const formData = {}
- for (const data of Array.from(element.serializeArray())) {
- formData[data.name] = data.value
- }
-
- if (grecaptchaResponse) {
- formData['g-recaptcha-response'] = grecaptchaResponse
- }
-
- // clear the response object which may be referenced downstream
- Object.keys(response).forEach(field => delete response[field])
-
- // for asyncForm prevent automatic redirect to /login if
- // authentication fails, we will handle it ourselves
- const httpRequestFn = _httpRequestFn(element.attr('method'))
- return httpRequestFn(element.attr('action'), formData, {
- disableAutoLoginRedirect: true,
- })
- .then(function (httpResponse) {
- const { data, headers } = httpResponse
- scope[attrs.name].inflight = false
- response.success = true
- response.error = false
-
- const onSuccessHandler = scope[attrs.onSuccess]
- if (onSuccessHandler) {
- onSuccessHandler(httpResponse)
- return
- }
-
- if (data.redir) {
- ga('send', 'event', formName, 'success')
- return (window.location = data.redir)
- } else if (data.message) {
- response.message = data.message
-
- if (data.message.type === 'error') {
- response.success = false
- response.error = true
- return ga('send', 'event', formName, 'failure', data.message)
- } else {
- return ga('send', 'event', formName, 'success')
- }
- } else if (scope.$eval(attrs.asyncFormDownloadResponse)) {
- const blob = new Blob([data], {
- type: headers('Content-Type'),
- })
- location.href = URL.createObjectURL(blob) // Trigger file save
- }
- })
- .catch(function (httpResponse) {
- const { data, status } = httpResponse
- scope[attrs.name].inflight = false
- response.success = false
- response.error = true
- response.status = status
- response.data = data
-
- const onErrorHandler = scope[attrs.onError]
- if (onErrorHandler) {
- onErrorHandler(httpResponse)
- return
- }
-
- let responseMessage
- if (data.message && data.message.text) {
- responseMessage = data.message.text
- } else {
- responseMessage = data.message
- }
-
- if (status === 400) {
- // Bad Request
- response.message = {
- text:
- responseMessage ||
- 'Invalid Request. Please correct the data and try again.',
- type: 'error',
- }
- } else if (status === 403) {
- // Forbidden
- response.message = {
- text:
- responseMessage ||
- 'Session error. Please check you have cookies enabled. If the problem persists, try clearing your cache and cookies.',
- type: 'error',
- }
- } else if (status === 429) {
- response.message = {
- text:
- responseMessage ||
- 'Too many attempts. Please wait for a while and try again.',
- type: 'error',
- }
- } else {
- response.message = {
- text:
- responseMessage ||
- 'Something went wrong talking to the server :(. Please try again.',
- type: 'error',
- }
- }
- ga('send', 'event', formName, 'failure', data.message)
- })
- }
-
- const submit = () =>
- validateCaptchaIfEnabled(response => _submitRequest(response))
-
- const _httpRequestFn = (method = 'post') => {
- const $HTTP_FNS = {
- post: $http.post,
- get: $http.get,
- }
- return $HTTP_FNS[method.toLowerCase()]
- }
-
- element.on('submit', function (e) {
- e.preventDefault()
- submit()
- })
-
- if (attrs.autoSubmit) {
- submit()
- }
- },
- }
- },
-])
-
-App.directive('formMessages', function () {
- return {
- restrict: 'E',
- template: `\
-
-
-\
-`,
- transclude: true,
- scope: {
- form: '=for',
- },
- }
-})
diff --git a/services/web/frontend/js/directives/autoSubmitForm.js b/services/web/frontend/js/directives/autoSubmitForm.js
deleted file mode 100644
index b1df2792be..0000000000
--- a/services/web/frontend/js/directives/autoSubmitForm.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import App from '../base'
-App.directive('autoSubmitForm', function () {
- return {
- link(scope, element) {
- element.submit() // Runs on load
- },
- }
-})
diff --git a/services/web/frontend/js/directives/bookmarkableTabset.js b/services/web/frontend/js/directives/bookmarkableTabset.js
deleted file mode 100644
index 851c5c2ab7..0000000000
--- a/services/web/frontend/js/directives/bookmarkableTabset.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import _ from 'lodash'
-import App from '../base'
-App.directive('bookmarkableTabset', [
- '$location',
- function ($location) {
- return {
- restrict: 'A',
- require: 'tabset',
- link(scope, el, attrs, tabset) {
- const _makeActive = function (hash) {
- if (hash && hash !== '') {
- const matchingTab = _.find(
- tabset.tabs,
- tab => tab.bookmarkableTabId === hash
- )
- if (matchingTab) {
- matchingTab.select()
- return el.children()[0].scrollIntoView({ behavior: 'smooth' })
- }
- }
- }
-
- scope.$applyAsync(function () {
- // for page load
- const hash = $location.hash()
- _makeActive(hash)
-
- // for links within page to a tab
- // this needs to be within applyAsync because there could be a link
- // within a tab to another tab
- const linksToTabs = document.querySelectorAll('.link-to-tab')
- const _clickLinkToTab = event => {
- const hash = event.currentTarget
- .getAttribute('href')
- .split('#')
- .pop()
- _makeActive(hash)
- }
-
- if (linksToTabs) {
- Array.from(linksToTabs).map(link =>
- link.addEventListener('click', _clickLinkToTab)
- )
- }
- })
- },
- }
- },
-])
-
-App.directive('bookmarkableTab', [
- '$location',
- function ($location) {
- return {
- restrict: 'A',
- require: 'tab',
- link(scope, el, attrs, tab) {
- const tabScope = el.isolateScope()
- const tabId = attrs.bookmarkableTab
- if (tabScope && tabId && tabId !== '') {
- tabScope.bookmarkableTabId = tabId
- tabScope.$watch('active', function (isActive, wasActive) {
- if (isActive && !wasActive && $location.hash() !== tabId) {
- return $location.hash(tabId)
- }
- })
- }
- },
- }
- },
-])
diff --git a/services/web/frontend/js/directives/equals.js b/services/web/frontend/js/directives/equals.js
deleted file mode 100644
index b1cffd9da0..0000000000
--- a/services/web/frontend/js/directives/equals.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-import App from '../base'
-
-export default App.directive('equals', function () {
- return {
- require: 'ngModel',
- link(scope, elem, attrs, ctrl) {
- const firstField = `#${attrs.equals}`
- return elem.add(firstField).on('keyup', () =>
- scope.$apply(function () {
- const equal = elem.val() === $(firstField).val()
- return ctrl.$setValidity('areEqual', equal)
- })
- )
- },
- }
-})
diff --git a/services/web/frontend/js/directives/expandableTextArea.js b/services/web/frontend/js/directives/expandableTextArea.js
deleted file mode 100644
index deefc5190b..0000000000
--- a/services/web/frontend/js/directives/expandableTextArea.js
+++ /dev/null
@@ -1,31 +0,0 @@
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-import App from '../base'
-
-export default App.directive('expandableTextArea', function () {
- return {
- restrict: 'A',
- link(scope, el) {
- const resetHeight = function () {
- const curHeight = el.outerHeight()
- const fitHeight = el.prop('scrollHeight')
- // clear height if text area is empty
- if (el.val() === '') {
- el.css('height', 'unset')
- }
- // otherwise expand to fit text
- else if (fitHeight > curHeight) {
- scope.$emit('expandable-text-area:resize')
- el.css('height', fitHeight)
- }
- }
-
- return scope.$watch(() => el.val(), resetHeight)
- },
- }
-})
diff --git a/services/web/frontend/js/directives/focus.js b/services/web/frontend/js/directives/focus.js
deleted file mode 100644
index e40c122194..0000000000
--- a/services/web/frontend/js/directives/focus.js
+++ /dev/null
@@ -1,118 +0,0 @@
-/* eslint-disable
- no-return-assign,
-*/
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * DS207: Consider shorter variations of null checks
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-import App from '../base'
-App.directive('focusWhen', [
- '$timeout',
- function ($timeout) {
- return {
- restrict: 'A',
- link(scope, element, attr) {
- return scope.$watch(attr.focusWhen, function (value) {
- if (value) {
- return $timeout(() => element.focus())
- }
- })
- },
- }
- },
-])
-
-App.directive('focusOn', function () {
- return {
- restrict: 'A',
- link(scope, element, attrs) {
- return scope.$on(attrs.focusOn, () => element.focus())
- },
- }
-})
-
-App.directive('selectWhen', [
- '$timeout',
- function ($timeout) {
- return {
- restrict: 'A',
- link(scope, element, attr) {
- return scope.$watch(attr.selectWhen, function (value) {
- if (value) {
- return $timeout(() => element.select())
- }
- })
- },
- }
- },
-])
-
-App.directive('selectOn', function () {
- return {
- restrict: 'A',
- link(scope, element, attrs) {
- return scope.$on(attrs.selectOn, () => element.select())
- },
- }
-})
-
-App.directive('selectNameWhen', [
- '$timeout',
- function ($timeout) {
- return {
- restrict: 'A',
- link(scope, element, attrs) {
- return scope.$watch(attrs.selectNameWhen, function (value) {
- if (value) {
- return $timeout(() => selectName(element))
- }
- })
- },
- }
- },
-])
-
-App.directive('selectNameOn', function () {
- return {
- restrict: 'A',
- link(scope, element, attrs) {
- return scope.$on(attrs.selectNameOn, () => selectName(element))
- },
- }
-})
-
-App.directive('focus', [
- '$timeout',
- function ($timeout) {
- return {
- scope: {
- trigger: '@focus',
- },
-
- link(scope, element) {
- return scope.$watch('trigger', function (value) {
- if (value === 'true') {
- return $timeout(() => element[0].focus())
- }
- })
- },
- }
- },
-])
-
-function selectName(element) {
- // Select up to last '.'. I.e. everything except the file extension
- element.focus()
- const name = element.val()
- if (element[0].setSelectionRange != null) {
- let selectionEnd = name.lastIndexOf('.')
- if (selectionEnd === -1) {
- selectionEnd = name.length
- }
- return element[0].setSelectionRange(0, selectionEnd)
- }
-}
diff --git a/services/web/frontend/js/directives/maxHeight.js b/services/web/frontend/js/directives/maxHeight.js
deleted file mode 100644
index eb9fd3de93..0000000000
--- a/services/web/frontend/js/directives/maxHeight.js
+++ /dev/null
@@ -1,22 +0,0 @@
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * DS207: Consider shorter variations of null checks
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-import App from '../base'
-
-export default App.directive('maxHeight', function () {
- return {
- restrict: 'A',
- link(scope, element, attrs) {
- return scope.$watch(attrs.maxHeight, function (value) {
- if (value != null) {
- return element.css({ 'max-height': value })
- }
- })
- },
- }
-})
diff --git a/services/web/frontend/js/directives/onEnter.js b/services/web/frontend/js/directives/onEnter.js
deleted file mode 100644
index 1dbfda8f2f..0000000000
--- a/services/web/frontend/js/directives/onEnter.js
+++ /dev/null
@@ -1,18 +0,0 @@
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-import App from '../base'
-
-export default App.directive('onEnter', function () {
- return (scope, element, attrs) =>
- element.bind('keydown keypress', function (event) {
- if (event.which === 13) {
- scope.$apply(() => scope.$eval(attrs.onEnter, { event }))
- return event.preventDefault()
- }
- })
-})
diff --git a/services/web/frontend/js/directives/rightClick.js b/services/web/frontend/js/directives/rightClick.js
deleted file mode 100644
index 1677d4a2e7..0000000000
--- a/services/web/frontend/js/directives/rightClick.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-import App from '../base'
-
-export default App.directive('rightClick', function () {
- return {
- restrict: 'A',
- link(scope, element, attrs) {
- return element.bind('contextmenu', function (e) {
- e.preventDefault()
- e.stopPropagation()
- return scope.$eval(attrs.rightClick)
- })
- },
- }
-})
diff --git a/services/web/frontend/js/directives/scroll.js b/services/web/frontend/js/directives/scroll.js
deleted file mode 100644
index 1d490e823d..0000000000
--- a/services/web/frontend/js/directives/scroll.js
+++ /dev/null
@@ -1,61 +0,0 @@
-/* eslint-disable
- max-len,
- no-return-assign,
-*/
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-import App from '../base'
-
-export default App.directive('updateScrollBottomOn', [
- '$timeout',
- function ($timeout) {
- return {
- restrict: 'A',
- link(scope, element, attrs, ctrls) {
- // We keep the offset from the bottom fixed whenever the event fires
- //
- // ^ | ^
- // | | | scrollTop
- // | | v
- // | |-----------
- // | | ^
- // | | |
- // | | | clientHeight (viewable area)
- // | | |
- // | | |
- // | | v
- // | |-----------
- // | | ^
- // | | | scrollBottom
- // v | v
- // \
- // scrollHeight
-
- let scrollBottom = 0
- element.on(
- 'scroll',
- e =>
- (scrollBottom =
- element[0].scrollHeight -
- element[0].scrollTop -
- element[0].clientHeight)
- )
-
- return scope.$on(attrs.updateScrollBottomOn, () =>
- $timeout(
- () =>
- element.scrollTop(
- element[0].scrollHeight - element[0].clientHeight - scrollBottom
- ),
- 0
- )
- )
- },
- }
- },
-])
diff --git a/services/web/frontend/js/directives/selectAll.js b/services/web/frontend/js/directives/selectAll.js
deleted file mode 100644
index 7737350fbc..0000000000
--- a/services/web/frontend/js/directives/selectAll.js
+++ /dev/null
@@ -1,108 +0,0 @@
-/* eslint-disable
- max-len,
- no-return-assign,
-*/
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * DS207: Consider shorter variations of null checks
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-import App from '../base'
-App.directive('selectAllList', function () {
- return {
- controller: [
- '$scope',
- function ($scope) {
- // Selecting or deselecting all should apply to all projects
- this.selectAll = () => $scope.$broadcast('select-all:select')
-
- this.deselectAll = () => $scope.$broadcast('select-all:deselect')
-
- this.clearSelectAllState = () => $scope.$broadcast('select-all:clear')
- },
- ],
- link(scope, element, attrs) {},
- }
-})
-
-App.directive('selectAll', function () {
- return {
- require: '^selectAllList',
- link(scope, element, attrs, selectAllListController) {
- scope.$on('select-all:clear', () => element.prop('checked', false))
-
- return element.change(function () {
- if (element.is(':checked')) {
- selectAllListController.selectAll()
- } else {
- selectAllListController.deselectAll()
- }
- return true
- })
- },
- }
-})
-
-App.directive('selectIndividual', function () {
- return {
- require: '^selectAllList',
- scope: {
- ngModel: '=',
- },
- link(scope, element, attrs, selectAllListController) {
- let ignoreChanges = false
-
- scope.$watch('ngModel', function (value) {
- if (value != null && !ignoreChanges) {
- return selectAllListController.clearSelectAllState()
- }
- })
-
- scope.$on('select-all:select', function () {
- if (element.prop('disabled')) {
- return
- }
- ignoreChanges = true
- scope.$apply(() => (scope.ngModel = true))
- return (ignoreChanges = false)
- })
-
- scope.$on('select-all:deselect', function () {
- if (element.prop('disabled')) {
- return
- }
- ignoreChanges = true
- scope.$apply(() => (scope.ngModel = false))
- return (ignoreChanges = false)
- })
-
- return scope.$on('select-all:row-clicked', function () {
- if (element.prop('disabled')) {
- return
- }
- ignoreChanges = true
- scope.$apply(function () {
- scope.ngModel = !scope.ngModel
- if (!scope.ngModel) {
- return selectAllListController.clearSelectAllState()
- }
- })
- return (ignoreChanges = false)
- })
- },
- }
-})
-
-export default App.directive('selectRow', function () {
- return {
- scope: true,
- link(scope, element, attrs) {
- return element.on('click', e =>
- scope.$broadcast('select-all:row-clicked')
- )
- },
- }
-})
diff --git a/services/web/frontend/js/directives/stopPropagation.js b/services/web/frontend/js/directives/stopPropagation.js
deleted file mode 100644
index c6c2ed349c..0000000000
--- a/services/web/frontend/js/directives/stopPropagation.js
+++ /dev/null
@@ -1,28 +0,0 @@
-/* eslint-disable
- max-len,
-*/
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-import App from '../base'
-App.directive('stopPropagation', function () {
- return {
- restrict: 'A',
- link(scope, element, attrs) {
- return element.bind(attrs.stopPropagation, e => e.stopPropagation())
- },
- }
-})
-
-export default App.directive('preventDefault', function () {
- return {
- restrict: 'A',
- link(scope, element, attrs) {
- return element.bind(attrs.preventDefault, e => e.preventDefault())
- },
- }
-})
diff --git a/services/web/frontend/js/directives/videoPlayState.js b/services/web/frontend/js/directives/videoPlayState.js
deleted file mode 100644
index 8cc1885145..0000000000
--- a/services/web/frontend/js/directives/videoPlayState.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/* eslint-disable
- max-len,
-*/
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-import App from '../base'
-
-export default App.directive('videoPlayState', [
- '$parse',
- function ($parse) {
- return {
- restrict: 'A',
- link(scope, element, attrs) {
- const videoDOMEl = element[0]
- return scope.$watch(
- () => $parse(attrs.videoPlayState)(scope),
- function (shouldPlay) {
- if (shouldPlay) {
- videoDOMEl.currentTime = 0
- return videoDOMEl.play()
- } else {
- return videoDOMEl.pause()
- }
- }
- )
- },
- }
- },
-])
diff --git a/services/web/frontend/js/filters/formatDate.js b/services/web/frontend/js/filters/formatDate.js
deleted file mode 100644
index 411f013641..0000000000
--- a/services/web/frontend/js/filters/formatDate.js
+++ /dev/null
@@ -1,48 +0,0 @@
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * DS207: Consider shorter variations of null checks
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-import App from '../base'
-import moment from 'moment'
-moment.updateLocale('en', {
- calendar: {
- lastDay: '[Yesterday]',
- sameDay: '[Today]',
- nextDay: '[Tomorrow]',
- lastWeek: 'ddd, Do MMM YY',
- nextWeek: 'ddd, Do MMM YY',
- sameElse: 'ddd, Do MMM YY',
- },
-})
-
-App.filter(
- 'formatDate',
- () =>
- function (date, format) {
- if (!date) return 'N/A'
- if (format == null) {
- format = 'Do MMM YYYY, h:mm a'
- }
- return moment(date).format(format)
- }
-)
-
-App.filter(
- 'utcDate',
- () =>
- function (date, format) {
- if (!date) return 'N/A'
- if (format == null) {
- format = 'D MMM YYYY, HH:mm:ss'
- }
- return moment(date).utc().format(format) + ' UTC'
- }
-)
-
-App.filter('relativeDate', () => date => moment(date).calendar())
-
-App.filter('fromNowDate', () => date => moment(date).fromNow())
diff --git a/services/web/frontend/js/ide.js b/services/web/frontend/js/ide.js
index 94f8b8df92..c293b8bdfd 100644
--- a/services/web/frontend/js/ide.js
+++ b/services/web/frontend/js/ide.js
@@ -32,24 +32,11 @@ import './ide/chat/index'
import './ide/file-view/index'
import './ide/toolbar/index'
import './ide/directives/layout'
-import './ide/directives/validFile'
import './ide/directives/verticalResizablePanes'
import './ide/services/ide'
-import './directives/focus'
-import './directives/scroll'
-import './directives/onEnter'
-import './directives/stopPropagation'
-import './directives/rightClick'
-import './directives/expandableTextArea'
-import './directives/videoPlayState'
-import './services/queued-http'
-import './services/validateCaptcha'
-import './services/validateCaptchaV3'
-import './services/wait-for'
-import './filters/formatDate'
-import './main/event'
-import './main/account-upgrade-angular'
-import './main/system-messages'
+import './services/queued-http' // used in FileTreeManager
+import './main/event' // used in various controllers
+import './main/system-messages' // used in project/editor
import '../../modules/modules-ide'
import './features/source-editor/ide'
import './shared/context/controllers/root-context-controller'
diff --git a/services/web/frontend/js/ide/directives/validFile.js b/services/web/frontend/js/ide/directives/validFile.js
deleted file mode 100644
index 339bc99d67..0000000000
--- a/services/web/frontend/js/ide/directives/validFile.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable
- max-len,
- no-return-assign,
-*/
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-import App from '../../base'
-import SafePath from './SafePath'
-
-export default App.directive('validFile', function () {
- return {
- require: 'ngModel',
- link(scope, element, attrs, ngModelCtrl) {
- return (ngModelCtrl.$validators.validFile = filename =>
- SafePath.isCleanFilename(filename))
- },
- }
-})
diff --git a/services/web/frontend/js/ide/review-panel/controllers/ReviewPanelController.js b/services/web/frontend/js/ide/review-panel/controllers/ReviewPanelController.js
index e0211988a7..95f155b90d 100644
--- a/services/web/frontend/js/ide/review-panel/controllers/ReviewPanelController.js
+++ b/services/web/frontend/js/ide/review-panel/controllers/ReviewPanelController.js
@@ -143,10 +143,6 @@ export default App.controller('ReviewPanelController', [
ide.$scope.$broadcast('review-panel:layout', false)
})
- $scope.$on('expandable-text-area:resize', event =>
- $timeout(() => ide.$scope.$broadcast('review-panel:layout'))
- )
-
$scope.$on('review-panel:sizes', (e, sizes) => {
$scope.$broadcast('editor:set-scroll-size', sizes)
dispatchReviewPanelEvent('sizes', sizes)
diff --git a/services/web/frontend/js/main.js b/services/web/frontend/js/main.js
index f57fc632ce..fbb23356a7 100644
--- a/services/web/frontend/js/main.js
+++ b/services/web/frontend/js/main.js
@@ -8,36 +8,16 @@
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
-import './main/token-access'
-import './main/clear-sessions'
-import './main/account-upgrade-angular'
-import './main/plans'
-import './main/scribtex-popup'
-import './main/event'
-import './main/bonus'
-import './main/system-messages'
-import './main/annual-upgrade'
-import './main/subscription/team-invite-controller'
-import './main/learn'
-import './main/keys'
-import './main/importing'
-import './directives/autoSubmitForm'
-import './directives/asyncForm'
-import './directives/stopPropagation'
-import './directives/focus'
-import './directives/equals'
-import './directives/eventTracking'
-import './directives/onEnter'
-import './directives/selectAll'
-import './directives/maxHeight'
-import './directives/bookmarkableTabset'
-import './services/queued-http'
-import './services/validateCaptcha'
-import './services/validateCaptchaV3'
-import './filters/formatDate'
+import './main/token-access' // used in project/token/access
+import './main/event' // used in various controllers
+import './main/bonus' // used in referal/bonus
+import './main/system-messages' // used in project/editor
+import './main/annual-upgrade' // used in subscriptions/upgradeToAnnual
+import './main/subscription/team-invite-controller' // used in subscriptions/team/invite
+import './directives/eventTracking' // used in lots of places
import './features/cookie-banner'
import '../../modules/modules-main'
-import './cdn-load-test'
+import './cdn-load-test' // TODO: remove this?
import { debugConsole } from '@/utils/debugging'
angular.module('SharelatexApp').config([
'$locationProvider',
diff --git a/services/web/frontend/js/main/account-upgrade-angular.js b/services/web/frontend/js/main/account-upgrade-angular.js
deleted file mode 100644
index 90fed142f7..0000000000
--- a/services/web/frontend/js/main/account-upgrade-angular.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import App from '../base'
-import { startFreeTrial, upgradePlan, paywallPrompt } from './account-upgrade'
-
-App.controller('FreeTrialModalController', [
- '$scope',
- function ($scope) {
- $scope.buttonClass = 'btn-primary'
- $scope.startFreeTrial = (source, version) =>
- startFreeTrial(source, version, $scope)
- $scope.paywallPrompt = source => paywallPrompt(source)
- },
-])
-
-App.controller('UpgradeModalController', [
- '$scope',
- function ($scope) {
- $scope.buttonClass = 'btn-primary'
- $scope.upgradePlan = source => upgradePlan(source, $scope)
- },
-])
diff --git a/services/web/frontend/js/main/clear-sessions.js b/services/web/frontend/js/main/clear-sessions.js
deleted file mode 100644
index 6ecf09d8d8..0000000000
--- a/services/web/frontend/js/main/clear-sessions.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/* eslint-disable
- max-len,
- no-return-assign,
-*/
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-import App from '../base'
-import getMeta from '../utils/meta'
-
-export default App.controller('ClearSessionsController', [
- '$scope',
- '$http',
- function ($scope, $http) {
- $scope.state = {
- otherSessions: getMeta('ol-otherSessions'),
- error: false,
- success: false,
- }
-
- return ($scope.clearSessions = function () {
- return $http({
- method: 'POST',
- url: '/user/sessions/clear',
- headers: { 'X-CSRF-Token': window.csrfToken },
- })
- .then(function () {
- $scope.state.otherSessions = []
- $scope.state.error = false
- return ($scope.state.success = true)
- })
- .catch(() => ($scope.state.error = true))
- })
- },
-])
diff --git a/services/web/frontend/js/main/keys.js b/services/web/frontend/js/main/keys.js
deleted file mode 100644
index 41b2f55fe6..0000000000
--- a/services/web/frontend/js/main/keys.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-import App from '../base'
-
-export default App.constant('Keys', {
- ENTER: 13,
- TAB: 9,
- ESCAPE: 27,
- SPACE: 32,
- BACKSPACE: 8,
- UP: 38,
- DOWN: 40,
- LEFT: 37,
- RIGHT: 39,
- PERIOD: 190,
- COMMA: 188,
- END: 35,
-})
diff --git a/services/web/frontend/js/main/learn.js b/services/web/frontend/js/main/learn.js
deleted file mode 100644
index f6bce77255..0000000000
--- a/services/web/frontend/js/main/learn.js
+++ /dev/null
@@ -1,102 +0,0 @@
-import _ from 'lodash'
-import App from '../base'
-import '../directives/mathjax'
-import '../services/algolia-search'
-App.controller('SearchWikiController', [
- '$scope',
- 'algoliaSearch',
- function ($scope, algoliaSearch) {
- $scope.hits = []
- $scope.hits_total = 0
- $scope.config_hits_per_page = 20
- $scope.processingSearch = false
-
- $scope.clearSearchText = function () {
- $scope.searchQueryText = ''
- updateHits([])
- }
-
- $scope.safeApply = function (fn) {
- const phase = $scope.$root.$$phase
- if (phase === '$apply' || phase === '$digest') {
- $scope.$eval(fn)
- } else {
- $scope.$apply(fn)
- }
- }
-
- const buildHitViewModel = function (hit) {
- const pagePath = hit.kb ? 'how-to/' : 'latex/'
- const pageSlug = encodeURIComponent(hit.pageName.replace(/\s/g, '_'))
- let sectionUnderscored = ''
- if (hit.sectionName && hit.sectionName !== '') {
- sectionUnderscored = '#' + hit.sectionName.replace(/\s/g, '_')
- }
- const section = hit._highlightResult.sectionName
- let pageName = hit._highlightResult.pageName.value
- if (section && section.value && section !== '') {
- pageName += ' - ' + section.value
- }
-
- let content = hit._highlightResult.content.value
- // Replace many new lines
- content = content.replace(/\n\n+/g, '\n\n')
- const lines = content.split('\n')
- // Only show the lines that have a highlighted match
- const matchingLines = []
- for (const line of lines) {
- if (!/^\[edit\]/.test(line)) {
- content += line + '\n'
- if (//.test(line)) {
- matchingLines.push(line)
- }
- }
- }
- content = matchingLines.join('\n...\n')
- const result = {
- name: pageName,
- url: `/learn/${pagePath}${pageSlug}${sectionUnderscored}`,
- content,
- }
- return result
- }
-
- const updateHits = (hits, hitsTotal = 0) => {
- $scope.safeApply(() => {
- $scope.hits = hits
- $scope.hits_total = hitsTotal
- })
- }
-
- $scope.search = function () {
- $scope.processingSearch = true
- const query = $scope.searchQueryText
- if (!query || query.length === 0) {
- updateHits([])
- return
- }
-
- algoliaSearch.searchWiki(
- query,
- {
- hitsPerPage: $scope.config_hits_per_page,
- },
- function (err, response) {
- if (err) {
- $scope.searchError = err
- }
-
- $scope.processingSearch = false
- if (response.hits.length === 0) {
- updateHits([])
- } else {
- const hits = _.map(response.hits, buildHitViewModel)
- updateHits(hits, response.nbHits)
- }
- }
- )
- }
- },
-])
-
-export default App.controller('LearnController', function () {})
diff --git a/services/web/frontend/js/main/plans.js b/services/web/frontend/js/main/plans.js
deleted file mode 100644
index 11b2b93a91..0000000000
--- a/services/web/frontend/js/main/plans.js
+++ /dev/null
@@ -1,340 +0,0 @@
-/* eslint-disable
- camelcase,
- max-len
-*/
-import App from '../base'
-import getMeta from '../utils/meta'
-
-App.factory('MultiCurrencyPricing', function () {
- const currencyCode = getMeta('ol-recommendedCurrency')
-
- return {
- currencyCode,
-
- plans: {
- USD: {
- symbol: '$',
- student: {
- monthly: '$9',
- annual: '$89',
- },
- personal: {
- monthly: '$14',
- annual: '$129',
- },
- collaborator: {
- monthly: '$21',
- annual: '$199',
- },
- professional: {
- monthly: '$42',
- annual: '$399',
- },
- },
- EUR: {
- symbol: '€',
- student: {
- monthly: '€8',
- annual: '€79',
- },
- personal: {
- monthly: '€13',
- annual: '€119',
- },
- collaborator: {
- monthly: '€19',
- annual: '€179',
- },
- professional: {
- monthly: '€39',
- annual: '€369',
- },
- },
- GBP: {
- symbol: '£',
- student: {
- monthly: '£7',
- annual: '£69',
- },
- personal: {
- monthly: '£11',
- annual: '£104',
- },
- collaborator: {
- monthly: '£17',
- annual: '£159',
- },
- professional: {
- monthly: '£34',
- annual: '£319',
- },
- },
- SEK: {
- symbol: 'kr',
- student: {
- monthly: '66 kr',
- annual: '659 kr',
- },
- personal: {
- monthly: '104 kr',
- annual: '969 kr',
- },
- collaborator: {
- monthly: '154 kr',
- annual: '1449 kr',
- },
- professional: {
- monthly: '299 kr',
- annual: '2869 kr',
- },
- },
- CAD: {
- symbol: '$',
- student: {
- monthly: '$10',
- annual: '$99',
- },
- personal: {
- monthly: '$16',
- annual: '$149',
- },
- collaborator: {
- monthly: '$25',
- annual: '$229',
- },
- professional: {
- monthly: '$48',
- annual: '$449',
- },
- },
- NOK: {
- symbol: 'kr',
- student: {
- monthly: '66 kr',
- annual: '659 kr',
- },
- personal: {
- monthly: '104 kr',
- annual: '969 kr',
- },
- collaborator: {
- monthly: '154 kr',
- annual: '1449 kr',
- },
- professional: {
- monthly: '299 kr',
- annual: '2869 kr',
- },
- },
- DKK: {
- symbol: 'kr',
- student: {
- monthly: '55 kr',
- annual: '549 kr',
- },
- personal: {
- monthly: '84 kr',
- annual: '799 kr',
- },
- collaborator: {
- monthly: '129 kr',
- annual: '1199 kr',
- },
- professional: {
- monthly: '249 kr',
- annual: '2379 kr',
- },
- },
- AUD: {
- symbol: '$',
- student: {
- monthly: '$11',
- annual: '$109',
- },
- personal: {
- monthly: '$17',
- annual: '$159',
- },
- collaborator: {
- monthly: '$25',
- annual: '$239',
- },
- professional: {
- monthly: '$49',
- annual: '$459',
- },
- },
- NZD: {
- symbol: '$',
- student: {
- monthly: '$11',
- annual: '$109',
- },
- personal: {
- monthly: '$17',
- annual: '$159',
- },
- collaborator: {
- monthly: '$25',
- annual: '$239',
- },
- professional: {
- monthly: '$49',
- annual: '$459',
- },
- },
- CHF: {
- symbol: 'Fr',
- student: {
- monthly: 'Fr 9',
- annual: 'Fr 89',
- },
- personal: {
- monthly: 'Fr 14',
- annual: 'Fr 134',
- },
- collaborator: {
- monthly: 'Fr 21',
- annual: 'Fr 199',
- },
- professional: {
- monthly: 'Fr 42',
- annual: 'Fr 399',
- },
- },
- SGD: {
- symbol: '$',
- student: {
- monthly: '$13',
- annual: '$129',
- },
- personal: {
- monthly: '$18',
- annual: '$169',
- },
- collaborator: {
- monthly: '$28',
- annual: '$259',
- },
- professional: {
- monthly: '$55',
- annual: '$519',
- },
- },
- INR: {
- symbol: '₹',
- student: {
- monthly: '₹219',
- annual: '₹2199',
- },
- personal: {
- monthly: '₹339',
- annual: '₹2999',
- },
- collaborator: {
- monthly: '₹499',
- annual: '₹4599',
- },
- professional: {
- monthly: '₹999',
- annual: '₹9599',
- },
- },
- BRL: {
- symbol: 'R$',
- student: {
- monthly: 'R$ 23',
- annual: 'R$ 229',
- },
- personal: {
- monthly: 'R$ 35',
- annual: 'R$ 329',
- },
- collaborator: {
- monthly: 'R$ 55',
- annual: 'R$ 499',
- },
- professional: {
- monthly: 'R$ 109',
- annual: 'R$ 999',
- },
- },
- MXN: {
- symbol: '$',
- student: {
- monthly: '$99',
- annual: '$999',
- },
- personal: {
- monthly: '$149',
- annual: '$1,399',
- },
- collaborator: {
- monthly: '$229',
- annual: '$2,199',
- },
- professional: {
- monthly: '$459',
- annual: '$4,399',
- },
- },
- COP: {
- symbol: '$',
- student: {
- monthly: '$ 12.900',
- annual: '$ 129.900',
- },
- personal: {
- monthly: '$ 21.900',
- annual: '$ 185.900',
- },
- collaborator: {
- monthly: '$ 29.900',
- annual: '$ 285.900',
- },
- professional: {
- monthly: '$ 59.900',
- annual: '$ 575.900',
- },
- },
- CLP: {
- symbol: '$',
- student: {
- monthly: '$3.990',
- annual: '$38.990',
- },
- personal: {
- monthly: '$6.190',
- annual: '$56.990',
- },
- collaborator: {
- monthly: '$9.190',
- annual: '$87.990',
- },
- professional: {
- monthly: '$18.990',
- annual: '$174.990',
- },
- },
- PEN: {
- symbol: 'S/',
- student: {
- monthly: 'S/ 16',
- annual: 'S/ 159',
- },
- personal: {
- monthly: 'S/ 26',
- annual: 'S/ 239',
- },
- collaborator: {
- monthly: 'S/ 39',
- annual: 'S/ 369',
- },
- professional: {
- monthly: 'S/ 76',
- annual: 'S/ 729',
- },
- },
- },
- }
-})
diff --git a/services/web/frontend/js/main/scribtex-popup.js b/services/web/frontend/js/main/scribtex-popup.js
deleted file mode 100644
index 2f29cd22b6..0000000000
--- a/services/web/frontend/js/main/scribtex-popup.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-import App from '../base'
-
-export default App.controller('ScribtexPopupController', [
- '$modal',
- function ($modal) {
- $modal.open({
- templateUrl: 'scribtexModalTemplate',
- })
- },
-])
diff --git a/services/web/frontend/js/services/validateCaptcha.js b/services/web/frontend/js/services/validateCaptcha.js
deleted file mode 100644
index 7b8cbf41dc..0000000000
--- a/services/web/frontend/js/services/validateCaptcha.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/* global grecaptcha */
-
-/* eslint-disable
- no-return-assign,
-*/
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- */
-import App from '../base'
-
-export default App.factory('validateCaptcha', function () {
- let _recaptchaCallbacks = []
- const onRecaptchaSubmit = function (token) {
- for (const cb of _recaptchaCallbacks) {
- cb(token)
- }
- _recaptchaCallbacks = []
- }
-
- let recaptchaId = null
- const validateCaptcha = (callback, captchaDisabled) => {
- if (callback == null) {
- callback = function () {}
- }
- if (
- typeof grecaptcha === 'undefined' ||
- grecaptcha === null ||
- captchaDisabled
- ) {
- return callback()
- }
- const reset = () => grecaptcha.reset()
- _recaptchaCallbacks.push(callback)
- _recaptchaCallbacks.push(reset)
- if (recaptchaId == null) {
- const el = $('#recaptcha')[0]
- recaptchaId = grecaptcha.render(el, { callback: onRecaptchaSubmit })
- }
- return grecaptcha.execute(recaptchaId)
- }
-
- return validateCaptcha
-})
diff --git a/services/web/frontend/js/services/validateCaptchaV3.js b/services/web/frontend/js/services/validateCaptchaV3.js
deleted file mode 100644
index 8283f34076..0000000000
--- a/services/web/frontend/js/services/validateCaptchaV3.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import App from '../base'
-
-export default App.factory('validateCaptchaV3', function () {
- const grecaptcha = window.grecaptcha
- const ExposedSettings = window.ExposedSettings
- return function validateCaptchaV3(actionName, callback = () => {}) {
- if (!grecaptcha) {
- return
- }
- if (!ExposedSettings || !ExposedSettings.recaptchaSiteKeyV3) {
- return
- }
- grecaptcha.ready(function () {
- grecaptcha
- .execute(ExposedSettings.recaptchaSiteKeyV3, { action: actionName })
- .then(callback)
- })
- }
-})
diff --git a/services/web/frontend/js/services/wait-for.js b/services/web/frontend/js/services/wait-for.js
deleted file mode 100644
index 5a177f2887..0000000000
--- a/services/web/frontend/js/services/wait-for.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/* eslint-disable
- max-len,
-*/
-// TODO: This file was created by bulk-decaffeinate.
-// Fix any style issues and re-enable lint.
-/*
- * decaffeinate suggestions:
- * DS102: Remove unnecessary code created because of implicit returns
- * DS207: Consider shorter variations of null checks
- * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
- */
-import App from '../base'
-
-export default App.factory('waitFor', [
- '$q',
- function ($q) {
- const waitFor = function (testFunction, timeout, pollInterval) {
- if (pollInterval == null) {
- pollInterval = 500
- }
- const iterationLimit = Math.floor(timeout / pollInterval)
- let iterations = 0
- return $q(function (resolve, reject) {
- let tryIteration
- return (tryIteration = function () {
- if (iterations > iterationLimit) {
- return reject(
- new Error(
- `waiting too long, ${JSON.stringify({ timeout, pollInterval })}`
- )
- )
- }
- iterations += 1
- const result = testFunction()
- if (result != null) {
- return resolve(result)
- } else {
- return setTimeout(tryIteration, pollInterval)
- }
- })()
- })
- }
- return waitFor
- },
-])