Просмотр исходного кода

Merge branch 'master-redesign' into master-redesign-templates-and-blog

Henry Oswald 12 лет назад
Родитель
Сommit
ba4d585854

+ 24 - 9
services/web/app/views/project/editor.jade

@@ -8,7 +8,7 @@ block vars
 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/bootstrap-3.1.1.js')
 	script(src=jsPath+'libs/jquery-layout.js')
 	script(src=jsPath+'libs/jquery.storage.js')
 
@@ -35,17 +35,32 @@ block content
 
 		include ./editor/left-menu
 
-		include ./editor/header
+		#chat-wrapper(
+			layout="chat",
+			spacing-open="12",
+			spacing-closed="0",
+			initial-size-east="250",
+			init-closed-east="true",
+			open-east="ui.chatOpen",
+			ng-hide="state.loading",
+			ng-cloak
+		)
+			.ui-layout-center
+				include ./editor/header
 
-		include ./editor/share
+				include ./editor/share
 
-		#ide-body(ng-cloak, layout="main", ng-hide="state.loading")
-			.ui-layout-west
-				include ./editor/file-tree
+				#ide-body(ng-cloak, layout="main", ng-hide="state.loading", resize-on="layout:chat:resize")
+					.ui-layout-west
+						include ./editor/file-tree
+
+					.ui-layout-center
+						include ./editor/editor
+						include ./editor/track-changes
+
+			.ui-layout-east
+				| Chat!
 
-			.ui-layout-center
-				include ./editor/editor
-				include ./editor/track-changes
 
 	script(src='/socket.io/socket.io.js')
 

+ 2 - 0
services/web/app/views/project/editor/editor.jade

@@ -2,6 +2,8 @@ div.full-size(
 	ng-show="ui.view == 'editor'"
 	layout="pdf"
 	resize-on="layout:main:resize"
+	resize-proportionally="true"
+	initial-size-east="'50%'"
 )
 	.ui-layout-center
 		.loading-panel(ng-show="!editor.sharejs_doc || editor.opening")

+ 8 - 1
services/web/app/views/project/editor/header.jade

@@ -29,5 +29,12 @@ header.toolbar.toolbar-header(ng-cloak, ng-hide="state.loading")
 			tooltip-placement="bottom"
 		)
 			i.fa.fa-fw.fa-history
-		a.btn.btn-full-height(href='#', tooltip="Chat", tooltip-placement="bottom")
+		a.btn.btn-full-height(
+			href,
+			tooltip="Chat",
+			tooltip-placement="bottom",
+			ng-class="{ active: ui.chatOpen }",
+			ng-click="toggleChat()",
+			ng-controller="ChatButtonController"
+		)
 			i.fa.fa-fw.fa-comment

+ 108 - 64
services/web/app/views/project/editor/left-menu.jade

@@ -2,76 +2,120 @@ aside#left-menu.full-size(
 	ng-class="{ 'shown': ui.leftMenuShown }"
 	ng-cloak
 )
-	h4 Settings
-	form(ng-controller="SettingsController")
-		.form-controls
-			label(for="compiler") Compiler
-			select.form-control(
-				name="compiler"
-				ng-model="project.compiler"
-			)
-				option(value='pdflatex') pdfLaTeX
-				option(value='latex') LaTeX
-				option(value='xelatex') XeLaTeX
-				option(value='lualatex') LuaLaTeX
+	h4 Download
 
-		.form-controls
-			label(for="spellCheckLanguage") Spell Check
-			select.form-control(
-				name="spellCheckLanguage"
-				ng-model="project.spellCheckLanguage"
+	ul.unformatted-list.nav.nav-downloads
+		li
+			a(
+				ng-href="/project/{{project_id}}/download/zip"
+				target="_blank"
 			)
-				option(value="") Off
-				optgroup(label="Language")
-					for language in languages
-						option(
-							value=language.code
-						)= language.name
-
-		.form-controls
-			label(for="autoComplete") Auto-Complete
-			input.form-control(
-				type="checkbox"
-				name="autoComplete"
-				ng-model="settings.autoComplete"
+				i.fa.fa-file-archive-o.fa-2x
+				br
+				| Source
+		li
+			a(
+				ng-href="/project/{{project_id}}/{{pdf.url}}"
+				target="_blank"
+				ng-if="pdf.url"
 			)
-
-		.form-controls
-			label(for="theme") Theme
-			select.form-control(
-				name="theme"
-				ng-model="settings.theme"
+				i.fa.fa-file-pdf-o.fa-2x
+				br
+				| PDF
+			div.pdf-disabled(
+				ng-if="!pdf.url"
+				tooltip="Please compile your project before downloading the PDF"
+				tooltip-placement="bottom"
 			)
-				each theme in themes
-					option(value=theme) #{theme}
-					
-		.form-controls
-			label(for="mode") Keybindings
-			select.form-control(
-				name="mode"
-				ng-model="settings.mode"
-			)
-				option(value='default') None
-				option(value='vim') Vim
-				option(value='emacs') Emacs
+				i.fa.fa-file-pdf-o.fa-2x
+				br
+				| PDF
 
-		.form-controls
-			label(for="fontSize") Font Size
-			select.form-control(
-				name="fontSize"
-				ng-model="settings.fontSize"
-			)
-				each size in ['10','11','12','13','14','16','20','24']
-					option(value=size) #{size}px
+	h4 Settings
+	form.settings(ng-controller="SettingsController")
+		.containter-fluid
+			.form-controls
+				.row
+					label.col-md-6(for="compiler") Compiler
+					.col-md-6
+						select.form-control(
+							name="compiler"
+							ng-model="project.compiler"
+						)
+							option(value='pdflatex') pdfLaTeX
+							option(value='latex') LaTeX
+							option(value='xelatex') XeLaTeX
+							option(value='lualatex') LuaLaTeX
 
-		.form-controls
-			label(for="pdfViewer") PDF Viewer
-			select.form-control(
-				name="pdfViewer"
-				ng-model="settings.pdfViewer"
-			)
-				option(value="pdfjs") Built-In
-				option(value="native") Native
+			.form-controls
+				.row
+					label.col-md-6(for="spellCheckLanguage") Spell Check
+					.col-md-6
+						select.form-control(
+							name="spellCheckLanguage"
+							ng-model="project.spellCheckLanguage"
+						)
+							option(value="") Off
+							optgroup(label="Language")
+								for language in languages
+									option(
+										value=language.code
+									)= language.name
+
+			.form-controls
+				.row
+					label.col-md-6(for="autoComplete") Auto-Complete
+					.col-md-6
+						select.form-control(
+							name="autoComplete"
+							ng-model="settings.autoComplete"
+							ng-options="o.v as o.n for o in [{ n: 'On', v: true }, { n: 'Off', v: false }]"
+						)
+
+			.form-controls
+				.row
+					label.col-md-6(for="theme") Theme
+					.col-md-6
+						select.form-control(
+							name="theme"
+							ng-model="settings.theme"
+						)
+							each theme in themes
+								option(value=theme) #{theme}
+
+			.form-controls
+				.row
+					label.col-md-6(for="mode") Keybindings
+					.col-md-6
+						select.form-control(
+							name="mode"
+							ng-model="settings.mode"
+						)
+							option(value='default') None
+							option(value='vim') Vim
+							option(value='emacs') Emacs
+
+			.form-controls
+				.row
+					label.col-md-6(for="fontSize") Font Size
+					.col-md-6
+						select.form-control(
+							name="fontSize"
+							ng-model="settings.fontSize"
+						)
+							each size in ['10','11','12','13','14','16','20','24']
+								option(value=size) #{size}px
+
+			.form-controls
+				.row
+					label.col-md-6(for="pdfViewer") PDF Viewer
+					.col-md-6
+						select.form-control(
+							name="pdfViewer"
+							ng-model="settings.pdfViewer"
+						)
+							option(value="pdfjs") Built-In
+							option(value="native") Native
 
 #left-menu-mask(
 	ng-show="ui.leftMenuShown",

+ 2 - 0
services/web/public/coffee/app/ide.coffee

@@ -8,6 +8,7 @@ define [
 	"ide/pdf/PdfManager"
 	"ide/settings/index"
 	"ide/share/index"
+	"ide/chat/index"
 	"ide/directives/layout"
 	"ide/services/ide"
 	"directives/focus"
@@ -40,6 +41,7 @@ define [
 		$scope.ui = {
 			leftMenuShown: false
 			view: "editor"
+			chatOpen: false
 		}
 		$scope.user = window.user
 		$scope.settings = window.userSettings

+ 7 - 0
services/web/public/coffee/app/ide/chat/controllers/ChatButtonController.coffee

@@ -0,0 +1,7 @@
+define [
+	"base"
+], (App) ->
+	App.controller "ChatButtonController", ["$scope", ($scope) ->
+		$scope.toggleChat = () ->
+			$scope.ui.chatOpen = !$scope.ui.chatOpen
+	]

+ 3 - 0
services/web/public/coffee/app/ide/chat/index.coffee

@@ -0,0 +1,3 @@
+define [
+	"ide/chat/controllers/ChatButtonController"
+], () ->

+ 97 - 42
services/web/public/coffee/app/ide/directives/layout.coffee

@@ -1,46 +1,101 @@
 define [
 	"base"
 ], (App) ->
-	App.directive "layout", () ->
+	App.directive "layout", ["$parse", ($parse) ->
 		return {
-			link: (scope, element, attrs) ->
-				name = attrs.layout
-
-				options =
-					spacing_open: 24
-					spacing_closed: 24
-					onresize: () =>
-						onResize()
-					maskIframesOnResize: scope.$eval(
-						attrs.maskIframesOnResize or "false"
-					)
-
-				onResize = () ->
-					state = element.layout().readState()
-					scope.$broadcast "layout:#{name}:resize", state
-					repositionControls()
-
-				# Restore previously recorded state
-				if (state = $.localStorage("layout.#{name}"))?
-					options.west = state.west
-					options.east = state.east
-
-				element.layout options
-				element.layout().resizeAll()
-
-				if attrs.resizeOn?
-					scope.$on attrs.resizeOn, () -> element.layout().resizeAll()
-
-				# Save state when exiting
-				$(window).unload () ->
-					$.localStorage("layout.#{name}", element.layout().readState())
-
-				repositionControls = () ->
-					state = element.layout().readState()
-					if state.east?
-						element.find(".ui-layout-resizer-controls").css({
-							position: "absolute"
-							right: state.east.size
-							"z-index": 10
-						})
-		}
+			compile: () ->
+				pre: (scope, element, attrs) ->
+					name = attrs.layout
+
+					if attrs.spacingOpen?
+						spacingOpen = parseInt(attrs.spacingOpen, 10)
+					else
+						spacingOpen = 24
+
+					if attrs.spacingClosed?
+						spacingClosed = parseInt(attrs.spacingClosed, 10)
+					else
+						spacingClosed = 24
+
+					options =
+						spacing_open: spacingOpen
+						spacing_closed: spacingClosed
+						slidable: false
+						onresize: () =>
+							onInternalResize()
+						maskIframesOnResize: scope.$eval(
+							attrs.maskIframesOnResize or "false"
+						)
+						east:
+							size: scope.$eval(attrs.initialSizeEast)
+							initClosed: scope.$eval(attrs.initClosedEast)
+						west:
+							size: scope.$eval(attrs.initialSizeEast)
+							initClosed: scope.$eval(attrs.initClosedWest)
+
+					# Restore previously recorded state
+					if (state = $.localStorage("layout.#{name}"))?
+						options.west = state.west
+						options.east = state.east
+
+					# Someone moved the resizer
+					onInternalResize = () ->
+						state = element.layout().readState()
+						scope.$broadcast "layout:#{name}:resize", state
+						repositionControls()
+						resetOpenStates()
+
+					oldWidth = element.width()
+					# Something resized our parent element
+					onExternalResize = () ->
+						console.log "EXTERNAL RESIOZE", name, attrs.resizeProportionally
+						if attrs.resizeProportionally? and scope.$eval(attrs.resizeProportionally)
+							eastState = element.layout().readState().east
+							if eastState?
+								newInternalWidth = eastState.size / oldWidth * element.width()
+								oldWidth = element.width()
+								element.layout().sizePane("east", newInternalWidth)
+								return
+							
+						element.layout().resizeAll()
+
+					element.layout options
+					element.layout().resizeAll()
+
+					if attrs.resizeOn?
+						scope.$on attrs.resizeOn, () -> onExternalResize()
+
+					# Save state when exiting
+					$(window).unload () ->
+						$.localStorage("layout.#{name}", element.layout().readState())
+
+					repositionControls = () ->
+						state = element.layout().readState()
+						if state.east?
+							element.find("> .ui-layout-resizer-controls").css({
+								position: "absolute"
+								right: state.east.size
+								"z-index": 10
+							})
+
+					resetOpenStates = () ->
+						state = element.layout().readState()
+						if attrs.openEast?
+							openEast = $parse(attrs.openEast)
+							openEast.assign(scope, !state.east.initClosed)
+
+					if attrs.openEast?
+						scope.$watch attrs.openEast, (value, oldValue) ->
+							console.log "Open East", value, oldValue
+							if value? and value != oldValue
+								if value
+									element.layout().open("east")
+								else
+									element.layout().close("east")
+							setTimeout () ->
+								scope.$digest()
+							, 0
+
+					resetOpenStates()
+		}
+	]

+ 1 - 1
services/web/public/coffee/app/ide/editor/EditorManager.coffee

@@ -9,7 +9,7 @@ define [
 				last_updated: null
 				open_doc_id: null
 				opening: true
-				cursorPosition: null
+				cursorPosition: {}
 				gotoLine: null
 			}
 

+ 16 - 12
services/web/public/coffee/app/ide/editor/auto-complete/AutoCompleteManager.coffee

@@ -29,19 +29,23 @@ define [
 		constructor: (@$scope, @editor) ->
 			@suggestionManager = new SuggestionManager()
 
-			insertMatch = Autocomplete::insertMatch
-			editor = @editor
-			Autocomplete::insertMatch = (data) ->
-				pos = editor.getCursorPosition()
-				range = new Range(pos.row, pos.column, pos.row, pos.column + 1)
-				nextChar = editor.session.getTextRange(range)
+			if !Autocomplete::_insertMatch?
+				# Only override this once since it's global but we may create multiple
+				# autocomplete handlers
+				Autocomplete::_insertMatch = Autocomplete::insertMatch
+				Autocomplete::insertMatch = (data) ->
+					pos = editor.getCursorPosition()
+					range = new Range(pos.row, pos.column, pos.row, pos.column + 1)
+					nextChar = editor.session.getTextRange(range)
 
-				# If we are in \begin{it|}, then we need to remove the trailing }
-				# since it will be adding in with the autocomplete of \begin{item}...
-				if this.completions.filterText.match(/^\\begin\{/) and nextChar == "}"
-					editor.session.remove(range)
-				
-				insertMatch.call editor.completer, data
+					console.log "INSERT MATCH", this
+
+					# If we are in \begin{it|}, then we need to remove the trailing }
+					# since it will be adding in with the autocomplete of \begin{item}...
+					if this.completions.filterText.match(/^\\begin\{/) and nextChar == "}"
+						editor.session.remove(range)
+					
+					Autocomplete::_insertMatch.call this, data
 
 			@$scope.$watch "autoComplete", (autocomplete) =>
 				console.log "autocomplete change", autocomplete

+ 2 - 2
services/web/public/coffee/app/ide/editor/cursor-position/CursorPositionManager.coffee

@@ -13,9 +13,9 @@ define [], () ->
 
 			@editor.on "changeSelection", () =>
 				cursor = @editor.getCursorPosition()
-				console.log "Updating cursor position", cursor
 				@$scope.$apply () =>
-					@$scope.cursorPosition = cursor
+					if @$scope.cursorPosition?
+						@$scope.cursorPosition = cursor
 
 			@$scope.$watch "gotoLine", (value) =>
 				console.log "Going to line", value

+ 5 - 6
services/web/public/coffee/app/ide/editor/directives/aceEditor.coffee

@@ -10,7 +10,7 @@ define [
 	"ace/keyboard/emacs"
 	"ace/mode/latex"
 	"ace/edit_session"
-], (App, Ace, UndoManager, AutoCompleteManager, SpellCheckManager, AnnotationsManager, CursorPositionManager) ->
+], (App, Ace, UndoManager, AutoCompleteManager, SpellCheckManager, HighlightsManager, CursorPositionManager) ->
 	LatexMode = require("ace/mode/latex").Mode
 	EditSession = require('ace/edit_session').EditSession
 
@@ -42,12 +42,14 @@ define [
 					else
 						@$originalApply(fn);
 
-				window.editor = editor = Ace.edit(element.find(".ace-editor-body")[0])
+				editor = Ace.edit(element.find(".ace-editor-body")[0])
+				window.editors ||= []
+				window.editors.push editor
 
 				autoCompleteManager   = new AutoCompleteManager(scope, editor, element)
 				spellCheckManager     = new SpellCheckManager(scope, editor, element)
 				undoManager           = new UndoManager(scope, editor, element)
-				annotationsManager    = new AnnotationsManager(scope, editor, element)
+				highlightsManager     = new HighlightsManager(scope, editor, element)
 				cursorPositionManager = new CursorPositionManager(scope, editor, element)
 
 				# Prevert Ctrl|Cmd-S from triggering save dialog
@@ -117,9 +119,6 @@ define [
 					resetSession()
 					session = editor.getSession()
 
-					autoCompleteManager.bindToSession(session)
-					annotationsManager.redrawAnnotations()
-
 					doc = session.getDocument()
 					doc.on "change", () ->
 						scope.$apply () ->

+ 3 - 0
services/web/public/coffee/app/ide/editor/highlights/HighlightsManager.coffee

@@ -29,6 +29,9 @@ define [
 				e.position = position
 				@showAnnotationLabels(position)
 
+			@editor.on "changeSession", () =>
+				@redrawAnnotations()
+
 		redrawAnnotations: () ->
 			@_clearMarkers()
 			@_clearLabels()

+ 1 - 0
services/web/public/coffee/app/ide/editor/spell-check/SpellCheckManager.coffee

@@ -28,6 +28,7 @@ define [
 
 			$(document).on "click", (e) =>
 				@closeContextMenu(e)
+				return true
 			# $(document).on "contextmenu", (e) =>
 			# 	@closeContextMenu(e)
 

+ 0 - 1
services/web/public/coffee/app/ide/pdf/controllers/PdfController.coffee

@@ -227,7 +227,6 @@ define [
 	App.controller "PdfSynctexController", ["$scope", "synctex", "ide", ($scope, synctex, ide) ->
 		$scope.showControls = true
 		$scope.$on "layout:pdf:resize", (event, data) ->
-			console.log "RESIZE DATA", data.east
 			if data.east.initClosed
 				$scope.showControls = false
 			else

+ 2 - 0
services/web/public/coffee/auto-complete/AutoCompleteManager.coffee

@@ -47,6 +47,8 @@ define [
 				range = new Range(pos.row, pos.column, pos.row, pos.column + 1)
 				nextChar = editor.session.getTextRange(range)
 
+				console.log "CALLING OLD"
+
 				# If we are in \begin{it|}, then we need to remove the trailing }
 				# since it will be adding in with the autocomplete of \begin{item}...
 				if this.completions.filterText.match(/^\\begin\{/) and nextChar == "}"

+ 7 - 0
services/web/public/stylesheets/app/editor.less

@@ -22,6 +22,13 @@
 	margin-left: -200px;
 }
 
+#chat-wrapper {
+	.full-size;
+	> .ui-layout-resizer > .ui-layout-toggler {
+		display: none !important;
+	}
+}
+
 #ide-body {
 	.full-size;
 	top: 40px;

+ 63 - 6
services/web/public/stylesheets/app/editor/left-menu.less

@@ -1,14 +1,16 @@
 #left-menu {
 	position: absolute;
-	width: 210px;
-	padding: 10px;
+	width: 260px;
+	padding: (@line-height-computed / 2);
 	top: 0;
 	bottom: 0;
 	background-color: #f4f4f4;
 	z-index: 100;
-	overflow: auto;
+	overflow-y: auto;
+	overflow-x: hidden;
 	-webkit-transition: left ease-in-out 0.35s;
 	transition: left ease-in-out 0.35s;
+	font-size: 14px;
 
 	left: -280px;
 	&.shown {
@@ -16,14 +18,69 @@
 	}
 
 	h4 {
-		font-family: @font-family-serif;
+		font-family: @font-family-sans-serif;
 		font-weight: 400;
 		font-size: 1rem;
 		margin: (@line-height-computed / 2) 0;
 		padding-bottom: (@line-height-computed / 4);
 		color: @gray-light;
-		border-bottom: 1px solid @gray-light;
-		text-transform: uppercase;
+		border-bottom: 1px solid @gray-lighter;
+	}
+
+	h4:first-child {
+		margin-top: 0;
+	}
+
+	ul.nav-downloads {
+		li {
+			display: inline-block;
+			text-align: center;
+			width: 100px;
+			a {
+				color: @gray-dark;
+				&:hover, &:active {
+					background-color: @link-color;
+					color: white;
+				}
+			}
+			.pdf-disabled {
+				color: @gray-light;
+			}
+			i {
+				margin-bottom: (@line-height-computed / 4);
+			}
+		}
+	}
+
+	form.settings {
+		label {
+			font-weight: normal;
+			color: @gray-dark;
+			margin-bottom: 0;
+			padding-top: 8px;
+		}
+		select.form-control {
+			height: 34px;
+			background: none;
+			border: none;
+			box-shadow: none;
+			color: @link-color;
+			cursor: pointer;
+			font-size: 14px;
+			font-weight: 700;
+		}
+		.form-controls {
+			padding: 0 (@line-height-computed / 4);
+			&:hover {
+				background-color: @link-color;
+				select.form-control {
+					color: white;
+				}
+				label {
+					color: white;
+				}
+			}
+		}
 	}
 }
 

+ 2 - 1
services/web/public/stylesheets/app/editor/toolbar.less

@@ -25,7 +25,8 @@
 		border-radius: 0;
 		border-right: 1px solid @toolbar-border-color;
 		color: @link-color;
-		padding: 6px 12px 8px;
+		padding: 3px 10px 5px;
+		font-size: 20px;
 		&:hover {
 			text-shadow: 0 1px 0 rgba(0, 0, 0, 0.15);
 			background-color: darken(white, 10%);