diff --git a/services/web/.gitignore b/services/web/.gitignore index f9bcc5cd9b..86ff84610b 100644 --- a/services/web/.gitignore +++ b/services/web/.gitignore @@ -46,10 +46,10 @@ TpdsWorker.js BackgroundJobsWorker.js public/js/history/versiondetail.js -!public/js/libs/* +!public/js/libs/ public/js/* !public/js/ace/* -!public/js/libs/* +!public/js/libs/ public/js/editor.js public/js/home.js public/js/forms.js diff --git a/services/web/Gruntfile.coffee b/services/web/Gruntfile.coffee index de6807ba38..01af8c73d9 100644 --- a/services/web/Gruntfile.coffee +++ b/services/web/Gruntfile.coffee @@ -98,7 +98,7 @@ module.exports = (grunt) -> exclude: ["libs"] }, { name: "ide", - exclude: ["libs"] + exclude: ["libs", "libs/pdf"] }, { name: "libs" },{ diff --git a/services/web/app/coffee/Features/Compile/CompileController.coffee b/services/web/app/coffee/Features/Compile/CompileController.coffee index 054c6f5aaf..663210b092 100755 --- a/services/web/app/coffee/Features/Compile/CompileController.coffee +++ b/services/web/app/coffee/Features/Compile/CompileController.coffee @@ -78,7 +78,12 @@ module.exports = CompileController = url = "#{compilerUrl}#{url}" logger.log url: url, "proxying to CLSI" oneMinute = 60 * 1000 - proxy = request(url: url, method: req.method, timeout: oneMinute) + # pass through If-* and Range headers for byte serving pdfs + # do not send any others, potential proxying loop if Host: is passed! + newHeaders = {} + for h, v of req.headers + newHeaders[h] = req.headers[h] if h.match /^(If-|Range)/i + proxy = request(url: url, method: req.method, timeout: oneMinute, headers: newHeaders) proxy.pipe(res) proxy.on "error", (error) -> logger.warn err: error, url: url, "CLSI proxy error" diff --git a/services/web/app/coffee/infrastructure/ExpressLocals.coffee b/services/web/app/coffee/infrastructure/ExpressLocals.coffee index cb3e7837aa..b85ba6850c 100644 --- a/services/web/app/coffee/infrastructure/ExpressLocals.coffee +++ b/services/web/app/coffee/infrastructure/ExpressLocals.coffee @@ -18,14 +18,18 @@ jsPath = logger.log "Generating file fingerprints..." for path in [ - "#{jsPath}libs/require.js", - "#{jsPath}ide.js", - "#{jsPath}main.js", + "#{jsPath}libs/require.js", + "#{jsPath}ide.js", + "#{jsPath}main.js", "#{jsPath}libs.js", "#{jsPath}ace/ace.js", - "#{jsPath}libs/pdf.js", - "#{jsPath}libs/pdf.worker.js", - "/stylesheets/style.css" + "#{jsPath}libs/pdf.js", + "#{jsPath}libs/pdf.worker.js", + "#{jsPath}libs/compatibility.js", + "#{jsPath}libs/pdfjs-1.0.712/pdf.js", + "#{jsPath}libs/pdfjs-1.0.712/pdf.worker.js", + "#{jsPath}libs/pdfjs-1.0.712/compatibility.js", + "/stylesheets/style.css" ] filePath = Path.join __dirname, "../../../", "public#{path}" exists = fs.existsSync filePath diff --git a/services/web/app/coffee/models/User.coffee b/services/web/app/coffee/models/User.coffee index 55e222d16e..783389cb6a 100644 --- a/services/web/app/coffee/models/User.coffee +++ b/services/web/app/coffee/models/User.coffee @@ -35,7 +35,9 @@ UserSchema = new Schema compileTimeout: { type:Number, default: Settings.defaultFeatures.compileTimeout } compileGroup: { type:String, default: Settings.defaultFeatures.compileGroup } } - featureSwitches : {} + featureSwitches : { + pdfng: { type: Boolean } + } referal_id : {type:String, default:() -> uuid.v4().split("-")[0]} refered_users: [ type:ObjectId, ref:'User' ] refered_user_count: { type:Number, default: 0 } diff --git a/services/web/app/views/project/editor.jade b/services/web/app/views/project/editor.jade index 48be8f0dbc..d6f99e24f2 100644 --- a/services/web/app/views/project/editor.jade +++ b/services/web/app/views/project/editor.jade @@ -112,11 +112,21 @@ block content - locals.suppressDefaultJs = true - - var fingerprintedPath = fingerprint(jsPath+'libs/pdf.worker.js') - - var pdfJsWorkerPath = jsPath+'libs/pdf.worker.js?fingerprint='+fingerprintedPath + - // user.featureSwitches = {} // override + - var usePdfNG = user.featureSwitches && user.featureSwitches.pdfng; + - var pdfPath = 'libs/pdf.worker.js'; + - if (usePdfNG) { pdfPath = 'libs/pdfjs-1.0.712/pdf.worker.js'; } + - var fingerprintedPath = fingerprint(jsPath+pdfPath) + - var pdfJsWorkerPath = jsPath+pdfPath+'?fingerprint='+fingerprintedPath script(type='text/javascript'). window.pdfJsWorkerPath = "#{pdfJsWorkerPath}"; + // when using pdfng we need a different pdfjs version + if usePdfNG + script(type='text/javascript'). + window.requirejs.paths['libs/pdf'] = 'libs/pdfjs-1.0.712/pdf' + window.requirejs.paths['libs/compatibility'] = 'libs/pdfjs-1.0.712/compatibility' + script( data-main=jsPath+"ide.js", baseurl=jsPath, diff --git a/services/web/app/views/project/editor/pdf.jade b/services/web/app/views/project/editor/pdf.jade index 1abcb75ae4..cbfeece827 100644 --- a/services/web/app/views/project/editor/pdf.jade +++ b/services/web/app/views/project/editor/pdf.jade @@ -58,16 +58,31 @@ div.full-size.pdf(ng-controller="PdfController") i.split-screen .pdf-viewer(ng-show="pdf.url && pdf.view == 'pdf' && !pdf.failure && !pdf.timeout && !pdf.error") - div( - pdfjs - ng-if="settings.pdfViewer == 'pdfjs'" - pdf-src="pdf.url" - key="{{ project_id }}" - resize-on="layout:main:resize,layout:pdf:resize" - highlights="pdf.highlights" - position="pdf.position" - dbl-click-callback="syncToCode" - ) + - // user.featureSwitches = {} // override + - var usePdfNG = user.featureSwitches && user.featureSwitches.pdfng; + if !usePdfNG + div( + pdfjs + ng-if="settings.pdfViewer == 'pdfjs'" + pdf-src="pdf.url" + key="{{ project_id }}" + resize-on="layout:main:resize,layout:pdf:resize" + highlights="pdf.highlights" + position="pdf.position" + dbl-click-callback="syncToCode" + ) + else + div( + pdfng + ng-if="settings.pdfViewer == 'pdfjs'" + pdf-src="pdf.url" + key="{{ project_id }}" + resize-on="layout:main:resize,layout:pdf:resize" + highlights="pdf.highlights" + position="pdf.position" + dbl-click-callback="syncToCode" + ) + iframe( ng-src="{{ pdf.url }}" ng-if="settings.pdfViewer == 'native'" diff --git a/services/web/public/coffee/base.coffee b/services/web/public/coffee/base.coffee index c79f8e6d45..b050b45802 100644 --- a/services/web/public/coffee/base.coffee +++ b/services/web/public/coffee/base.coffee @@ -13,4 +13,4 @@ define [ "ipCookie" ]) - return App \ No newline at end of file + return App diff --git a/services/web/public/coffee/ide.coffee b/services/web/public/coffee/ide.coffee index e5abde12cf..2bd1ae236f 100644 --- a/services/web/public/coffee/ide.coffee +++ b/services/web/public/coffee/ide.coffee @@ -106,4 +106,4 @@ define [ else $scope.darkTheme = false - angular.bootstrap(document.body, ["SharelatexApp"]) \ No newline at end of file + angular.bootstrap(document.body, ["SharelatexApp"]) diff --git a/services/web/public/coffee/ide/pdf/PdfManager.coffee b/services/web/public/coffee/ide/pdf/PdfManager.coffee index f53d649e97..b9e3fe5e88 100644 --- a/services/web/public/coffee/ide/pdf/PdfManager.coffee +++ b/services/web/public/coffee/ide/pdf/PdfManager.coffee @@ -2,6 +2,7 @@ define [ "ide/pdf/controllers/PdfController" "ide/pdf/controllers/PdfViewToggleController" "ide/pdf/directives/pdfJs" + "ide/pdfng/directives/pdfJs" # alternative incremental viewer ], () -> class PdfManager constructor: (@ide, @$scope) -> diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfAnnotations.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfAnnotations.coffee new file mode 100644 index 0000000000..e9943859b8 --- /dev/null +++ b/services/web/public/coffee/ide/pdfng/directives/pdfAnnotations.coffee @@ -0,0 +1,45 @@ +define [ + "base" +], (App) -> + # App = angular.module 'pdfAnnotations', [] + App.factory 'pdfAnnotations', [ () -> + class pdfAnnotations + + @EXTERNAL_LINK_TARGET = "_blank"; + + constructor: (options) -> + @annotationsLayerDiv = options.annotations; + @viewport = options.viewport + @navigateFn = options.navigateFn + + setAnnotations: (annotations) -> + for annotation in annotations + switch annotation.subtype + when 'Link' then @addLink(annotation); + when 'Text' then continue + + addLink: (link) -> + element = @buildLinkElementFromRect(link.rect); + @setLinkTarget(element, link); + @annotationsLayerDiv.appendChild(element); + + buildLinkElementFromRect: (rect) -> + rect = @viewport.convertToViewportRectangle(rect); + rect = PDFJS.Util.normalizeRect(rect); + element = document.createElement("a"); + element.style.left = Math.floor(rect[0]) + 'px'; + element.style.top = Math.floor(rect[1]) + 'px'; + element.style.width = Math.ceil(rect[2] - rect[0]) + 'px'; + element.style.height = Math.ceil(rect[3] - rect[1]) + 'px'; + element + + setLinkTarget: (element, link) -> + if link.url + element.href = link.url; + element.target = @EXTERNAL_LINK_TARGET; + else if (link.dest) + element.href = "#" + link.dest; + element.onclick = (e) => + @navigateFn link + return false + ] diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfHighlights.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfHighlights.coffee new file mode 100644 index 0000000000..fc2b72bd79 --- /dev/null +++ b/services/web/public/coffee/ide/pdfng/directives/pdfHighlights.coffee @@ -0,0 +1,29 @@ +define [ + "base" +], (App) -> + #app = angular.module 'pdfHighlights', [] + + App.factory 'pdfHighlights', [ () -> + class pdfHighlights + + constructor: (options) -> + @highlightsLayerDiv = options.highlights[0] + @highlightElements = [] + + addHighlight: (viewport, left, top, width, height) -> + rect = viewport.convertToViewportRectangle([left, top, left + width, top + height]) + rect = PDFJS.Util.normalizeRect(rect) + element = document.createElement("div") + element.style.left = Math.floor(rect[0]) + 'px' + element.style.top = Math.floor(rect[1]) + 'px' + element.style.width = Math.ceil(rect[2] - rect[0]) + 'px' + element.style.height = Math.ceil(rect[3] - rect[1]) + 'px' + @highlightElements.push(element) + @highlightsLayerDiv.appendChild(element) + element + + clearHighlights: () -> + for h in @highlightElements + h.remove() + @highlightElements = [] + ] diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfJs.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfJs.coffee new file mode 100644 index 0000000000..aba1bd9578 --- /dev/null +++ b/services/web/public/coffee/ide/pdfng/directives/pdfJs.coffee @@ -0,0 +1,208 @@ +define [ + "base" + "ide/pdfng/directives/pdfViewer" + "text!libs/pdfListView/TextLayer.css" + "text!libs/pdfListView/AnnotationsLayer.css" + "text!libs/pdfListView/HighlightsLayer.css" +], ( + App + pdfViewer + textLayerCss + annotationsLayerCss + highlightsLayerCss +) -> + if PDFJS? + PDFJS.workerSrc = window.pdfJsWorkerPath + + style = $("