diff --git a/services/web/app/coffee/Features/Errors/ErrorController.coffee b/services/web/app/coffee/Features/Errors/ErrorController.coffee index 55006b73c7..c4f3089fe0 100644 --- a/services/web/app/coffee/Features/Errors/ErrorController.coffee +++ b/services/web/app/coffee/Features/Errors/ErrorController.coffee @@ -38,5 +38,5 @@ module.exports = ErrorController = logger.warn {err: error, url: req.url}, "not found error" res.sendStatus(404) else - logger.error err: error, url:req.url, method:req.method, user:user, "error passed to top level next middlewear" + logger.error err: error, url:req.url, method:req.method, "error passed to top level next middlewear" res.sendStatus(500) diff --git a/services/web/app/coffee/Features/Subscription/SubscriptionGroupController.coffee b/services/web/app/coffee/Features/Subscription/SubscriptionGroupController.coffee index 05737061fe..6b8bd99c35 100644 --- a/services/web/app/coffee/Features/Subscription/SubscriptionGroupController.coffee +++ b/services/web/app/coffee/Features/Subscription/SubscriptionGroupController.coffee @@ -54,8 +54,8 @@ module.exports = renderSubscriptionGroupAdminPage: (req, res)-> user_id = AuthenticationController.getLoggedInUserId(req) SubscriptionLocator.getUsersSubscription user_id, (err, subscription)-> - if !subscription.groupPlan - return res.redirect("/") + if !subscription?.groupPlan + return res.redirect("/user/subscription") SubscriptionGroupHandler.getPopulatedListOfMembers user_id, (err, users)-> res.render "subscriptions/group_admin", title: 'group_admin' diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor/labels/LabelsManager.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor/labels/LabelsManager.coffee index 07b60b08b9..a5d2c10625 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor/labels/LabelsManager.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor/labels/LabelsManager.coffee @@ -11,7 +11,7 @@ define [ class LabelsManager constructor: (@$scope, @editor, @element, @Labels) -> - @loadLabelsTimeout = null + @debouncer = {} # DocId => Timeout onChange = (change) => if change.remote @@ -36,13 +36,20 @@ define [ currentDocId = @$scope.docId @Labels.loadDocLabelsFromServer(currentDocId) + loadDocLabelsFromServer: (docId) -> + @Labels.loadDocLabelsFromServer(docId) + scheduleLoadCurrentDocLabelsFromServer: () -> # De-bounce loading labels with a timeout - if @loadLabelsTimeout - clearTimeout(@loadLabelsTimeout) - @loadLabelsTimeout = setTimeout( + currentDocId = @$scope.docId + existingTimeout = @debouncer[currentDocId] + if existingTimeout? + clearTimeout(existingTimeout) + delete @debouncer[currentDocId] + @debouncer[currentDocId] = setTimeout( () => - @loadCurrentDocLabelsFromServer() + @loadDocLabelsFromServer(currentDocId) + delete @debouncer[currentDocId] , 1000 , this ) diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor/spell-check/SpellCheckManager.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor/spell-check/SpellCheckManager.coffee index 759b1d2b70..bef2edfc41 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor/spell-check/SpellCheckManager.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor/spell-check/SpellCheckManager.coffee @@ -217,6 +217,7 @@ define [ words = [] positions = [] for line, row in lines + line = @blankOutBlacklistedCommands(line) if !linesToProcess? or linesToProcess[row] # Regex generated from /\\?['\p{L}]+/g via https://mothereff.in/regexpu. # \p{L} matches unicode characters in the 'letter' category, but is not supported until ES6. @@ -246,3 +247,22 @@ define [ error: (xhr, status, error) -> callback error return $.ajax options + + blacklistedCommandRegex: /// + \\ # initial backslash + (label # any of these commands + |[a-z]{0,16}ref + |usepackage + |begin + |end + |[a-z]{0,16}cite + |input + |include + |includegraphics) + ( \[ [^\]]* \] )? # optional [...] args + \{ [^}]* \} # the {...} args + ///g + + blankOutBlacklistedCommands: (line) -> + line.replace @blacklistedCommandRegex, (command) -> + Array(command.length+1).join('.') diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee index ff4d5a4101..e6401b11ac 100644 --- a/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee +++ b/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee @@ -323,6 +323,8 @@ define [ clearTimeout spinnerTimer else spinner.remove(element) + # stop displaying the text layer + element.removeClass 'pdfjs-viewer-show-text' ctrl.redraw(origposition) $timeout renderVisiblePages scope.loadSuccess = true @@ -405,6 +407,53 @@ define [ scope.adjustingScroll = true element.scrollTop(currentScrollTop + delta) + element.on 'mousedown', (e) -> + # 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 + # the text layer when the click is outside. + # 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 + # the root element, we can assume that the user has clicked either the + # grey background area or the scrollbars. + if e.target != element[0] and !_hasSelection() + element.addClass 'pdfjs-viewer-show-text' + _setMouseUpHandler() + + mouseUpHandler = null # keep track of the handler to avoid adding multiple times + + _setMouseUpHandler = () -> + if not mouseUpHandler? + mouseUpHandler = $(document.body).one 'mouseup', _handleSelectionMouseUp + + _handleSelectionMouseUp = () -> + mouseUpHandler = null # reset handler, has now fired + window.setTimeout () -> + removedClass = _removeClassIfNoSelection() + # if we still have a selection we need to keep the handler going + if not removedClass then _setMouseUpHandler() + , 10 + return true + + _removeClassIfNoSelection = () -> + if _hasSelection() + return false # didn't remove the text layer + else + element.removeClass 'pdfjs-viewer-show-text' + return true + + _hasSelection = () -> + selection = window.getSelection?() + # check the selection collapsed state in preference to + # using selection.toString() as the latter is "" when + # the selection is hidden (e.g. while viewing logs) + return selection? and _isSelectionWithinPDF(selection) and !selection.isCollapsed + + _isSelectionWithinPDF = (selection) -> + if selection.rangeCount == 0 + return false + selectionAncestorNode = selection.getRangeAt(0).commonAncestorContainer + return element.find(selectionAncestorNode).length > 0 or element.is(selectionAncestorNode) + element.on 'scroll', () -> #console.log 'scroll event', element.scrollTop(), 'adjusting?', scope.adjustingScroll #scope.scrollPosition = element.scrollTop() diff --git a/services/web/public/stylesheets/app/editor/pdf.less b/services/web/public/stylesheets/app/editor/pdf.less index 12c86a6190..0c98050242 100644 --- a/services/web/public/stylesheets/app/editor/pdf.less +++ b/services/web/public/stylesheets/app/editor/pdf.less @@ -37,6 +37,7 @@ margin: 10px auto; padding: 0 10px; box-sizing: content-box; + user-select: none; } } .progress-thin { @@ -338,3 +339,13 @@ .files-dropdown { display: inline-block; } + +.plv-text-layer { + display: none; + user-select: text; + + .pdf-page-container:hover &, + .pdfjs-viewer-show-text & { + display: block; + } +} diff --git a/services/web/public/stylesheets/app/editor/toolbar.less b/services/web/public/stylesheets/app/editor/toolbar.less index 5f84f64682..1bb5f62bdc 100644 --- a/services/web/public/stylesheets/app/editor/toolbar.less +++ b/services/web/public/stylesheets/app/editor/toolbar.less @@ -10,6 +10,7 @@ right: 0; padding: .15em .6em .2em; font-size: 60%; + pointer-events: none; // Labels were capturing button/anchor clicks. } } diff --git a/services/web/test/UnitTests/coffee/Subscription/SubscriptionGroupControllerTests.coffee b/services/web/test/UnitTests/coffee/Subscription/SubscriptionGroupControllerTests.coffee index d493eacd8d..09eab53063 100644 --- a/services/web/test/UnitTests/coffee/Subscription/SubscriptionGroupControllerTests.coffee +++ b/services/web/test/UnitTests/coffee/Subscription/SubscriptionGroupControllerTests.coffee @@ -96,7 +96,16 @@ describe "SubscriptionGroupController", -> res = redirect : (path)=> - path.should.equal("/") + path.should.equal("/user/subscription") + done() + @Controller.renderSubscriptionGroupAdminPage @req, res + + it "should redirect you don't have a subscription", (done)-> + @SubscriptionLocator.getUsersSubscription = sinon.stub().callsArgWith(1) + + res = + redirect : (path)=> + path.should.equal("/user/subscription") done() @Controller.renderSubscriptionGroupAdminPage @req, res