2014-02-12 10:23:40 +00:00
define [
" utils/Modal "
" pdf/CompiledView "
2014-04-09 11:35:23 +00:00
" pdf/SyncButtonsView "
2014-02-12 10:23:40 +00:00
" libs/latex-log-parser "
" libs/jquery.storage "
2014-06-21 10:56:58 +00:00
" underscore "
2014-02-12 10:23:40 +00:00
" libs/backbone "
2014-04-09 11:35:23 +00:00
] , (Modal, CompiledView, SyncButtonsView, LogParser) ->
2014-02-12 10:23:40 +00:00
class PdfManager
templates:
pdfLink: $ ( " # pdfSideBarLinkTemplate " ) . html ( )
constructor: (@ide) ->
_ . extend @ , Backbone . Events
2014-04-09 11:35:23 +00:00
@ createSyncButtons ( )
2014-02-12 10:23:40 +00:00
@ createPdfPanel ( )
@ ide . editor . aceEditor . commands . addCommand
name: " compile " ,
bindKey: win: " Ctrl-Enter " , mac: " Command-Enter "
exec: (editor) =>
@ refreshPdf ( )
readOnly: true
@ ide . editor . aceEditor . commands . removeCommand " replace "
createPdfPanel: () ->
@view = new CompiledView manager: @ , ide: @ ide
2014-04-08 15:49:21 +00:00
@ view . on " dblclick " , (e) => @ syncToCode ( e )
2014-02-12 10:23:40 +00:00
@ view . render ( )
if $ . localStorage ( " layout.pdf " ) == " flat "
@ switchToFlatView ( )
else if $ . localStorage ( " layout.pdf " ) == " split "
@ switchToSplitView ( )
else if $ ( window ) . width ( ) < 1024
@ switchToFlatView ( )
else
@ switchToSplitView ( )
2014-04-09 11:35:23 +00:00
createSyncButtons: () ->
unless @ ide . userSettings . pdfViewer == " native "
@syncButtonsView = new SyncButtonsView ( ide: @ ide )
@ syncButtonsView . on " click:sync-code-to-pdf " , () =>
@ syncToPdf ( )
@ syncButtonsView . on " click:sync-pdf-to-code " , () =>
@ syncToCode ( )
@ syncButtonsView . hide ( )
2014-02-12 10:23:40 +00:00
switchToFlatView: (options = {showPdf: false}) ->
@ teardownSplitView ( )
@ setupFlatView ( )
@ view . toggleFlatViewButton ( )
if options . showPdf
@ ide . sideBarView . selectLink " pdf "
@ ide . mainAreaManager . change " pdf "
@ view . resize ( )
switchToSplitView: () ->
@ teardownFlatView ( )
@ setupSplitView ( )
@ view . toggleSplitViewButton ( )
@ view . resize ( )
@ ide . editor . setIdeToEditorPanel ( )
setupFlatView: () ->
@ teardownFlatView ( )
@ ide . editor . switchToFlatView ( )
pdfLink = $ ( @ templates . pdfLink )
@ ide . sideBarView . addLink
identifier : " pdf "
before : " history "
element : pdfLink
pdfLink . on " click " , (e) => @ showPdfPanel ( )
@ ide . mainAreaManager . addArea
identifier: " pdf "
element: @ view . $el
@ view . resize ( )
@ view . undelegateEvents ( )
@ view . delegateEvents ( )
teardownFlatView: () ->
@ ide . sideBarView . removeLink ( " pdf " )
@ ide . mainAreaManager . removeArea ( " pdf " )
@ view . afterSwitchView ( )
setupSplitView: () ->
@ ide . editor . switchToSplitView ( )
@ ide . editor . rightPanel . append (
@ view . $el
)
@ view . $el . show ( )
@ view . resize ( )
@ view . undelegateEvents ( )
@ view . delegateEvents ( )
2014-04-09 11:35:23 +00:00
@ ide . editor . $splitter . append (
@ syncButtonsView ? . $el
)
2014-02-12 10:23:40 +00:00
setTimeout ( @ ide . layoutManager . resizeAllSplitters , 100 )
teardownSplitView: () ->
@ view . afterSwitchView ( )
showPdfPanel: () ->
@ ide . sideBarView . selectLink ' pdf '
@ ide . mainAreaManager . change ' pdf '
@ view . resize ( )
if ! @ view . hasPdf ( )
@ refreshPdf ( )
showRawLogPanel: () ->
@ ide . mainAreaManager . change ' rawLog '
refreshPdf: (opts) ->
if @ ide . project ?
@ _refreshPdfWhenProjectIsLoaded ( opts )
else
@ ide . on " afterJoinProject " , () =>
@ _refreshPdfWhenProjectIsLoaded ( opts )
2014-05-19 14:28:35 +00:00
_refreshPdfWhenProjectIsLoaded: (opts = {}) ->
2014-04-09 11:35:23 +00:00
2014-02-12 10:23:40 +00:00
if ! @ ide . project . get ( " rootDoc_id " ) ?
new Modal
title: " No root document selected "
message: " First you need to choose a root document via the settings menu. This tells ShareLaTeX which file to run LaTeX on. "
buttons: [ {
text: " OK " ,
class : " btn-primary "
} ]
else if ! @ compiling
@ view . onCompiling ( )
2014-04-09 11:35:23 +00:00
@ syncButtonsView ? . hide ( )
2014-02-12 10:23:40 +00:00
@compiling = true
2014-06-01 14:43:52 +00:00
@ _doCompile opts , (error, status, outputFiles) =>
2014-02-12 10:23:40 +00:00
@compiling = false
2014-06-10 17:14:28 +00:00
@ view . doneCompiling ( )
@ syncButtonsView ? . show ( )
2014-05-19 14:28:35 +00:00
if error ?
@ view . updateLog ( systemError: true )
@ view . unsetPdf ( )
@ view . showLog ( )
else if status == " timedout "
@ view . updateLog ( timedOut: true )
@ view . unsetPdf ( )
@ view . showLog ( )
else if status == " autocompile-backoff "
2014-02-12 10:23:40 +00:00
@ view . showBeforeCompile ( )
else
2014-05-19 14:28:35 +00:00
pdfExists = ( status == " success " )
@ fetchLogAndUpdateView ( pdfExists )
2014-02-12 10:23:40 +00:00
if pdfExists
@ view . setPdf ( " /project/ #{ @ ide . project_id } /output/output.pdf?cache_bust= #{ Date . now ( ) } " )
@ view . showPdf ( )
else
@ view . unsetPdf ( )
@ view . showLog ( )
2014-04-09 11:35:23 +00:00
@ syncButtonsView ? . hide ( )
2014-02-12 10:23:40 +00:00
if outputFiles ?
@ view . showOutputFileDownloadLinks ( outputFiles )
2014-06-01 14:43:52 +00:00
_doCompile: ( opts , callback = (error, status, outputFiles) -> ) ->
2014-05-19 14:28:35 +00:00
url = " /project/ #{ @ ide . project_id } /compile "
2014-06-01 14:43:52 +00:00
if opts . isAutoCompile
2014-05-19 14:28:35 +00:00
url += " ?auto_compile=true "
$ . ajax (
url: url
type: " POST "
headers:
" X-CSRF-Token " : window . csrfToken
2014-06-01 14:43:52 +00:00
contentType: " application/json; charset=utf-8 "
2014-05-19 14:28:35 +00:00
dataType: ' json '
2014-06-01 14:43:52 +00:00
data: JSON . stringify settingsOverride:
rootDoc_id: opts . rootDocOverride_id ? null
2014-05-19 14:28:35 +00:00
success: (body, status, response) ->
callback null , body . status , body . outputFiles
error: (error) ->
callback error
)
2014-02-12 10:23:40 +00:00
fetchLogAndUpdateView: (pdfExists) ->
$ . ajax (
url: " /project/ #{ @ ide . project_id } /output/output.log "
success: (body, status, response) =>
@ parseLogAndUpdateView ( pdfExists , body )
error: () =>
@ view . updateLog ( pdfExists: pdfExists , logExists: false )
)
parseLogAndUpdateView: (pdfExists, log) ->
errors = LogParser . parse ( log , ignoreDuplicates: true )
lastCompileErrors = { }
for error in errors . all
error.file = @ _normalizeFilePath ( error . file )
doc_id = @ ide . fileTreeManager . getDocIdOfPath ( error . file )
if doc_id ?
lastCompileErrors [ doc_id ] || = [ ]
lastCompileErrors [ doc_id ] . push
row: error . line - 1
type: if error . level == " error " then " error " else " warning "
text: error . message
@ide.editor.compilationErrors = lastCompileErrors
@ ide . editor . refreshCompilationErrors ( )
@ view . updateLog ( pdfExists: pdfExists , logExists: true , compileErrors: errors , rawLog: log )
_normalizeFilePath: (path) ->
path = path . replace ( /^compiles\/[0-9a-f]{32}\/(\.\/)?/ , " " )
path = path . replace ( /^\/compile\// , " " )
rootDoc_id = @ ide . project . get ( " rootDoc_id " )
if rootDoc_id ?
rootDocPath = @ ide . fileTreeManager . getPathOfEntityId ( rootDoc_id )
if rootDocPath ?
rootDocDir = rootDocPath . split ( " / " ) . slice ( 0 , - 1 ) . map ( (part) -> part + " / " ) . join ( " " )
path = path . replace ( /^\.\// , rootDocDir )
return path
downloadPdf: () ->
@ ide . mainAreaManager . setIframeSrc " /project/ #{ @ ide . project_id } /output/output.pdf?popupDownload=true "
2014-03-27 17:00:41 +00:00
deleteCachedFiles: () ->
modal = new Modal
title: " Clear cache? "
message: " This will clear all hidden LaTeX files like .aux, .bbl, etc, from our compile server. You generally don ' t need to do this unless you ' re having trouble with references. Your project files will not be deleted or changed. "
buttons: [ {
text: " Cancel "
} , {
text: " Clear from cache " ,
class : " btn-primary " ,
close: false
callback: ($button) =>
$button . text ( " Clearing... " )
$button . prop ( " disabled " , true )
$ . ajax ( {
url: " /project/ #{ @ ide . project_id } /output "
type: " DELETE "
headers:
" X-CSRF-Token " : window . csrfToken
complete: () -> modal . remove ( )
} )
} ]
2014-04-08 15:49:21 +00:00
syncToCode: (e) ->
2014-04-09 11:35:23 +00:00
if ! e ?
e = @ view . getPdfPosition ( )
return if ! e ?
# It's not clear exactly where we should sync to if it was directly
# clicked on, but a little bit down from the very top seems best.
e.y = e . y + 80
2014-04-08 15:49:21 +00:00
$ . ajax {
url: " /project/ #{ @ ide . project_id } /sync/pdf "
data:
page: e . page + 1
h: e . x . toFixed ( 2 )
v: e . y . toFixed ( 2 )
type: " GET "
success: (response) =>
data = JSON . parse ( response )
if data . code and data . code . length > 0
file = data . code [ 0 ] . file
line = data . code [ 0 ] . line
@ ide . fileTreeManager . openDocByPath ( file , line )
2014-04-08 16:21:49 +00:00
}
syncToPdf: () ->
entity_id = @ ide . editor . getCurrentDocId ( )
file = @ ide . fileTreeManager . getPathOfEntityId ( entity_id )
2014-05-29 15:41:24 +00:00
# If the root file is folder/main.tex, then synctex sees the
# path as folder/./main.tex
rootFolderPath = @ ide . fileTreeManager . getRootFolderPath ( )
if rootFolderPath != " "
file = file . replace ( RegExp ( " ^ #{ rootFolderPath } " ) , " #{ rootFolderPath } /. " )
2014-04-08 16:21:49 +00:00
line = @ ide . editor . getCurrentLine ( )
column = @ ide . editor . getCurrentColumn ( )
$ . ajax {
url: " /project/ #{ @ ide . project_id } /sync/code "
data:
file: file
line: line + 1
column: column
type: " GET "
success: (response) =>
data = JSON . parse ( response )
2014-04-08 17:21:44 +00:00
@ view . highlightInPdf ( data . pdf or [ ] )
2014-04-08 16:21:49 +00:00
}