mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-11 22:25:03 +00:00
Remove unused Angular code from "main" and "ide" endpoints (#15868)
GitOrigin-RevId: dc7ed968c60ae6c64d3cd6d2ec47c93e8d32d7db
This commit is contained in:
parent
d5b3c10cb5
commit
17ac0eb16b
29 changed files with 11 additions and 1558 deletions
services/web
app/views
frontend/js
|
@ -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")}
|
|
@ -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 .
|
|
@ -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: `\
|
||||
<div class="alert" ng-class="{
|
||||
'alert-danger': form.response.message.type == 'error',
|
||||
'alert-success': form.response.message.type != 'error'
|
||||
}" ng-show="!!form.response.message" ng-bind-html="form.response.message.text">
|
||||
</div>
|
||||
<div ng-transclude></div>\
|
||||
`,
|
||||
transclude: true,
|
||||
scope: {
|
||||
form: '=for',
|
||||
},
|
||||
}
|
||||
})
|
|
@ -1,8 +0,0 @@
|
|||
import App from '../base'
|
||||
App.directive('autoSubmitForm', function () {
|
||||
return {
|
||||
link(scope, element) {
|
||||
element.submit() // Runs on load
|
||||
},
|
||||
}
|
||||
})
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
])
|
|
@ -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)
|
||||
})
|
||||
)
|
||||
},
|
||||
}
|
||||
})
|
|
@ -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)
|
||||
},
|
||||
}
|
||||
})
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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 })
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
})
|
|
@ -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()
|
||||
}
|
||||
})
|
||||
})
|
|
@ -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)
|
||||
})
|
||||
},
|
||||
}
|
||||
})
|
|
@ -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
|
||||
)
|
||||
)
|
||||
},
|
||||
}
|
||||
},
|
||||
])
|
|
@ -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')
|
||||
)
|
||||
},
|
||||
}
|
||||
})
|
|
@ -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())
|
||||
},
|
||||
}
|
||||
})
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
}
|
||||
},
|
||||
])
|
|
@ -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())
|
|
@ -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'
|
||||
|
|
|
@ -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))
|
||||
},
|
||||
}
|
||||
})
|
|
@ -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)
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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)
|
||||
},
|
||||
])
|
|
@ -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))
|
||||
})
|
||||
},
|
||||
])
|
|
@ -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,
|
||||
})
|
|
@ -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 (/<em>/.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 () {})
|
|
@ -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',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
|
@ -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',
|
||||
})
|
||||
},
|
||||
])
|
|
@ -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
|
||||
})
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
})
|
|
@ -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
|
||||
},
|
||||
])
|
Loading…
Add table
Reference in a new issue