2018-11-05 05:06:39 -05:00
/ * e s l i n t - d i s a b l e
camelcase ,
handle - callback - err ,
max - len ,
no - return - assign ,
no - undef ,
* /
// 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
* DS206 : Consider reworking classes to avoid initClass
* DS207 : Consider shorter variations of null checks
* Full docs : https : //github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
* /
define ( [
2020-04-06 07:45:56 -04:00
'./Document' ,
'./components/spellMenu' ,
'./directives/aceEditor' ,
'./directives/toggleSwitch' ,
'./controllers/SavingNotificationController'
2018-11-05 05:06:39 -05:00
] , function ( Document ) {
let EditorManager
return ( EditorManager = ( function ( ) {
EditorManager = class EditorManager {
static initClass ( ) {
this . prototype . _syncTimeout = null
}
constructor ( ide , $scope , localStorage ) {
this . ide = ide
this . $scope = $scope
this . localStorage = localStorage
this . $scope . editor = {
sharejs _doc : null ,
open _doc _id : null ,
open _doc _name : null ,
opening : true ,
trackChanges : false ,
wantTrackChanges : false ,
showRichText : this . showRichText ( )
}
this . $scope . $on ( 'entity:selected' , ( event , entity ) => {
if ( this . $scope . ui . view !== 'history' && entity . type === 'doc' ) {
return this . openDoc ( entity )
}
} )
this . $scope . $on ( 'entity:deleted' , ( event , entity ) => {
if ( this . $scope . editor . open _doc _id === entity . id ) {
if ( ! this . $scope . project . rootDoc _id ) {
2019-12-16 05:55:45 -05:00
this . $scope . ui . view = null
2018-11-05 05:06:39 -05:00
return
}
const doc = this . ide . fileTreeManager . findEntityById (
this . $scope . project . rootDoc _id
)
if ( doc == null ) {
2019-12-16 05:55:45 -05:00
this . $scope . ui . view = null
2018-11-05 05:06:39 -05:00
return
}
return this . openDoc ( doc )
}
} )
let initialized = false
this . $scope . $on ( 'file-tree:initialized' , ( ) => {
if ( ! initialized ) {
initialized = true
return this . autoOpenDoc ( )
}
} )
this . $scope . $on ( 'flush-changes' , ( ) => {
return Document . flushAll ( )
} )
2020-05-06 06:01:35 -04:00
window . addEventListener ( 'blur' , ( ) => {
// The browser may put the tab into sleep as it looses focus.
// Flushing the documents should help with keeping the documents in
// sync: we can use any new version of the doc that the server may
// present us. There should be no need to insert local changes into
// the doc history as the user comes back.
sl _console . log ( '[EditorManager] forcing flush onblur' )
Document . flushAll ( )
} )
2018-11-05 05:06:39 -05:00
this . $scope . $watch ( 'editor.wantTrackChanges' , value => {
if ( value == null ) {
return
}
return this . _syncTrackChangesState ( this . $scope . editor . sharejs _doc )
} )
}
showRichText ( ) {
return (
this . localStorage ( ` editor.mode. ${ this . $scope . project _id } ` ) ===
'rich-text'
)
}
autoOpenDoc ( ) {
const open _doc _id =
this . ide . localStorage ( ` doc.open_id. ${ this . $scope . project _id } ` ) ||
this . $scope . project . rootDoc _id
if ( open _doc _id == null ) {
return
}
const doc = this . ide . fileTreeManager . findEntityById ( open _doc _id )
if ( doc == null ) {
return
}
return this . openDoc ( doc )
}
openDocId ( doc _id , options ) {
if ( options == null ) {
options = { }
}
const doc = this . ide . fileTreeManager . findEntityById ( doc _id )
if ( doc == null ) {
return
}
return this . openDoc ( doc , options )
}
openDoc ( doc , options ) {
if ( options == null ) {
options = { }
}
sl _console . log ( ` [openDoc] Opening ${ doc . id } ` )
this . $scope . ui . view = 'editor'
const done = ( ) => {
if ( options . gotoLine != null ) {
// allow Ace to display document before moving, delay until next tick
// added delay to make this happen later that gotoStoredPosition in
// CursorPositionManager
return setTimeout ( ( ) => {
return this . $scope . $broadcast (
'editor:gotoLine' ,
options . gotoLine ,
options . gotoColumn
)
} , 0 )
} else if ( options . gotoOffset != null ) {
return setTimeout ( ( ) => {
return this . $scope . $broadcast (
'editor:gotoOffset' ,
options . gotoOffset
)
} , 0 )
}
}
2020-01-29 10:06:29 -05:00
// If we already have the document open we can return at this point.
// Note: only use forceReopen:true to override this when the document is
// is out of sync and needs to be reloaded from the server.
2018-11-05 05:06:39 -05:00
if ( doc . id === this . $scope . editor . open _doc _id && ! options . forceReopen ) {
2020-01-29 10:05:57 -05:00
// automatically update the file tree whenever the file is opened
this . ide . fileTreeManager . selectEntity ( doc )
2018-11-05 05:06:39 -05:00
this . $scope . $apply ( ( ) => {
return done ( )
} )
return
}
2020-01-29 10:06:29 -05:00
// We're now either opening a new document or reloading a broken one.
2018-11-05 05:06:39 -05:00
this . $scope . editor . open _doc _id = doc . id
this . $scope . editor . open _doc _name = doc . name
this . ide . localStorage ( ` doc.open_id. ${ this . $scope . project _id } ` , doc . id )
this . ide . fileTreeManager . selectEntity ( doc )
this . $scope . editor . opening = true
return this . _openNewDocument ( doc , ( error , sharejs _doc ) => {
if ( error != null ) {
this . ide . showGenericMessageModal (
'Error opening document' ,
'Sorry, something went wrong opening this document. Please try again.'
)
return
}
this . _syncTrackChangesState ( sharejs _doc )
this . $scope . $broadcast ( 'doc:opened' )
return this . $scope . $apply ( ( ) => {
this . $scope . editor . opening = false
this . $scope . editor . sharejs _doc = sharejs _doc
return done ( )
} )
} )
}
_openNewDocument ( doc , callback ) {
if ( callback == null ) {
callback = function ( error , sharejs _doc ) { }
}
sl _console . log ( '[_openNewDocument] Opening...' )
const current _sharejs _doc = this . $scope . editor . sharejs _doc
2020-01-29 10:06:29 -05:00
const new _sharejs _doc = Document . getDocument ( this . ide , doc . id )
// Leave the current document only when we are opening a different new
// one, to avoid race conditions between leaving and joining the same
// document.
if (
current _sharejs _doc != null &&
current _sharejs _doc !== new _sharejs _doc
) {
2018-11-05 05:06:39 -05:00
sl _console . log ( '[_openNewDocument] Leaving existing open doc...' )
current _sharejs _doc . leaveAndCleanUp ( )
this . _unbindFromDocumentEvents ( current _sharejs _doc )
}
return new _sharejs _doc . join ( error => {
if ( error != null ) {
return callback ( error )
}
this . _bindToDocumentEvents ( doc , new _sharejs _doc )
return callback ( null , new _sharejs _doc )
} )
}
_bindToDocumentEvents ( doc , sharejs _doc ) {
sharejs _doc . on ( 'error' , ( error , meta ) => {
let message
if ( ( error != null ? error . message : undefined ) != null ) {
; ( { message } = error )
} else if ( typeof error === 'string' ) {
message = error
} else {
message = ''
}
if ( /maxDocLength/ . test ( message ) ) {
this . ide . showGenericMessageModal (
'Document Too Long' ,
'Sorry, this file is too long to be edited manually. Please upload it directly.'
)
} else if ( /too many comments or tracked changes/ . test ( message ) ) {
this . ide . showGenericMessageModal (
'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.'
)
} else {
this . ide . socket . disconnect ( )
this . ide . reportError ( error , meta )
2020-05-01 09:59:55 -04:00
this . ide . showOutOfSyncModal (
2018-11-05 05:06:39 -05:00
'Out of sync' ,
2020-05-01 09:59:55 -04:00
"Sorry, this file has gone out of sync and we need to do a full refresh. <br> <a href='/learn/Kb/Editor_out_of_sync_problems'>Please see this help guide for more information</a>" ,
sharejs _doc . doc . _doc . snapshot
2018-11-05 05:06:39 -05:00
)
}
2020-03-30 06:19:14 -04:00
const removeHandler = this . $scope . $on ( 'project:joined' , ( ) => {
this . openDoc ( doc , { forceReopen : true } )
removeHandler ( )
} )
2018-11-05 05:06:39 -05:00
} )
return sharejs _doc . on ( 'externalUpdate' , update => {
if ( this . _ignoreExternalUpdates ) {
return
}
2019-03-04 07:00:04 -05:00
if (
_ . property ( [ 'meta' , 'type' ] ) ( update ) === 'external' &&
_ . property ( [ 'meta' , 'source' ] ) ( update ) === 'git-bridge'
) {
return
}
2018-11-05 05:06:39 -05:00
return this . ide . showGenericMessageModal (
'Document Updated Externally' ,
'This document was just updated externally. Any recent changes you have made may have been overwritten. To see previous versions please look in the history.'
)
} )
}
_unbindFromDocumentEvents ( document ) {
return document . off ( )
}
getCurrentDocValue ( ) {
return this . $scope . editor . sharejs _doc != null
? this . $scope . editor . sharejs _doc . getSnapshot ( )
: undefined
}
getCurrentDocId ( ) {
return this . $scope . editor . open _doc _id
}
startIgnoringExternalUpdates ( ) {
return ( this . _ignoreExternalUpdates = true )
}
stopIgnoringExternalUpdates ( ) {
return ( this . _ignoreExternalUpdates = false )
}
_syncTrackChangesState ( doc ) {
let tryToggle
if ( doc == null ) {
return
}
if ( this . _syncTimeout != null ) {
clearTimeout ( this . _syncTimeout )
this . _syncTimeout = null
}
const want = this . $scope . editor . wantTrackChanges
const have = doc . getTrackingChanges ( )
if ( want === have ) {
this . $scope . editor . trackChanges = want
return
}
return ( tryToggle = ( ) => {
const saved =
doc . getInflightOp ( ) == null && doc . getPendingOp ( ) == null
if ( saved ) {
doc . setTrackingChanges ( want )
return this . $scope . $apply ( ( ) => {
return ( this . $scope . editor . trackChanges = want )
} )
} else {
return ( this . _syncTimeout = setTimeout ( tryToggle , 100 ) )
}
} ) ( )
}
}
EditorManager . initClass ( )
return EditorManager
} ) ( ) )
} )