mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-29 21:53:46 -05:00
Merge pull request #856 from sharelatex/ns-use-regex-test
Use regex test instead of string match
This commit is contained in:
commit
6ee2a83885
20 changed files with 117 additions and 122 deletions
|
@ -217,8 +217,8 @@ module.exports = AuthenticationController =
|
||||||
value = if Object.keys(req.query).length > 0 then "#{req.path}?#{querystring.stringify(req.query)}" else "#{req.path}"
|
value = if Object.keys(req.query).length > 0 then "#{req.path}?#{querystring.stringify(req.query)}" else "#{req.path}"
|
||||||
if (
|
if (
|
||||||
req.session? &&
|
req.session? &&
|
||||||
!value.match(new RegExp('^\/(socket.io|js|stylesheets|img)\/.*$')) &&
|
!/^\/(socket.io|js|stylesheets|img)\/.*$/.test(value) &&
|
||||||
!value.match(new RegExp('^.*\.(png|jpeg|svg)$'))
|
!/^.*\.(png|jpeg|svg)$/.test(value)
|
||||||
)
|
)
|
||||||
req.session.postLoginRedirect = value
|
req.session.postLoginRedirect = value
|
||||||
|
|
||||||
|
|
|
@ -262,7 +262,7 @@ module.exports = CompileController =
|
||||||
if req.query?.pdfng
|
if req.query?.pdfng
|
||||||
newHeaders = {}
|
newHeaders = {}
|
||||||
for h, v of req.headers
|
for h, v of req.headers
|
||||||
newHeaders[h] = req.headers[h] if h.match /^(If-|Range)/i
|
newHeaders[h] = req.headers[h] if /^(If-|Range)/i.test(h)
|
||||||
options.headers = newHeaders
|
options.headers = newHeaders
|
||||||
proxy = request(options)
|
proxy = request(options)
|
||||||
proxy.pipe(res)
|
proxy.pipe(res)
|
||||||
|
|
|
@ -80,7 +80,7 @@ module.exports = ProjectFileAgent = {
|
||||||
path: source_entity_path
|
path: source_entity_path
|
||||||
}, (err, entity, type) ->
|
}, (err, entity, type) ->
|
||||||
if err?
|
if err?
|
||||||
if err.toString().match(/^not found.*/)
|
if /^not found.*/.test(err.toString())
|
||||||
err = new SourceFileNotFoundError()
|
err = new SourceFileNotFoundError()
|
||||||
return callback(err)
|
return callback(err)
|
||||||
callback(null, project, entity, type)
|
callback(null, project, entity, type)
|
||||||
|
|
|
@ -466,6 +466,6 @@ THEME_LIST = []
|
||||||
do generateThemeList = () ->
|
do generateThemeList = () ->
|
||||||
files = fs.readdirSync __dirname + '/../../../../public/js/' + PackageVersions.lib('ace')
|
files = fs.readdirSync __dirname + '/../../../../public/js/' + PackageVersions.lib('ace')
|
||||||
for file in files
|
for file in files
|
||||||
if file.slice(-2) == "js" and file.match(/^theme-/)
|
if file.slice(-2) == "js" and /^theme-/.test(file)
|
||||||
cleanName = file.slice(0,-3).slice(6)
|
cleanName = file.slice(0,-3).slice(6)
|
||||||
THEME_LIST.push cleanName
|
THEME_LIST.push cleanName
|
||||||
|
|
|
@ -294,7 +294,7 @@ module.exports = ProjectEntityMongoUpdateHandler = self =
|
||||||
# in the destination folder
|
# in the destination folder
|
||||||
self._checkValidElementName destEntity, entity.name, (err)->
|
self._checkValidElementName destEntity, entity.name, (err)->
|
||||||
return callback(err) if err?
|
return callback(err) if err?
|
||||||
if entityType.match(/folder/)
|
if /folder/.test(entityType)
|
||||||
logger.log destFolderPath: destFolderPath.fileSystem, folderPath: entityPath.fileSystem, "checking folder is not moving into child folder"
|
logger.log destFolderPath: destFolderPath.fileSystem, folderPath: entityPath.fileSystem, "checking folder is not moving into child folder"
|
||||||
isNestedFolder = destFolderPath.fileSystem.slice(0, entityPath.fileSystem.length) == entityPath.fileSystem
|
isNestedFolder = destFolderPath.fileSystem.slice(0, entityPath.fileSystem.length) == entityPath.fileSystem
|
||||||
if isNestedFolder
|
if isNestedFolder
|
||||||
|
|
|
@ -20,8 +20,8 @@ module.exports = ProjectRootDocManager =
|
||||||
# Previously /.*\\documentclass/ would totally lock up on lines of 500kb (data text files :()
|
# Previously /.*\\documentclass/ would totally lock up on lines of 500kb (data text files :()
|
||||||
# This regex will only look from the start of the line, including whitespace so will return quickly
|
# This regex will only look from the start of the line, including whitespace so will return quickly
|
||||||
# regardless of line length.
|
# regardless of line length.
|
||||||
match = line.match /^\s*\\documentclass/
|
match = /^\s*\\documentclass/.test(line)
|
||||||
isRootDoc = Path.extname(path).match(/\.R?tex$/) and match
|
isRootDoc = /\.R?tex$/.test(Path.extname(path)) and match
|
||||||
if isRootDoc
|
if isRootDoc
|
||||||
rootDocId = doc?._id
|
rootDocId = doc?._id
|
||||||
cb(rootDocId)
|
cb(rootDocId)
|
||||||
|
@ -31,4 +31,3 @@ module.exports = ProjectRootDocManager =
|
||||||
ProjectEntityUpdateHandler.setRootDoc project_id, root_doc_id, callback
|
ProjectEntityUpdateHandler.setRootDoc project_id, root_doc_id, callback
|
||||||
else
|
else
|
||||||
callback()
|
callback()
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# This file is shared between the frontend and server code of web, so that
|
# This file is shared between the frontend and server code of web, so that
|
||||||
# filename validation is the same in both implementations.
|
# filename validation is the same in both implementations.
|
||||||
# Both copies must be kept in sync:
|
# Both copies must be kept in sync:
|
||||||
# app/coffee/Features/Project/SafePath.coffee
|
# app/coffee/Features/Project/SafePath.coffee
|
||||||
# public/coffee/ide/directives/SafePath.coffee
|
# public/coffee/ide/directives/SafePath.coffee
|
||||||
|
@ -55,7 +55,7 @@ load = () ->
|
||||||
clean: (filename) ->
|
clean: (filename) ->
|
||||||
filename = filename.replace BADCHAR_RX, '_'
|
filename = filename.replace BADCHAR_RX, '_'
|
||||||
# for BADFILE_RX replace any matches with an equal number of underscores
|
# for BADFILE_RX replace any matches with an equal number of underscores
|
||||||
filename = filename.replace BADFILE_RX, (match) ->
|
filename = filename.replace BADFILE_RX, (match) ->
|
||||||
return new Array(match.length + 1).join("_")
|
return new Array(match.length + 1).join("_")
|
||||||
# replace blocked filenames 'prototype' with '@prototype'
|
# replace blocked filenames 'prototype' with '@prototype'
|
||||||
filename = filename.replace BLOCKEDFILE_RX, "@$1"
|
filename = filename.replace BLOCKEDFILE_RX, "@$1"
|
||||||
|
@ -63,9 +63,9 @@ load = () ->
|
||||||
|
|
||||||
isCleanFilename: (filename) ->
|
isCleanFilename: (filename) ->
|
||||||
return SafePath.isAllowedLength(filename) &&
|
return SafePath.isAllowedLength(filename) &&
|
||||||
not filename.match(BADCHAR_RX) &&
|
!BADCHAR_RX.test(filename) &&
|
||||||
not filename.match(BADFILE_RX) &&
|
!BADFILE_RX.test(filename) &&
|
||||||
not filename.match(BLOCKEDFILE_RX)
|
!BLOCKEDFILE_RX.test(filename)
|
||||||
|
|
||||||
isAllowedLength: (pathname) ->
|
isAllowedLength: (pathname) ->
|
||||||
return pathname.length > 0 && pathname.length <= MAX_PATH
|
return pathname.length > 0 && pathname.length <= MAX_PATH
|
||||||
|
@ -73,4 +73,4 @@ load = () ->
|
||||||
if define?
|
if define?
|
||||||
define [], load
|
define [], load
|
||||||
else
|
else
|
||||||
module.exports = load()
|
module.exports = load()
|
||||||
|
|
|
@ -22,9 +22,9 @@ module.exports = UserController =
|
||||||
getPersonalInfo: (req, res, next = (error) ->) ->
|
getPersonalInfo: (req, res, next = (error) ->) ->
|
||||||
{user_id} = req.params
|
{user_id} = req.params
|
||||||
|
|
||||||
if user_id.match(/^\d+$/)
|
if /^\d+$/.test(user_id)
|
||||||
query = { "overleaf.id": parseInt(user_id, 10) }
|
query = { "overleaf.id": parseInt(user_id, 10) }
|
||||||
else if user_id.match(/^[a-f0-9]{24}$/)
|
else if /^[a-f0-9]{24}$/.test(user_id)
|
||||||
query = { _id: ObjectId(user_id) }
|
query = { _id: ObjectId(user_id) }
|
||||||
else
|
else
|
||||||
return res.send(400)
|
return res.send(400)
|
||||||
|
|
|
@ -198,9 +198,9 @@ define [
|
||||||
userAgent = navigator.userAgent
|
userAgent = navigator.userAgent
|
||||||
ide.browserIsSafari = (
|
ide.browserIsSafari = (
|
||||||
userAgent &&
|
userAgent &&
|
||||||
userAgent.match(/.*Safari\/.*/) &&
|
/.*Safari\/.*/.test(userAgent) &&
|
||||||
!userAgent.match(/.*Chrome\/.*/) &&
|
!/.*Chrome\/.*/.test(userAgent) &&
|
||||||
!userAgent.match(/.*Chromium\/.*/)
|
!/.*Chromium\/.*/.test(userAgent)
|
||||||
)
|
)
|
||||||
catch err
|
catch err
|
||||||
console.error err
|
console.error err
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# This file is shared between the frontend and server code of web, so that
|
# This file is shared between the frontend and server code of web, so that
|
||||||
# filename validation is the same in both implementations.
|
# filename validation is the same in both implementations.
|
||||||
# Both copies must be kept in sync:
|
# Both copies must be kept in sync:
|
||||||
# app/coffee/Features/Project/SafePath.coffee
|
# app/coffee/Features/Project/SafePath.coffee
|
||||||
# public/coffee/ide/directives/SafePath.coffee
|
# public/coffee/ide/directives/SafePath.coffee
|
||||||
|
@ -55,17 +55,17 @@ load = () ->
|
||||||
clean: (filename) ->
|
clean: (filename) ->
|
||||||
filename = filename.replace BADCHAR_RX, '_'
|
filename = filename.replace BADCHAR_RX, '_'
|
||||||
# for BADFILE_RX replace any matches with an equal number of underscores
|
# for BADFILE_RX replace any matches with an equal number of underscores
|
||||||
filename = filename.replace BADFILE_RX, (match) ->
|
filename = filename.replace BADFILE_RX, (match) ->
|
||||||
return new Array(match.length + 1).join("_")
|
return new Array(match.length + 1).join("_")
|
||||||
# replace blocked filenames 'prototype' with '@prototype'
|
# replace blocked filenames 'prototype' with '@prototype'
|
||||||
filename = filename.replace BLOCKEDFILE_RX, "@$1"
|
filename = filename.replace BLOCKEDFILE_RX, "@$1"
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
isCleanFilename: (filename) ->
|
isCleanFilename: (filename) ->
|
||||||
return SafePath.isAllowedLength(filename) &&
|
return SafePath.isAllowedLength(filename) and
|
||||||
not filename.match(BADCHAR_RX) &&
|
not BADCHAR_RX.test(filename) and
|
||||||
not filename.match(BADFILE_RX) &&
|
not BADFILE_RX.test(filename) and
|
||||||
not filename.match(BLOCKEDFILE_RX)
|
not BLOCKEDFILE_RX.test(filename)
|
||||||
|
|
||||||
isAllowedLength: (pathname) ->
|
isAllowedLength: (pathname) ->
|
||||||
return pathname.length > 0 && pathname.length <= MAX_PATH
|
return pathname.length > 0 && pathname.length <= MAX_PATH
|
||||||
|
@ -73,4 +73,4 @@ load = () ->
|
||||||
if define?
|
if define?
|
||||||
define [], load
|
define [], load
|
||||||
else
|
else
|
||||||
module.exports = load()
|
module.exports = load()
|
||||||
|
|
|
@ -36,7 +36,7 @@ define [
|
||||||
|
|
||||||
@$scope.$on "flush-changes", () =>
|
@$scope.$on "flush-changes", () =>
|
||||||
Document.flushAll()
|
Document.flushAll()
|
||||||
|
|
||||||
@$scope.$watch "editor.wantTrackChanges", (value) =>
|
@$scope.$watch "editor.wantTrackChanges", (value) =>
|
||||||
return if !value?
|
return if !value?
|
||||||
@_syncTrackChangesState(@$scope.editor.sharejs_doc)
|
@_syncTrackChangesState(@$scope.editor.sharejs_doc)
|
||||||
|
@ -47,7 +47,7 @@ define [
|
||||||
@localStorage("editor.mode.#{@$scope.project_id}") == 'rich-text'
|
@localStorage("editor.mode.#{@$scope.project_id}") == 'rich-text'
|
||||||
|
|
||||||
autoOpenDoc: () ->
|
autoOpenDoc: () ->
|
||||||
open_doc_id =
|
open_doc_id =
|
||||||
@ide.localStorage("doc.open_id.#{@$scope.project_id}") or
|
@ide.localStorage("doc.open_id.#{@$scope.project_id}") or
|
||||||
@$scope.project.rootDoc_id
|
@$scope.project.rootDoc_id
|
||||||
return if !open_doc_id?
|
return if !open_doc_id?
|
||||||
|
@ -76,7 +76,7 @@ define [
|
||||||
setTimeout () =>
|
setTimeout () =>
|
||||||
@$scope.$broadcast "editor:gotoOffset", options.gotoOffset
|
@$scope.$broadcast "editor:gotoOffset", options.gotoOffset
|
||||||
, 0
|
, 0
|
||||||
|
|
||||||
|
|
||||||
if doc.id == @$scope.editor.open_doc_id and !options.forceReopen
|
if doc.id == @$scope.editor.open_doc_id and !options.forceReopen
|
||||||
@$scope.$apply () =>
|
@$scope.$apply () =>
|
||||||
|
@ -97,7 +97,7 @@ define [
|
||||||
"Sorry, something went wrong opening this document. Please try again."
|
"Sorry, something went wrong opening this document. Please try again."
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@_syncTrackChangesState(sharejs_doc)
|
@_syncTrackChangesState(sharejs_doc)
|
||||||
|
|
||||||
@$scope.$broadcast "doc:opened"
|
@$scope.$broadcast "doc:opened"
|
||||||
|
@ -131,12 +131,12 @@ define [
|
||||||
message = error
|
message = error
|
||||||
else
|
else
|
||||||
message = ""
|
message = ""
|
||||||
if message.match "maxDocLength"
|
if /maxDocLength/.test(message)
|
||||||
@ide.showGenericMessageModal(
|
@ide.showGenericMessageModal(
|
||||||
"Document Too Long"
|
"Document Too Long"
|
||||||
"Sorry, this file is too long to be edited manually. Please upload it directly."
|
"Sorry, this file is too long to be edited manually. Please upload it directly."
|
||||||
)
|
)
|
||||||
else if message.match "too many comments or tracked changes"
|
else if /too many comments or tracked changes/.test(message)
|
||||||
@ide.showGenericMessageModal(
|
@ide.showGenericMessageModal(
|
||||||
"Too many comments or tracked changes"
|
"Too many comments or tracked changes"
|
||||||
"Sorry, this file has too many comments or tracked changes. Please try accepting or rejecting some existing changes, or resolving and deleting some comments."
|
"Sorry, this file has too many comments or tracked changes. Please try accepting or rejecting some existing changes, or resolving and deleting some comments."
|
||||||
|
@ -165,13 +165,13 @@ define [
|
||||||
|
|
||||||
getCurrentDocId: () ->
|
getCurrentDocId: () ->
|
||||||
@$scope.editor.open_doc_id
|
@$scope.editor.open_doc_id
|
||||||
|
|
||||||
startIgnoringExternalUpdates: () ->
|
startIgnoringExternalUpdates: () ->
|
||||||
@_ignoreExternalUpdates = true
|
@_ignoreExternalUpdates = true
|
||||||
|
|
||||||
stopIgnoringExternalUpdates: () ->
|
stopIgnoringExternalUpdates: () ->
|
||||||
@_ignoreExternalUpdates = false
|
@_ignoreExternalUpdates = false
|
||||||
|
|
||||||
_syncTimeout: null
|
_syncTimeout: null
|
||||||
_syncTrackChangesState: (doc) ->
|
_syncTrackChangesState: (doc) ->
|
||||||
return if !doc?
|
return if !doc?
|
||||||
|
|
|
@ -416,10 +416,10 @@ define [
|
||||||
# see if we can lookup a suitable mode from ace
|
# see if we can lookup a suitable mode from ace
|
||||||
# but fall back to text by default
|
# but fall back to text by default
|
||||||
try
|
try
|
||||||
if scope.fileName.match(/\.(Rtex|bbl)$/i)
|
if /\.(Rtex|bbl)$/i.test(scope.fileName)
|
||||||
# recognise Rtex and bbl as latex
|
# recognise Rtex and bbl as latex
|
||||||
mode = "ace/mode/latex"
|
mode = "ace/mode/latex"
|
||||||
else if scope.fileName.match(/\.(sty|cls|clo)$/)
|
else if /\.(sty|cls|clo)$/.test(scope.fileName)
|
||||||
# recognise some common files as tex
|
# recognise some common files as tex
|
||||||
mode = "ace/mode/tex"
|
mode = "ace/mode/tex"
|
||||||
else
|
else
|
||||||
|
@ -437,7 +437,7 @@ define [
|
||||||
|
|
||||||
session.setUseWrapMode(true)
|
session.setUseWrapMode(true)
|
||||||
# use syntax validation only when explicitly set
|
# use syntax validation only when explicitly set
|
||||||
if scope.syntaxValidation? and syntaxValidationEnabled and !scope.fileName.match(/\.bib$/)
|
if scope.syntaxValidation? and syntaxValidationEnabled and !/\.bib$/.test(scope.fileName)
|
||||||
session.setOption("useWorker", scope.syntaxValidation);
|
session.setOption("useWorker", scope.syntaxValidation);
|
||||||
|
|
||||||
# now attach session to editor
|
# now attach session to editor
|
||||||
|
|
|
@ -163,12 +163,11 @@ define [
|
||||||
end = change.end
|
end = change.end
|
||||||
{lineUpToCursor, commandFragment} = Helpers.getContext(@editor, end)
|
{lineUpToCursor, commandFragment} = Helpers.getContext(@editor, end)
|
||||||
if ((i = lineUpToCursor.indexOf('%')) > -1 and lineUpToCursor[i-1] != '\\')
|
if ((i = lineUpToCursor.indexOf('%')) > -1 and lineUpToCursor[i-1] != '\\')
|
||||||
console.log lineUpToCursor, i
|
|
||||||
return
|
return
|
||||||
lastCharIsBackslash = lineUpToCursor.slice(-1) == "\\"
|
lastCharIsBackslash = lineUpToCursor.slice(-1) == "\\"
|
||||||
lastTwoChars = lineUpToCursor.slice(-2)
|
lastTwoChars = lineUpToCursor.slice(-2)
|
||||||
# Don't offer autocomplete on double-backslash, backslash-colon, etc
|
# Don't offer autocomplete on double-backslash, backslash-colon, etc
|
||||||
if lastTwoChars.match(/^\\[^a-zA-Z]$/)
|
if /^\\[^a-zA-Z]$/.test(lastTwoChars)
|
||||||
@editor?.completer?.detach?()
|
@editor?.completer?.detach?()
|
||||||
return
|
return
|
||||||
# Check that this change was made by us, not a collaborator
|
# Check that this change was made by us, not a collaborator
|
||||||
|
@ -185,8 +184,8 @@ define [
|
||||||
, 0
|
, 0
|
||||||
if (
|
if (
|
||||||
change.action == "insert" and
|
change.action == "insert" and
|
||||||
change.lines[0].match(/\\(\w+){}/)?[1].match(
|
/(begin|end|[a-z]*ref|usepackage|[a-z]*cite[a-z]*|input|include)/.test(
|
||||||
/(begin|end|[a-z]*ref|usepackage|[a-z]*cite[a-z]*|input|include)/
|
change.lines[0].match(/\\(\w+){}/)?[1]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
setTimeout () =>
|
setTimeout () =>
|
||||||
|
@ -209,7 +208,7 @@ define [
|
||||||
|
|
||||||
# If we are in \begin{it|}, then we need to remove the trailing }
|
# If we are in \begin{it|}, then we need to remove the trailing }
|
||||||
# since it will be adding in with the autocomplete of \begin{item}...
|
# since it will be adding in with the autocomplete of \begin{item}...
|
||||||
if this.completions.filterText.match(/^\\\w+{/) and nextChar == "}"
|
if /^\\\w+{/.test(this.completions.filterText) and nextChar == "}"
|
||||||
editor.session.remove(range)
|
editor.session.remove(range)
|
||||||
|
|
||||||
# Provide our own `insertMatch` implementation.
|
# Provide our own `insertMatch` implementation.
|
||||||
|
|
|
@ -6,41 +6,41 @@ define [
|
||||||
], (_, EventEmitter, ColorManager, AceShareJsCodec) ->
|
], (_, EventEmitter, ColorManager, AceShareJsCodec) ->
|
||||||
class TrackChangesManager
|
class TrackChangesManager
|
||||||
Range = ace.require("ace/range").Range
|
Range = ace.require("ace/range").Range
|
||||||
|
|
||||||
constructor: (@$scope, @editor, @element) ->
|
constructor: (@$scope, @editor, @element) ->
|
||||||
window.trackChangesManager ?= @
|
window.trackChangesManager ?= @
|
||||||
|
|
||||||
@$scope.$watch "trackChanges", (track_changes) =>
|
@$scope.$watch "trackChanges", (track_changes) =>
|
||||||
return if !track_changes?
|
return if !track_changes?
|
||||||
@setTrackChanges(track_changes)
|
@setTrackChanges(track_changes)
|
||||||
|
|
||||||
@$scope.$watch "sharejsDoc", (doc, oldDoc) =>
|
@$scope.$watch "sharejsDoc", (doc, oldDoc) =>
|
||||||
return if !doc?
|
return if !doc?
|
||||||
if oldDoc?
|
if oldDoc?
|
||||||
@disconnectFromDoc(oldDoc)
|
@disconnectFromDoc(oldDoc)
|
||||||
@connectToDoc(doc)
|
@connectToDoc(doc)
|
||||||
|
|
||||||
@$scope.$on "comment:add", (e, thread_id, offset, length) =>
|
@$scope.$on "comment:add", (e, thread_id, offset, length) =>
|
||||||
@addCommentToSelection(thread_id, offset, length)
|
@addCommentToSelection(thread_id, offset, length)
|
||||||
|
|
||||||
@$scope.$on "comment:select_line", (e) =>
|
@$scope.$on "comment:select_line", (e) =>
|
||||||
@selectLineIfNoSelection()
|
@selectLineIfNoSelection()
|
||||||
|
|
||||||
@$scope.$on "changes:accept", (e, change_ids) =>
|
@$scope.$on "changes:accept", (e, change_ids) =>
|
||||||
@acceptChangeIds(change_ids)
|
@acceptChangeIds(change_ids)
|
||||||
|
|
||||||
@$scope.$on "changes:reject", (e, change_ids) =>
|
@$scope.$on "changes:reject", (e, change_ids) =>
|
||||||
@rejectChangeIds(change_ids)
|
@rejectChangeIds(change_ids)
|
||||||
|
|
||||||
@$scope.$on "comment:remove", (e, comment_id) =>
|
@$scope.$on "comment:remove", (e, comment_id) =>
|
||||||
@removeCommentId(comment_id)
|
@removeCommentId(comment_id)
|
||||||
|
|
||||||
@$scope.$on "comment:resolve_threads", (e, thread_ids) =>
|
@$scope.$on "comment:resolve_threads", (e, thread_ids) =>
|
||||||
@hideCommentsByThreadIds(thread_ids)
|
@hideCommentsByThreadIds(thread_ids)
|
||||||
|
|
||||||
@$scope.$on "comment:unresolve_thread", (e, thread_id) =>
|
@$scope.$on "comment:unresolve_thread", (e, thread_id) =>
|
||||||
@showCommentByThreadId(thread_id)
|
@showCommentByThreadId(thread_id)
|
||||||
|
|
||||||
@$scope.$on "review-panel:recalculate-screen-positions", () =>
|
@$scope.$on "review-panel:recalculate-screen-positions", () =>
|
||||||
@recalculateReviewEntriesScreenPositions()
|
@recalculateReviewEntriesScreenPositions()
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ define [
|
||||||
@$scope.$evalAsync () =>
|
@$scope.$evalAsync () =>
|
||||||
changingSelection = false
|
changingSelection = false
|
||||||
@updateFocus()
|
@updateFocus()
|
||||||
|
|
||||||
onResize = () =>
|
onResize = () =>
|
||||||
@recalculateReviewEntriesScreenPositions()
|
@recalculateReviewEntriesScreenPositions()
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ define [
|
||||||
bindToAce()
|
bindToAce()
|
||||||
else
|
else
|
||||||
unbindFromAce()
|
unbindFromAce()
|
||||||
|
|
||||||
disconnectFromDoc: (doc) ->
|
disconnectFromDoc: (doc) ->
|
||||||
@changeIdToMarkerIdMap = {}
|
@changeIdToMarkerIdMap = {}
|
||||||
doc.off "ranges:clear"
|
doc.off "ranges:clear"
|
||||||
|
@ -111,18 +111,18 @@ define [
|
||||||
@$scope.sharejsDoc?.track_changes_as = window.user.id or "anonymous"
|
@$scope.sharejsDoc?.track_changes_as = window.user.id or "anonymous"
|
||||||
else
|
else
|
||||||
@$scope.sharejsDoc?.track_changes_as = null
|
@$scope.sharejsDoc?.track_changes_as = null
|
||||||
|
|
||||||
connectToDoc: (doc) ->
|
connectToDoc: (doc) ->
|
||||||
@rangesTracker = doc.ranges
|
@rangesTracker = doc.ranges
|
||||||
@setTrackChanges(@$scope.trackChanges)
|
@setTrackChanges(@$scope.trackChanges)
|
||||||
|
|
||||||
doc.on "ranges:dirty", () =>
|
doc.on "ranges:dirty", () =>
|
||||||
@updateAnnotations()
|
@updateAnnotations()
|
||||||
doc.on "ranges:clear", () =>
|
doc.on "ranges:clear", () =>
|
||||||
@clearAnnotations()
|
@clearAnnotations()
|
||||||
doc.on "ranges:redraw", () =>
|
doc.on "ranges:redraw", () =>
|
||||||
@redrawAnnotations()
|
@redrawAnnotations()
|
||||||
|
|
||||||
clearAnnotations: () ->
|
clearAnnotations: () ->
|
||||||
session = @editor.getSession()
|
session = @editor.getSession()
|
||||||
for change_id, markers of @changeIdToMarkerIdMap
|
for change_id, markers of @changeIdToMarkerIdMap
|
||||||
|
@ -139,9 +139,9 @@ define [
|
||||||
|
|
||||||
for comment in @rangesTracker.comments
|
for comment in @rangesTracker.comments
|
||||||
@_onCommentAdded(comment)
|
@_onCommentAdded(comment)
|
||||||
|
|
||||||
@broadcastChange()
|
@broadcastChange()
|
||||||
|
|
||||||
_doneUpdateThisLoop: false
|
_doneUpdateThisLoop: false
|
||||||
_pendingUpdates: false
|
_pendingUpdates: false
|
||||||
updateAnnotations: () ->
|
updateAnnotations: () ->
|
||||||
|
@ -161,9 +161,9 @@ define [
|
||||||
|
|
||||||
_doUpdateAnnotations: () ->
|
_doUpdateAnnotations: () ->
|
||||||
dirty = @rangesTracker.getDirtyState()
|
dirty = @rangesTracker.getDirtyState()
|
||||||
|
|
||||||
updateMarkers = false
|
updateMarkers = false
|
||||||
|
|
||||||
for id, change of dirty.change.added
|
for id, change of dirty.change.added
|
||||||
if change.op.i?
|
if change.op.i?
|
||||||
@_onInsertAdded(change)
|
@_onInsertAdded(change)
|
||||||
|
@ -177,7 +177,7 @@ define [
|
||||||
for id, change of dirty.change.moved
|
for id, change of dirty.change.moved
|
||||||
updateMarkers = true
|
updateMarkers = true
|
||||||
@_onChangeMoved(change)
|
@_onChangeMoved(change)
|
||||||
|
|
||||||
for id, comment of dirty.comment.added
|
for id, comment of dirty.comment.added
|
||||||
@_onCommentAdded(comment)
|
@_onCommentAdded(comment)
|
||||||
for id, comment of dirty.comment.removed
|
for id, comment of dirty.comment.removed
|
||||||
|
@ -185,7 +185,7 @@ define [
|
||||||
for id, comment of dirty.comment.moved
|
for id, comment of dirty.comment.moved
|
||||||
updateMarkers = true
|
updateMarkers = true
|
||||||
@_onCommentMoved(comment)
|
@_onCommentMoved(comment)
|
||||||
|
|
||||||
@rangesTracker.resetDirtyState()
|
@rangesTracker.resetDirtyState()
|
||||||
if updateMarkers
|
if updateMarkers
|
||||||
@editor.renderer.updateBackMarkers()
|
@editor.renderer.updateBackMarkers()
|
||||||
|
@ -195,18 +195,18 @@ define [
|
||||||
op = { c: content, p: offset, t: thread_id }
|
op = { c: content, p: offset, t: thread_id }
|
||||||
# @rangesTracker.applyOp op # Will apply via sharejs
|
# @rangesTracker.applyOp op # Will apply via sharejs
|
||||||
@$scope.sharejsDoc.submitOp op
|
@$scope.sharejsDoc.submitOp op
|
||||||
|
|
||||||
addCommentToSelection: (thread_id, offset, length) ->
|
addCommentToSelection: (thread_id, offset, length) ->
|
||||||
start = @_shareJsOffsetToAcePosition(offset)
|
start = @_shareJsOffsetToAcePosition(offset)
|
||||||
end = @_shareJsOffsetToAcePosition(offset + length)
|
end = @_shareJsOffsetToAcePosition(offset + length)
|
||||||
range = new Range(start.row, start.column, end.row, end.column)
|
range = new Range(start.row, start.column, end.row, end.column)
|
||||||
content = @editor.session.getTextRange(range)
|
content = @editor.session.getTextRange(range)
|
||||||
@addComment(offset, content, thread_id)
|
@addComment(offset, content, thread_id)
|
||||||
|
|
||||||
selectLineIfNoSelection: () ->
|
selectLineIfNoSelection: () ->
|
||||||
if @editor.selection.isEmpty()
|
if @editor.selection.isEmpty()
|
||||||
@editor.selection.selectLine()
|
@editor.selection.selectLine()
|
||||||
|
|
||||||
acceptChangeIds: (change_ids) ->
|
acceptChangeIds: (change_ids) ->
|
||||||
@rangesTracker.removeChangeIds(change_ids)
|
@rangesTracker.removeChangeIds(change_ids)
|
||||||
@updateAnnotations()
|
@updateAnnotations()
|
||||||
|
@ -225,12 +225,12 @@ define [
|
||||||
#
|
#
|
||||||
# foo quux baz
|
# foo quux baz
|
||||||
# |--| -> insertion of "quux", op 1, at position 4
|
# |--| -> insertion of "quux", op 1, at position 4
|
||||||
# | -> deletion of "bar", op 2, pushed forward by "quux" to position 8
|
# | -> deletion of "bar", op 2, pushed forward by "quux" to position 8
|
||||||
#
|
#
|
||||||
# When rejecting these changes at once, if the insertion is rejected first, we get unexpected
|
# When rejecting these changes at once, if the insertion is rejected first, we get unexpected
|
||||||
# results. What happens is:
|
# results. What happens is:
|
||||||
#
|
#
|
||||||
# 1) Rejecting the insertion deletes the added word "quux", i.e., it removes 4 chars
|
# 1) Rejecting the insertion deletes the added word "quux", i.e., it removes 4 chars
|
||||||
# starting from position 4;
|
# starting from position 4;
|
||||||
#
|
#
|
||||||
# "foo quux baz" -> "foo baz"
|
# "foo quux baz" -> "foo baz"
|
||||||
|
@ -247,27 +247,27 @@ define [
|
||||||
# "foo bazbar" (note "bar" readded at position 8)
|
# "foo bazbar" (note "bar" readded at position 8)
|
||||||
#
|
#
|
||||||
# The issue happens because of step 1. To revert the insertion of "quux", 4 characters are deleted
|
# The issue happens because of step 1. To revert the insertion of "quux", 4 characters are deleted
|
||||||
# from position 4. This includes the position where the deletion exists; when that position is
|
# from position 4. This includes the position where the deletion exists; when that position is
|
||||||
# cleared, the RangesTracker considers that the deletion is gone and stops tracking/updating it.
|
# cleared, the RangesTracker considers that the deletion is gone and stops tracking/updating it.
|
||||||
# As we still hold a reference to it, the code tries to revert it by readding the deleted text, but
|
# As we still hold a reference to it, the code tries to revert it by readding the deleted text, but
|
||||||
# does so at the outdated position (position 8, which was valid when "quux" was present).
|
# does so at the outdated position (position 8, which was valid when "quux" was present).
|
||||||
#
|
#
|
||||||
# To avoid this kind of problem, we need to make sure that reverting operations doesn't affect
|
# To avoid this kind of problem, we need to make sure that reverting operations doesn't affect
|
||||||
# subsequent operations that come after. Reverse sorting the operations based on position will
|
# subsequent operations that come after. Reverse sorting the operations based on position will
|
||||||
# achieve it; in the case above, it makes sure that the the deletion is reverted first:
|
# achieve it; in the case above, it makes sure that the the deletion is reverted first:
|
||||||
#
|
#
|
||||||
# 1) Rejecting the deletion adds the deleted word "bar" at position 8
|
# 1) Rejecting the deletion adds the deleted word "bar" at position 8
|
||||||
#
|
#
|
||||||
# "foo quux baz" -> "foo quuxbar baz"
|
# "foo quux baz" -> "foo quuxbar baz"
|
||||||
# | -> deletion of "bar" is reverted by
|
# | -> deletion of "bar" is reverted by
|
||||||
# reinserting "bar" at position 8
|
# reinserting "bar" at position 8
|
||||||
#
|
#
|
||||||
# 2) Rejecting the insertion deletes the added word "quux", i.e., it removes 4 chars
|
# 2) Rejecting the insertion deletes the added word "quux", i.e., it removes 4 chars
|
||||||
# starting from position 4 and achieves the expected result:
|
# starting from position 4 and achieves the expected result:
|
||||||
#
|
#
|
||||||
# "foo quuxbar baz" -> "foo bar baz"
|
# "foo quuxbar baz" -> "foo bar baz"
|
||||||
# |--| -> 4 characters to be removed
|
# |--| -> 4 characters to be removed
|
||||||
|
|
||||||
changes.sort((a, b) -> b.op.p - a.op.p)
|
changes.sort((a, b) -> b.op.p - a.op.p)
|
||||||
|
|
||||||
session = @editor.getSession()
|
session = @editor.getSession()
|
||||||
|
@ -303,7 +303,7 @@ define [
|
||||||
if resolve_ids[comment.op.t]
|
if resolve_ids[comment.op.t]
|
||||||
@_onCommentRemoved(comment)
|
@_onCommentRemoved(comment)
|
||||||
@broadcastChange()
|
@broadcastChange()
|
||||||
|
|
||||||
showCommentByThreadId: (thread_id) ->
|
showCommentByThreadId: (thread_id) ->
|
||||||
for comment in @rangesTracker?.comments or []
|
for comment in @rangesTracker?.comments or []
|
||||||
if comment.op.t == thread_id
|
if comment.op.t == thread_id
|
||||||
|
@ -339,7 +339,7 @@ define [
|
||||||
return if change.action != "insert"
|
return if change.action != "insert"
|
||||||
pasted_text = change.lines.join("\n")
|
pasted_text = change.lines.join("\n")
|
||||||
paste_offset = @_aceRangeToShareJs(change.start)
|
paste_offset = @_aceRangeToShareJs(change.start)
|
||||||
# We have to wait until the change has been processed by the range tracker,
|
# We have to wait until the change has been processed by the range tracker,
|
||||||
# since if we move the ops into place beforehand, they will be moved again
|
# since if we move the ops into place beforehand, they will be moved again
|
||||||
# when the changes are processed by the range tracker. This ranges:dirty
|
# when the changes are processed by the range tracker. This ranges:dirty
|
||||||
# event is fired after the doc has applied the changes to the range tracker.
|
# event is fired after the doc has applied the changes to the range tracker.
|
||||||
|
@ -374,7 +374,7 @@ define [
|
||||||
end = start
|
end = start
|
||||||
expected_markers.push { marker_id: background_marker_id, start, end }
|
expected_markers.push { marker_id: background_marker_id, start, end }
|
||||||
expected_markers.push { marker_id: callout_marker_id, start, end: start }
|
expected_markers.push { marker_id: callout_marker_id, start, end: start }
|
||||||
|
|
||||||
for comment in @rangesTracker.comments
|
for comment in @rangesTracker.comments
|
||||||
if @changeIdToMarkerIdMap[comment.id]?
|
if @changeIdToMarkerIdMap[comment.id]?
|
||||||
{background_marker_id, callout_marker_id} = @changeIdToMarkerIdMap[comment.id]
|
{background_marker_id, callout_marker_id} = @changeIdToMarkerIdMap[comment.id]
|
||||||
|
@ -382,7 +382,7 @@ define [
|
||||||
end = @_shareJsOffsetToAcePosition(comment.op.p + comment.op.c.length)
|
end = @_shareJsOffsetToAcePosition(comment.op.p + comment.op.c.length)
|
||||||
expected_markers.push { marker_id: background_marker_id, start, end }
|
expected_markers.push { marker_id: background_marker_id, start, end }
|
||||||
expected_markers.push { marker_id: callout_marker_id, start, end: start }
|
expected_markers.push { marker_id: callout_marker_id, start, end: start }
|
||||||
|
|
||||||
for {marker_id, start, end} in expected_markers
|
for {marker_id, start, end} in expected_markers
|
||||||
marker = markers[marker_id]
|
marker = markers[marker_id]
|
||||||
delete markers[marker_id]
|
delete markers[marker_id]
|
||||||
|
@ -391,11 +391,11 @@ define [
|
||||||
marker.range.end.row != end.row or
|
marker.range.end.row != end.row or
|
||||||
marker.range.end.column != end.column
|
marker.range.end.column != end.column
|
||||||
console.error "Change doesn't match marker anymore", {change, marker, start, end}
|
console.error "Change doesn't match marker anymore", {change, marker, start, end}
|
||||||
|
|
||||||
for marker_id, marker of markers
|
for marker_id, marker of markers
|
||||||
if marker.clazz.match("track-changes")
|
if /track-changes/.test(marker.clazz)
|
||||||
console.error "Orphaned ace marker", marker
|
console.error "Orphaned ace marker", marker
|
||||||
|
|
||||||
updateFocus: () ->
|
updateFocus: () ->
|
||||||
selection = @editor.getSelectionRange()
|
selection = @editor.getSelectionRange()
|
||||||
selection_start = @_aceRangeToShareJs(selection.start)
|
selection_start = @_aceRangeToShareJs(selection.start)
|
||||||
|
@ -403,10 +403,10 @@ define [
|
||||||
entries = @_getCurrentDocEntries()
|
entries = @_getCurrentDocEntries()
|
||||||
is_selection = (selection_start != selection_end)
|
is_selection = (selection_start != selection_end)
|
||||||
@$scope.$emit "editor:focus:changed", selection_start, selection_end, is_selection
|
@$scope.$emit "editor:focus:changed", selection_start, selection_end, is_selection
|
||||||
|
|
||||||
broadcastChange: () ->
|
broadcastChange: () ->
|
||||||
@$scope.$emit "editor:track-changes:changed", @$scope.docId
|
@$scope.$emit "editor:track-changes:changed", @$scope.docId
|
||||||
|
|
||||||
recalculateReviewEntriesScreenPositions: () ->
|
recalculateReviewEntriesScreenPositions: () ->
|
||||||
session = @editor.getSession()
|
session = @editor.getSession()
|
||||||
renderer = @editor.renderer
|
renderer = @editor.renderer
|
||||||
|
@ -455,7 +455,7 @@ define [
|
||||||
first_row > @end.row or last_row < @start.row
|
first_row > @end.row or last_row < @start.row
|
||||||
return @
|
return @
|
||||||
return ace_range
|
return ace_range
|
||||||
|
|
||||||
_createCalloutMarker: (position, klass) ->
|
_createCalloutMarker: (position, klass) ->
|
||||||
session = @editor.getSession()
|
session = @editor.getSession()
|
||||||
callout_range = @_makeZeroWidthRange(position)
|
callout_range = @_makeZeroWidthRange(position)
|
||||||
|
@ -486,21 +486,21 @@ define [
|
||||||
|
|
||||||
callout_marker_id = @_createCalloutMarker(position, "track-changes-deleted-marker-callout")
|
callout_marker_id = @_createCalloutMarker(position, "track-changes-deleted-marker-callout")
|
||||||
@changeIdToMarkerIdMap[change.id] = { background_marker_id, callout_marker_id }
|
@changeIdToMarkerIdMap[change.id] = { background_marker_id, callout_marker_id }
|
||||||
|
|
||||||
_onInsertRemoved: (change) ->
|
_onInsertRemoved: (change) ->
|
||||||
{background_marker_id, callout_marker_id} = @changeIdToMarkerIdMap[change.id]
|
{background_marker_id, callout_marker_id} = @changeIdToMarkerIdMap[change.id]
|
||||||
delete @changeIdToMarkerIdMap[change.id]
|
delete @changeIdToMarkerIdMap[change.id]
|
||||||
session = @editor.getSession()
|
session = @editor.getSession()
|
||||||
session.removeMarker background_marker_id
|
session.removeMarker background_marker_id
|
||||||
session.removeMarker callout_marker_id
|
session.removeMarker callout_marker_id
|
||||||
|
|
||||||
_onDeleteRemoved: (change) ->
|
_onDeleteRemoved: (change) ->
|
||||||
{background_marker_id, callout_marker_id} = @changeIdToMarkerIdMap[change.id]
|
{background_marker_id, callout_marker_id} = @changeIdToMarkerIdMap[change.id]
|
||||||
delete @changeIdToMarkerIdMap[change.id]
|
delete @changeIdToMarkerIdMap[change.id]
|
||||||
session = @editor.getSession()
|
session = @editor.getSession()
|
||||||
session.removeMarker background_marker_id
|
session.removeMarker background_marker_id
|
||||||
session.removeMarker callout_marker_id
|
session.removeMarker callout_marker_id
|
||||||
|
|
||||||
_onCommentAdded: (comment) ->
|
_onCommentAdded: (comment) ->
|
||||||
if @rangesTracker.resolvedThreadIds[comment.op.t]
|
if @rangesTracker.resolvedThreadIds[comment.op.t]
|
||||||
# Comment is resolved so shouldn't be displayed.
|
# Comment is resolved so shouldn't be displayed.
|
||||||
|
@ -515,7 +515,7 @@ define [
|
||||||
background_marker_id = session.addMarker background_range, "track-changes-marker track-changes-comment-marker", "text"
|
background_marker_id = session.addMarker background_range, "track-changes-marker track-changes-comment-marker", "text"
|
||||||
callout_marker_id = @_createCalloutMarker(start, "track-changes-comment-marker-callout")
|
callout_marker_id = @_createCalloutMarker(start, "track-changes-comment-marker-callout")
|
||||||
@changeIdToMarkerIdMap[comment.id] = { background_marker_id, callout_marker_id }
|
@changeIdToMarkerIdMap[comment.id] = { background_marker_id, callout_marker_id }
|
||||||
|
|
||||||
_onCommentRemoved: (comment) ->
|
_onCommentRemoved: (comment) ->
|
||||||
if @changeIdToMarkerIdMap[comment.id]?
|
if @changeIdToMarkerIdMap[comment.id]?
|
||||||
# Resolved comments may not have marker ids
|
# Resolved comments may not have marker ids
|
||||||
|
@ -532,11 +532,11 @@ define [
|
||||||
_aceChangeToShareJs: (delta) ->
|
_aceChangeToShareJs: (delta) ->
|
||||||
lines = @editor.getSession().getDocument().getLines 0, delta.start.row
|
lines = @editor.getSession().getDocument().getLines 0, delta.start.row
|
||||||
return AceShareJsCodec.aceChangeToShareJs(delta, lines)
|
return AceShareJsCodec.aceChangeToShareJs(delta, lines)
|
||||||
|
|
||||||
_shareJsOffsetToAcePosition: (offset) ->
|
_shareJsOffsetToAcePosition: (offset) ->
|
||||||
lines = @editor.getSession().getDocument().getAllLines()
|
lines = @editor.getSession().getDocument().getAllLines()
|
||||||
return AceShareJsCodec.shareJsOffsetToAcePosition(offset, lines)
|
return AceShareJsCodec.shareJsOffsetToAcePosition(offset, lines)
|
||||||
|
|
||||||
_onChangeMoved: (change) ->
|
_onChangeMoved: (change) ->
|
||||||
start = @_shareJsOffsetToAcePosition(change.op.p)
|
start = @_shareJsOffsetToAcePosition(change.op.p)
|
||||||
if change.op.i?
|
if change.op.i?
|
||||||
|
@ -544,12 +544,12 @@ define [
|
||||||
else
|
else
|
||||||
end = start
|
end = start
|
||||||
@_updateMarker(change.id, start, end)
|
@_updateMarker(change.id, start, end)
|
||||||
|
|
||||||
_onCommentMoved: (comment) ->
|
_onCommentMoved: (comment) ->
|
||||||
start = @_shareJsOffsetToAcePosition(comment.op.p)
|
start = @_shareJsOffsetToAcePosition(comment.op.p)
|
||||||
end = @_shareJsOffsetToAcePosition(comment.op.p + comment.op.c.length)
|
end = @_shareJsOffsetToAcePosition(comment.op.p + comment.op.c.length)
|
||||||
@_updateMarker(comment.id, start, end)
|
@_updateMarker(comment.id, start, end)
|
||||||
|
|
||||||
_updateMarker: (change_id, start, end) ->
|
_updateMarker: (change_id, start, end) ->
|
||||||
return if !@changeIdToMarkerIdMap[change_id]?
|
return if !@changeIdToMarkerIdMap[change_id]?
|
||||||
session = @editor.getSession()
|
session = @editor.getSession()
|
||||||
|
@ -563,4 +563,3 @@ define [
|
||||||
callout_marker = markers[callout_marker_id]
|
callout_marker = markers[callout_marker_id]
|
||||||
callout_marker.range.start = start
|
callout_marker.range.start = start
|
||||||
callout_marker.range.end = start
|
callout_marker.range.end = start
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@ module.exports = PgDb = (options) ->
|
||||||
client.query sql, values, (error, result) ->
|
client.query sql, values, (error, result) ->
|
||||||
if !error?
|
if !error?
|
||||||
callback?()
|
callback?()
|
||||||
else if error.toString().match "duplicate key value violates unique constraint"
|
else if /duplicate key value violates unique constraint/.test(error.toString())
|
||||||
callback? "Document already exists"
|
callback? "Document already exists"
|
||||||
else
|
else
|
||||||
callback? error?.message
|
callback? error?.message
|
||||||
|
|
|
@ -177,7 +177,7 @@ module.exports = Model = (db, options) ->
|
||||||
# The callback is called with the version of the document at which the op was applied.
|
# The callback is called with the version of the document at which the op was applied.
|
||||||
# This is the op.v after transformation, and its doc.v - 1.
|
# This is the op.v after transformation, and its doc.v - 1.
|
||||||
callback null, opData.v
|
callback null, opData.v
|
||||||
|
|
||||||
# I need a decent strategy here for deciding whether or not to save the snapshot.
|
# I need a decent strategy here for deciding whether or not to save the snapshot.
|
||||||
#
|
#
|
||||||
# The 'right' strategy looks something like "Store the snapshot whenever the snapshot
|
# The 'right' strategy looks something like "Store the snapshot whenever the snapshot
|
||||||
|
@ -219,13 +219,13 @@ module.exports = Model = (db, options) ->
|
||||||
dbMeta: dbMeta
|
dbMeta: dbMeta
|
||||||
|
|
||||||
doc.opQueue = makeOpQueue docName, doc
|
doc.opQueue = makeOpQueue docName, doc
|
||||||
|
|
||||||
refreshReapingTimeout docName
|
refreshReapingTimeout docName
|
||||||
model.emit 'add', docName, data
|
model.emit 'add', docName, data
|
||||||
callback null, doc for callback in callbacks if callbacks
|
callback null, doc for callback in callbacks if callbacks
|
||||||
|
|
||||||
doc
|
doc
|
||||||
|
|
||||||
# This is a little helper wrapper around db.getOps. It does two things:
|
# This is a little helper wrapper around db.getOps. It does two things:
|
||||||
#
|
#
|
||||||
# - If there's no database set, it returns an error to the callback
|
# - If there's no database set, it returns an error to the callback
|
||||||
|
@ -371,7 +371,7 @@ module.exports = Model = (db, options) ->
|
||||||
@create = (docName, type, meta, callback) ->
|
@create = (docName, type, meta, callback) ->
|
||||||
[meta, callback] = [{}, meta] if typeof meta is 'function'
|
[meta, callback] = [{}, meta] if typeof meta is 'function'
|
||||||
|
|
||||||
return callback? 'Invalid document name' if docName.match /\//
|
return callback? 'Invalid document name' if /\//.test(docName)
|
||||||
return callback? 'Document already exists' if docs[docName]
|
return callback? 'Document already exists' if docs[docName]
|
||||||
|
|
||||||
type = types[type] if typeof type == 'string'
|
type = types[type] if typeof type == 'string'
|
||||||
|
@ -400,7 +400,7 @@ module.exports = Model = (db, options) ->
|
||||||
|
|
||||||
# Perminantly deletes the specified document.
|
# Perminantly deletes the specified document.
|
||||||
# If listeners are attached, they are removed.
|
# If listeners are attached, they are removed.
|
||||||
#
|
#
|
||||||
# The callback is called with (error) if there was an error. If error is null / undefined, the
|
# The callback is called with (error) if there was an error. If error is null / undefined, the
|
||||||
# document was deleted.
|
# document was deleted.
|
||||||
#
|
#
|
||||||
|
@ -484,7 +484,7 @@ module.exports = Model = (db, options) ->
|
||||||
# Apply an op to the specified document.
|
# Apply an op to the specified document.
|
||||||
# The callback is passed (error, applied version #)
|
# The callback is passed (error, applied version #)
|
||||||
# opData = {op:op, v:v, meta:metadata}
|
# opData = {op:op, v:v, meta:metadata}
|
||||||
#
|
#
|
||||||
# Ops are queued before being applied so that the following code applies op C before op B:
|
# Ops are queued before being applied so that the following code applies op C before op B:
|
||||||
# model.applyOp 'doc', OPA, -> model.applyOp 'doc', OPB
|
# model.applyOp 'doc', OPA, -> model.applyOp 'doc', OPB
|
||||||
# model.applyOp 'doc', OPC
|
# model.applyOp 'doc', OPC
|
||||||
|
@ -501,7 +501,7 @@ module.exports = Model = (db, options) ->
|
||||||
# TODO: op and meta should be combineable in the op that gets sent
|
# TODO: op and meta should be combineable in the op that gets sent
|
||||||
@applyMetaOp = (docName, metaOpData, callback) ->
|
@applyMetaOp = (docName, metaOpData, callback) ->
|
||||||
{path, value} = metaOpData.meta
|
{path, value} = metaOpData.meta
|
||||||
|
|
||||||
return callback? "path should be an array" unless isArray path
|
return callback? "path should be an array" unless isArray path
|
||||||
|
|
||||||
load docName, (error, doc) ->
|
load docName, (error, doc) ->
|
||||||
|
@ -522,7 +522,7 @@ module.exports = Model = (db, options) ->
|
||||||
#
|
#
|
||||||
# The callback is called once the listener is attached, but before any ops have been passed
|
# The callback is called once the listener is attached, but before any ops have been passed
|
||||||
# to the listener.
|
# to the listener.
|
||||||
#
|
#
|
||||||
# This will _not_ edit the document metadata.
|
# This will _not_ edit the document metadata.
|
||||||
#
|
#
|
||||||
# If there are any listeners, we don't purge the document from the cache. But be aware, this behaviour
|
# If there are any listeners, we don't purge the document from the cache. But be aware, this behaviour
|
||||||
|
@ -600,4 +600,3 @@ module.exports = Model = (db, options) ->
|
||||||
|
|
||||||
# Model inherits from EventEmitter.
|
# Model inherits from EventEmitter.
|
||||||
Model:: = new EventEmitter
|
Model:: = new EventEmitter
|
||||||
|
|
||||||
|
|
|
@ -356,7 +356,7 @@ define [
|
||||||
qs.clsiserverid = response.clsiServerId
|
qs.clsiserverid = response.clsiServerId
|
||||||
for file in response.outputFiles
|
for file in response.outputFiles
|
||||||
if IGNORE_FILES.indexOf(file.path) == -1
|
if IGNORE_FILES.indexOf(file.path) == -1
|
||||||
isOutputFile = file.path.match(/^output\./)
|
isOutputFile = /^output\./.test(file.path)
|
||||||
$scope.pdf.outputFiles.push {
|
$scope.pdf.outputFiles.push {
|
||||||
# Turn 'output.blg' into 'blg file'.
|
# Turn 'output.blg' into 'blg file'.
|
||||||
name: if isOutputFile then "#{file.path.replace(/^output\./, "")} file" else file.path
|
name: if isOutputFile then "#{file.path.replace(/^output\./, "")} file" else file.path
|
||||||
|
@ -489,8 +489,7 @@ define [
|
||||||
doc = ide.editorManager.getCurrentDocValue()
|
doc = ide.editorManager.getCurrentDocValue()
|
||||||
return null if !doc?
|
return null if !doc?
|
||||||
for line in doc.split("\n")
|
for line in doc.split("\n")
|
||||||
match = line.match /^[^%]*\\documentclass/
|
if /^[^%]*\\documentclass/.test(line)
|
||||||
if match
|
|
||||||
return ide.editorManager.getCurrentDocId()
|
return ide.editorManager.getCurrentDocId()
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ define [
|
||||||
# TODO need a proper url manipulation library to add to query string
|
# TODO need a proper url manipulation library to add to query string
|
||||||
url = $scope.pdfSrc
|
url = $scope.pdfSrc
|
||||||
# add 'pdfng=true' to show that we are using the angular pdfjs viewer
|
# add 'pdfng=true' to show that we are using the angular pdfjs viewer
|
||||||
queryStringExists = url.match(/\?/)
|
queryStringExists = /\?/.test(url)
|
||||||
url = url + (if not queryStringExists then '?' else '&') + 'pdfng=true'
|
url = url + (if not queryStringExists then '?' else '&') + 'pdfng=true'
|
||||||
# for isolated compiles, load the pdf on-demand because nobody will overwrite it
|
# for isolated compiles, load the pdf on-demand because nobody will overwrite it
|
||||||
onDemandLoading = true
|
onDemandLoading = true
|
||||||
|
@ -307,7 +307,7 @@ define [
|
||||||
return unless scale?
|
return unless scale?
|
||||||
origposition = angular.copy scope.position
|
origposition = angular.copy scope.position
|
||||||
# console.log 'origposition', origposition
|
# console.log 'origposition', origposition
|
||||||
|
|
||||||
if not spinnerTimer?
|
if not spinnerTimer?
|
||||||
spinnerTimer = setTimeout () ->
|
spinnerTimer = setTimeout () ->
|
||||||
spinner.add(element)
|
spinner.add(element)
|
||||||
|
@ -384,7 +384,7 @@ define [
|
||||||
return if error == 'cancelled'
|
return if error == 'cancelled'
|
||||||
# check if too many retries or file is missing
|
# check if too many retries or file is missing
|
||||||
message = error?.message or error
|
message = error?.message or error
|
||||||
if scope.loadCount > 3 || message.match(/^Missing PDF/i) || message.match(/^loading/i)
|
if scope.loadCount > 3 || /^Missing PDF/i.test(message) || /^loading/i.test(message)
|
||||||
scope.$emit 'pdf:error:display'
|
scope.$emit 'pdf:error:display'
|
||||||
return
|
return
|
||||||
if scope.loadSuccess
|
if scope.loadSuccess
|
||||||
|
@ -408,12 +408,12 @@ define [
|
||||||
element.scrollTop(currentScrollTop + delta)
|
element.scrollTop(currentScrollTop + delta)
|
||||||
|
|
||||||
element.on 'mousedown', (e) ->
|
element.on 'mousedown', (e) ->
|
||||||
# We're checking that the event target isn't the directive root element
|
# We're checking that the event target isn't the directive root element
|
||||||
# to make sure that the click was within a PDF page - no point in showing
|
# to make sure that the click was within a PDF page - no point in showing
|
||||||
# the text layer when the click is outside.
|
# the text layer when the click is outside.
|
||||||
# If the user clicks a PDF page, the mousedown target will be the canvas
|
# If the user clicks a PDF page, the mousedown target will be the canvas
|
||||||
# element (or the text layer one). Alternatively, if the event target is
|
# element (or the text layer one). Alternatively, if the event target is
|
||||||
# the root element, we can assume that the user has clicked either the
|
# the root element, we can assume that the user has clicked either the
|
||||||
# grey background area or the scrollbars.
|
# grey background area or the scrollbars.
|
||||||
if e.target != element[0] and !_hasSelection()
|
if e.target != element[0] and !_hasSelection()
|
||||||
element.addClass 'pdfjs-viewer-show-text'
|
element.addClass 'pdfjs-viewer-show-text'
|
||||||
|
@ -444,7 +444,7 @@ define [
|
||||||
_hasSelection = () ->
|
_hasSelection = () ->
|
||||||
selection = window.getSelection?()
|
selection = window.getSelection?()
|
||||||
# check the selection collapsed state in preference to
|
# check the selection collapsed state in preference to
|
||||||
# using selection.toString() as the latter is "" when
|
# using selection.toString() as the latter is "" when
|
||||||
# the selection is hidden (e.g. while viewing logs)
|
# the selection is hidden (e.g. while viewing logs)
|
||||||
return selection? and _isSelectionWithinPDF(selection) and !selection.isCollapsed
|
return selection? and _isSelectionWithinPDF(selection) and !selection.isCollapsed
|
||||||
|
|
||||||
|
|
|
@ -28,9 +28,9 @@ define [
|
||||||
# Only show the lines that have a highlighted match
|
# Only show the lines that have a highlighted match
|
||||||
matching_lines = []
|
matching_lines = []
|
||||||
for line in lines
|
for line in lines
|
||||||
if !line.match(/^\[edit\]/)
|
if !/^\[edit\]/.test(line)
|
||||||
content += line + "\n"
|
content += line + "\n"
|
||||||
if line.match(/<em>/)
|
if /<em>/.test(line)
|
||||||
matching_lines.push line
|
matching_lines.push line
|
||||||
content = matching_lines.join("\n...\n")
|
content = matching_lines.join("\n...\n")
|
||||||
result =
|
result =
|
||||||
|
@ -38,7 +38,7 @@ define [
|
||||||
url :"/learn/#{page_underscored}##{section_underscored}"
|
url :"/learn/#{page_underscored}##{section_underscored}"
|
||||||
content: content
|
content: content
|
||||||
return result
|
return result
|
||||||
|
|
||||||
updateHits = (hits)->
|
updateHits = (hits)->
|
||||||
$scope.safeApply ->
|
$scope.safeApply ->
|
||||||
$scope.hits = hits
|
$scope.hits = hits
|
||||||
|
@ -48,7 +48,7 @@ define [
|
||||||
if !query? or query.length == 0
|
if !query? or query.length == 0
|
||||||
updateHits []
|
updateHits []
|
||||||
return
|
return
|
||||||
|
|
||||||
algoliaSearch.searchWiki query, (err, response)->
|
algoliaSearch.searchWiki query, (err, response)->
|
||||||
if response.hits.length == 0
|
if response.hits.length == 0
|
||||||
updateHits []
|
updateHits []
|
||||||
|
@ -56,4 +56,4 @@ define [
|
||||||
hits = _.map response.hits, buildHitViewModel
|
hits = _.map response.hits, buildHitViewModel
|
||||||
updateHits hits
|
updateHits hits
|
||||||
|
|
||||||
App.controller "LearnController", () ->
|
App.controller "LearnController", () ->
|
||||||
|
|
|
@ -27,9 +27,9 @@ define [
|
||||||
# Only show the lines that have a highlighted match
|
# Only show the lines that have a highlighted match
|
||||||
matching_lines = []
|
matching_lines = []
|
||||||
for line in lines
|
for line in lines
|
||||||
if !line.match(/^\[edit\]/)
|
if !/^\[edit\]/.test(line)
|
||||||
content += line + "\n"
|
content += line + "\n"
|
||||||
if line.match(/<em>/)
|
if /<em>/.test(line)
|
||||||
matching_lines.push line
|
matching_lines.push line
|
||||||
content = matching_lines.join("\n...\n")
|
content = matching_lines.join("\n...\n")
|
||||||
result =
|
result =
|
||||||
|
@ -53,4 +53,4 @@ define [
|
||||||
updateHits []
|
updateHits []
|
||||||
else
|
else
|
||||||
hits = _.map response.hits, buildHitViewModel
|
hits = _.map response.hits, buildHitViewModel
|
||||||
updateHits hits
|
updateHits hits
|
||||||
|
|
Loading…
Reference in a new issue