mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-30 03:53:05 -05:00
Start rebuilding editor
This commit is contained in:
parent
0d70777f7f
commit
6d0053e709
14 changed files with 488 additions and 1007 deletions
|
@ -167,6 +167,7 @@ module.exports = ProjectController =
|
|||
priority_title: true
|
||||
bodyClasses: ["editor"]
|
||||
project : project
|
||||
project_id : project._id
|
||||
userObject : JSON.stringify({
|
||||
id : user.id
|
||||
email : user.email
|
||||
|
@ -179,7 +180,6 @@ module.exports = ProjectController =
|
|||
userSettingsObject: JSON.stringify({
|
||||
mode : user.ace.mode
|
||||
theme : user.ace.theme
|
||||
project_id : project._id
|
||||
fontSize : user.ace.fontSize
|
||||
autoComplete: user.ace.autoComplete
|
||||
spellCheckLanguage: user.ace.spellCheckLanguage
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
doctype html
|
||||
html(itemscope, itemtype='http://schema.org/Product')
|
||||
block vars
|
||||
|
||||
head
|
||||
- if (typeof(gaExperimentCode) !== "undefined" && gaExperimentCode)
|
||||
#{gaExperimentCode}
|
||||
|
@ -38,9 +40,13 @@ html(itemscope, itemtype='http://schema.org/Product')
|
|||
block scripts
|
||||
|
||||
body
|
||||
include layout/navbar
|
||||
- if(typeof(suppressNavbar) == "undefined")
|
||||
include layout/navbar
|
||||
|
||||
block content
|
||||
include layout/footer
|
||||
|
||||
- if(typeof(suppressFooter) == "undefined")
|
||||
include layout/footer
|
||||
|
||||
- if (typeof(lookingForScribtex) != "undefined" && lookingForScribtex)
|
||||
.modal.hide#scribtexModal
|
||||
|
@ -54,16 +60,17 @@ html(itemscope, itemtype='http://schema.org/Product')
|
|||
.modal-footer
|
||||
button(data-dismiss="modal").btn OK
|
||||
|
||||
script(type='text/javascript').
|
||||
window.requirejs = {
|
||||
"urlArgs" : "fingerprint=#{fingerprint(jsPath + 'app/main.js')}"
|
||||
};
|
||||
|
||||
script(
|
||||
data-main=jsPath+'app/main.js',
|
||||
baseurl=jsPath,
|
||||
src=jsPath+'libs/require.js?fingerprint='+fingerprint(jsPath + 'libs/require.js')
|
||||
)
|
||||
- if(typeof(suppressFooter) == "undefined")
|
||||
script(type='text/javascript').
|
||||
window.requirejs = {
|
||||
"urlArgs" : "fingerprint=#{fingerprint(jsPath + 'app/main.js')}"
|
||||
};
|
||||
script(
|
||||
data-main=jsPath+'app/main.js',
|
||||
baseurl=jsPath,
|
||||
src=jsPath+'libs/require.js?fingerprint='+fingerprint(jsPath + 'libs/require.js')
|
||||
)
|
||||
|
||||
- if (typeof(tenderUrl) != "undefined")
|
||||
script(src="https://#{tenderUrl}/tender_widget.js" )
|
||||
|
|
|
@ -1,41 +1,136 @@
|
|||
extends ../layout
|
||||
|
||||
block vars
|
||||
- var suppressNavbar = true
|
||||
- var suppressFooter = true
|
||||
- var suppressDefaultJs = true
|
||||
|
||||
block scripts
|
||||
//- Only use the native bootstrap on the editor page,
|
||||
//- since we use the Angular-based bootstrap elsewhere.
|
||||
script(src=jsPath+'libs/bootstrap-3.1.1.js')
|
||||
script(src=jsPath+'libs/jquery-layout.js')
|
||||
script(src=jsPath+'libs/jquery.storage.js')
|
||||
|
||||
block content
|
||||
#loadingScreen
|
||||
h3 Loading...
|
||||
p#loadingMessage Loading editor
|
||||
|
||||
#errorMessages
|
||||
#connectionLostMessage(style="display: none;")
|
||||
| Lost connection.
|
||||
span#trying-reconnect
|
||||
| Reconnecting in
|
||||
span#reconnection-countdown ?
|
||||
| seconds.
|
||||
a(href='#')#try-reconnect-now Try now.
|
||||
span#reconnecting
|
||||
| Reconnecting...
|
||||
.editor(ng-controller="IdeController")
|
||||
|
||||
#savingProblems(style="display: none")
|
||||
| Saving...
|
||||
.loading-screen(ng-show="state.loading")
|
||||
.container
|
||||
h3 Loading...
|
||||
.progress
|
||||
.progress-bar(ng-style="{'width': state.load_progress + '%'}")
|
||||
|
||||
div#toolbar.sidebar-navigation
|
||||
ul#tabs
|
||||
#toolbar-footer
|
||||
header.toolbar.toolbar-header(ng-cloak, ng-hide="state.loading")
|
||||
a.btn.btn-full-height(href='#', tooltip="Menu", tooltip-placement="bottom")
|
||||
i.fa.fa-bars
|
||||
|
||||
#tab-content.tab-content
|
||||
span.name {{ project.name }}
|
||||
|
||||
include ../templates
|
||||
include ../templates/dropbox
|
||||
a(href='#', data-toggle="tooltip", title="Rename")
|
||||
i.fa.fa-pencil
|
||||
|
||||
.toolbar-right
|
||||
a.btn.btn-full-height(href='#', tooltip="Share", tooltip-placement="bottom")
|
||||
i.fa.fa-group
|
||||
a.btn.btn-full-height(href='#', tooltip="Recent Changes", tooltip-placement="bottom")
|
||||
i.fa.fa-history
|
||||
a.btn.btn-full-height(href='#', tooltip="Chat", tooltip-placement="bottom")
|
||||
i.fa.fa-comment
|
||||
|
||||
#editor-content(ng-cloak, layout="main", ng-hide="state.loading")
|
||||
aside#file-tree.ui-layout-west
|
||||
.toolbar.toolbar-small
|
||||
a(href, tooltip-html-unsafe="New<br>File", tooltip-placement="bottom")
|
||||
i.fa.fa-file
|
||||
a(href, tooltip="New Folder", tooltip-placement="bottom")
|
||||
i.fa.fa-folder
|
||||
a(href, tooltip="Upload File", tooltip-placement="bottom")
|
||||
i.fa.fa-upload
|
||||
|
||||
.toolbar-right
|
||||
a(href, tooltip="Rename", tooltip-placement="bottom")
|
||||
i.fa.fa-pencil
|
||||
a(href, tooltip="Delete", tooltip-placement="bottom", tooltip-append-to-body="true")
|
||||
i.fa.fa-trash-o
|
||||
|
||||
ul.list-unstyled.file-tree-list
|
||||
file-entity(
|
||||
entity="entity",
|
||||
ng-repeat="entity in rootFolder.children"
|
||||
)
|
||||
.ui-layout-center
|
||||
|
||||
script(type='text/ng-template', id='entityListItemTemplate')
|
||||
li(
|
||||
ng-class="{ 'selected': entity.selected }",
|
||||
ng-controller="FileTreeEntityController"
|
||||
)
|
||||
.entity(ng-if="entity.type == 'doc'")
|
||||
.entity-name(ng-click="select()")
|
||||
//- Just a spacer to align with folders
|
||||
i.fa.fa-fw.toggle
|
||||
i.fa.fa-fw.fa-file
|
||||
| {{ entity.name }}
|
||||
|
||||
.entity(ng-if="entity.type == 'file'")
|
||||
.entity-name(ng-click="select()")
|
||||
i.fa.fa-fw.toggle
|
||||
i.fa.fa-fw.fa-image
|
||||
| {{ entity.name }}
|
||||
|
||||
.entity(ng-if="entity.type == 'folder'", ng-controller="FileTreeFolderController")
|
||||
.entity-name
|
||||
i.fa.fa-fw.toggle(
|
||||
ng-class="{'fa-chevron-right': !expanded, 'fa-chevron-down': expanded}"
|
||||
ng-click="toggleExpanded()"
|
||||
)
|
||||
|
||||
i.fa.fa-fw(
|
||||
ng-class="{\
|
||||
'fa-folder': !expanded, \
|
||||
'fa-folder-open': expanded \
|
||||
}"
|
||||
ng-click="select()"
|
||||
)
|
||||
span(ng-click="select()") {{ entity.name }}
|
||||
|
||||
ul.list-unstyled(ng-show="expanded")
|
||||
file-entity(entity="child", ng-repeat="child in entity.children")
|
||||
|
||||
|
||||
//- #loadingScreen
|
||||
//- h3 Loading...
|
||||
//- p#loadingMessage Loading editor
|
||||
|
||||
//- #errorMessages
|
||||
//- #connectionLostMessage(style="display: none;")
|
||||
//- | Lost connection.
|
||||
//- span#trying-reconnect
|
||||
//- | Reconnecting in
|
||||
//- span#reconnection-countdown ?
|
||||
//- | seconds.
|
||||
//- a(href='#')#try-reconnect-now Try now.
|
||||
//- span#reconnecting
|
||||
//- | Reconnecting...
|
||||
|
||||
//- #savingProblems(style="display: none")
|
||||
//- | Saving...
|
||||
|
||||
//- div#toolbar.sidebar-navigation
|
||||
//- ul#tabs
|
||||
//- #toolbar-footer
|
||||
|
||||
//- #tab-content.tab-content
|
||||
|
||||
//- include ../templates
|
||||
//- include ../templates/dropbox
|
||||
|
||||
script(src='/socket.io/socket.io.js')
|
||||
|
||||
script(type='text/javascript').
|
||||
window.project_id = "!{project_id}"
|
||||
window.sharelatex = !{sharelatexObject};
|
||||
window.userSettings = !{userSettingsObject};
|
||||
window.user = !{userObject};
|
||||
|
@ -64,14 +159,15 @@ block content
|
|||
script(type='text/javascript').
|
||||
ga('send', 'event', 'editor-interaction', 'editor-opened')
|
||||
|
||||
- locals.supressDefaultJs = true
|
||||
- locals.suppressDefaultJs = true
|
||||
|
||||
- var fingerprintedPath = fingerprint(jsPath+'libs/pdf.worker.js')
|
||||
- var pdfJsWorkerPath = jsPath+'libs/pdf.worker.js?fingerprint='+fingerprintedPath
|
||||
script(type='text/javascript').
|
||||
window.sharelatex.pdfJsWorkerPath = "#{pdfJsWorkerPath}"
|
||||
|
||||
script(
|
||||
data-main=jsPath+'ide.js',
|
||||
data-main=jsPath+'app/ide.js',
|
||||
baseurl=jsPath,
|
||||
data-ace-base=jsPath+'ace',
|
||||
src=jsPath+'libs/require.js?fingerprint='+fingerprint(jsPath + 'libs/require.js')
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
define [
|
||||
"../libs/angular-autocomplete/angular-autocomplete"
|
||||
"../libs/ui-bootstrap"
|
||||
"modules/recursionHelper"
|
||||
], () ->
|
||||
App = angular.module("SharelatexApp", [
|
||||
"ui.bootstrap"
|
||||
"autocomplete"
|
||||
"RecursionHelper"
|
||||
])
|
||||
|
||||
return App
|
50
services/web/public/coffee/app/ide.coffee
Normal file
50
services/web/public/coffee/app/ide.coffee
Normal file
|
@ -0,0 +1,50 @@
|
|||
define [
|
||||
"base"
|
||||
"ide/file-tree/FileTreeManager"
|
||||
"ide/directives/layout"
|
||||
], (
|
||||
App
|
||||
FileTreeManager
|
||||
) ->
|
||||
App.controller "IdeController", ["$scope", "$timeout", ($scope, $timeout) ->
|
||||
$scope.state = {
|
||||
loading: true
|
||||
load_progress: 40
|
||||
}
|
||||
|
||||
window.ide = ide = {
|
||||
'$scope': $scope
|
||||
}
|
||||
ide.fileTreeManager = new FileTreeManager(ide, $scope)
|
||||
|
||||
$scope.project_id = window.project_id
|
||||
|
||||
ioOptions =
|
||||
reconnect: false
|
||||
"force new connection": true
|
||||
$scope.socket = io.connect null, ioOptions
|
||||
|
||||
$scope.socket.on "connect", () ->
|
||||
$scope.$apply () ->
|
||||
$scope.state.load_progress = 80
|
||||
|
||||
joinProject = () =>
|
||||
$scope.socket.emit 'joinProject', {
|
||||
project_id: $scope.project_id
|
||||
}, (err, project, permissionsLevel, protocolVersion) =>
|
||||
if $scope.protocolVersion? and $scope.protocolVersion != protocolVersion
|
||||
location.reload(true)
|
||||
|
||||
$scope.$apply () ->
|
||||
$scope.protocolVersion = protocolVersion
|
||||
$scope.project = project
|
||||
$scope.state.load_progress = 100
|
||||
$scope.state.loading = false
|
||||
|
||||
$scope.$emit "project:joined"
|
||||
|
||||
console.log "Project", $scope.project, $scope.rootFolder
|
||||
|
||||
setTimeout(joinProject, 100) ]
|
||||
|
||||
angular.bootstrap(document.body, ["SharelatexApp"])
|
25
services/web/public/coffee/app/ide/directives/layout.coffee
Normal file
25
services/web/public/coffee/app/ide/directives/layout.coffee
Normal file
|
@ -0,0 +1,25 @@
|
|||
define [
|
||||
"base"
|
||||
], (App) ->
|
||||
App.directive "layout", () ->
|
||||
return {
|
||||
link: (scope, element, attrs) ->
|
||||
name = attrs.layout
|
||||
|
||||
options =
|
||||
spacing_open: 24
|
||||
spacing_closed: 24
|
||||
onresize: () =>
|
||||
scope.$broadcast "layout:#{name}:resize"
|
||||
|
||||
# Restore previously recorded state
|
||||
if (state = $.localStorage("layout.main"))?
|
||||
options.west = state.west
|
||||
options.east = state.east
|
||||
|
||||
$(element).layout options
|
||||
|
||||
# Save state when exiting
|
||||
$(window).unload () ->
|
||||
$.localStorage("layout.#{name}", element.layout().readState())
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
define [
|
||||
"ide/file-tree/directives/fileEntity"
|
||||
"ide/file-tree/controllers/FileTreeFolderController"
|
||||
"ide/file-tree/controllers/FileTreeEntityController"
|
||||
], () ->
|
||||
class FileTreeManager
|
||||
constructor: (@ide, @$scope) ->
|
||||
@$scope.$on "project:joined", =>
|
||||
console.log "Joined"
|
||||
@loadRootFolder()
|
||||
|
||||
forEachEntity: (callback) ->
|
||||
@_forEachEntityInFolder(@$scope.rootFolder, callback)
|
||||
|
||||
_forEachEntityInFolder: (folder, callback) ->
|
||||
for entity in folder.children
|
||||
callback(entity)
|
||||
if entity.children?
|
||||
@_forEachEntityInFolder(entity, callback)
|
||||
|
||||
loadRootFolder: () ->
|
||||
@$scope.rootFolder = @_parseFolder(@$scope.project.rootFolder[0])
|
||||
|
||||
_parseFolder: (rawFolder) ->
|
||||
folder = {
|
||||
name: rawFolder.name
|
||||
id: rawFolder.id
|
||||
type: "folder"
|
||||
children: []
|
||||
}
|
||||
|
||||
for doc in rawFolder.docs or []
|
||||
folder.children.push {
|
||||
name: doc.name
|
||||
type: "doc"
|
||||
id: doc._id
|
||||
}
|
||||
|
||||
for file in rawFolder.fileRefs or []
|
||||
folder.children.push {
|
||||
name: file.name
|
||||
type: "file"
|
||||
id: file._id
|
||||
}
|
||||
|
||||
for childFolder in rawFolder.folders or []
|
||||
folder.children.push @_parseFolder(childFolder)
|
||||
|
||||
return folder
|
|
@ -0,0 +1,9 @@
|
|||
define [
|
||||
"base"
|
||||
], (App) ->
|
||||
App.controller "FileTreeEntityController", ["$scope", ($scope) ->
|
||||
$scope.select = ($event) ->
|
||||
ide.fileTreeManager.forEachEntity (entity) ->
|
||||
entity.selected = false
|
||||
$scope.entity.selected = true
|
||||
]
|
|
@ -0,0 +1,9 @@
|
|||
define [
|
||||
"base"
|
||||
], (App) ->
|
||||
App.controller "FileTreeFolderController", ["$scope", ($scope) ->
|
||||
$scope.expanded = false
|
||||
|
||||
$scope.toggleExpanded = () ->
|
||||
$scope.expanded = !$scope.expanded
|
||||
]
|
|
@ -0,0 +1,15 @@
|
|||
define [
|
||||
"base"
|
||||
], (App) ->
|
||||
App.directive "fileEntity", ["RecursionHelper", (RecursionHelper) ->
|
||||
return {
|
||||
restrict: "E"
|
||||
scope: {
|
||||
entity: "="
|
||||
}
|
||||
templateUrl: "entityListItemTemplate"
|
||||
compile: (element) ->
|
||||
RecursionHelper.compile element, (scope, element, attrs, ctrl) ->
|
||||
# Link function here if needed
|
||||
}
|
||||
]
|
|
@ -0,0 +1,44 @@
|
|||
#
|
||||
# * An Angular service which helps with creating recursive directives.
|
||||
# * @author Mark Lagendijk
|
||||
# * @license MIT
|
||||
#
|
||||
# From: https://github.com/marklagendijk/angular-recursion
|
||||
angular.module("RecursionHelper", []).factory "RecursionHelper", [
|
||||
"$compile"
|
||||
($compile) ->
|
||||
|
||||
###
|
||||
Manually compiles the element, fixing the recursion loop.
|
||||
@param element
|
||||
@param [link] A post-link function, or an object with function(s) registered via pre and post properties.
|
||||
@returns An object containing the linking functions.
|
||||
###
|
||||
return compile: (element, link) ->
|
||||
|
||||
# Normalize the link parameter
|
||||
link = post: link if angular.isFunction(link)
|
||||
|
||||
# Break the recursion loop by removing the contents
|
||||
contents = element.contents().remove()
|
||||
compiledContents = undefined
|
||||
pre: (if (link and link.pre) then link.pre else null)
|
||||
|
||||
###
|
||||
Compiles and re-adds the contents
|
||||
###
|
||||
post: (scope, element) ->
|
||||
|
||||
# Compile the contents
|
||||
compiledContents = $compile(contents) unless compiledContents
|
||||
|
||||
# Re-add the compiled contents to the element
|
||||
compiledContents scope, (clone) ->
|
||||
element.append clone
|
||||
return
|
||||
|
||||
|
||||
# Call the post-linking function, if any
|
||||
link.post.apply null, arguments if link and link.post
|
||||
return
|
||||
]
|
|
@ -6,7 +6,6 @@
|
|||
* Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php).
|
||||
* 2013/02/10
|
||||
**/
|
||||
define([], function() {
|
||||
;(function($, window, document) {
|
||||
'use strict';
|
||||
|
||||
|
@ -81,5 +80,3 @@ define([], function() {
|
|||
$[method].options = defaults;
|
||||
});
|
||||
}(jQuery, window, document));
|
||||
|
||||
});
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -813,3 +813,7 @@
|
|||
|
||||
@content-margin-top: @line-height-computed;
|
||||
@content-margin-top: @line-height-computed;
|
||||
|
||||
// Custom
|
||||
|
||||
@toolbar-border-color: @gray-lighter;
|
||||
|
|
Loading…
Reference in a new issue