Nate Stemen 9 лет назад
Родитель
Сommit
428ae3aa53

+ 28 - 0
services/web/app/coffee/Features/Labels/LabelsController.coffee

@@ -0,0 +1,28 @@
+EditorRealTimeController = require "../Editor/EditorRealTimeController"
+LabelsHandler = require './LabelsHandler'
+logger = require 'logger-sharelatex'
+
+
+module.exports = LabelsController =
+
+	getAllLabels: (req, res, next) ->
+		project_id = req.params.project_id
+		logger.log {project_id}, "getting all labels for project"
+		LabelsHandler.getAllLabelsForProject project_id, (err, projectLabels) ->
+			if err?
+				logger.err {project_id, err}, "[LabelsController] error getting all labels from project"
+				return next(err)
+			res.json {projectId: project_id, projectLabels: projectLabels}
+
+	broadcastLabelsForDoc: (req, res, next) ->
+		project_id = req.params.project_id
+		doc_id = req.params.doc_id
+		logger.log {project_id, doc_id}, "getting labels for doc"
+		LabelsHandler.getLabelsForDoc project_id, doc_id, (err, docLabels) ->
+			if err?
+				logger.err {project_id, doc_id, err}, "[LabelsController] error getting labels from doc"
+				return next(err)
+			EditorRealTimeController.emitToRoom project_id, 'broadcastDocLabels', {
+				docId: doc_id, labels: docLabels
+			}
+			res.sendStatus(200)

+ 43 - 0
services/web/app/coffee/Features/Labels/LabelsHandler.coffee

@@ -0,0 +1,43 @@
+ProjectEntityHandler = require "../Project/ProjectEntityHandler"
+DocumentUpdaterHandler = require('../DocumentUpdater/DocumentUpdaterHandler')
+
+
+module.exports = LabelsHandler =
+
+	labelCaptureRegex: () ->
+		/\\label\{([^\}\n\\]{0,80})\}/g
+
+	getAllLabelsForProject: (projectId, callback=(err, projectLabels)->) ->
+		DocumentUpdaterHandler.flushProjectToMongo projectId, (err) ->
+			if err?
+				return callback(err)
+			ProjectEntityHandler.getAllDocs projectId, (err, docs) ->
+				if err?
+					return callback(err)
+				projectLabels = LabelsHandler.extractLabelsFromProjectDocs docs
+				callback(null, projectLabels)
+
+	getLabelsForDoc: (projectId, docId, callback=(err, docLabels)->) ->
+		DocumentUpdaterHandler.flushDocToMongo projectId, docId, (err) ->
+			if err?
+				return callback(err)
+			ProjectEntityHandler.getDoc projectId, docId, (err, lines) ->
+				if err?
+					return callback(err)
+				docLabels = LabelsHandler.extractLabelsFromDoc lines
+				callback(null, docLabels)
+
+	extractLabelsFromDoc: (lines) ->
+		docLabels = []
+		for line in lines
+			re = LabelsHandler.labelCaptureRegex()
+			while (labelMatch = re.exec(line))
+				if labelMatch[1]
+					docLabels.push(labelMatch[1])
+		return docLabels
+
+	extractLabelsFromProjectDocs: (projectDocs) ->
+		projectLabels = {}  # docId => List[Label]
+		for _path, doc of projectDocs
+			projectLabels[doc._id] = LabelsHandler.extractLabelsFromDoc(doc.lines)
+		return projectLabels

+ 4 - 0
services/web/app/coffee/router.coffee

@@ -44,6 +44,7 @@ SudoModeMiddlewear = require('./Features/SudoMode/SudoModeMiddlewear')
 AnalyticsRouter = require('./Features/Analytics/AnalyticsRouter')
 AnnouncementsController = require("./Features/Announcements/AnnouncementsController")
 MetaController = require('./Features/Metadata/MetaController')
+LabelsController = require('./Features/Labels/LabelsController')
 
 logger = require("logger-sharelatex")
 _ = require("underscore")
@@ -204,6 +205,9 @@ module.exports = class Router
 		webRouter.get '/project/:project_id/metadata', AuthorizationMiddlewear.ensureUserCanReadProject, AuthenticationController.requireLogin(), MetaController.getMetadata
 		webRouter.post '/project/:project_id/doc/:doc_id/metadata', AuthorizationMiddlewear.ensureUserCanReadProject, AuthenticationController.requireLogin(), MetaController.broadcastMetadataForDoc
 
+		webRouter.get '/project/:project_id/labels', AuthorizationMiddlewear.ensureUserCanReadProject, AuthenticationController.requireLogin(), LabelsController.getAllLabels
+		webRouter.post '/project/:project_id/doc/:doc_id/labels', AuthorizationMiddlewear.ensureUserCanReadProject, AuthenticationController.requireLogin(), LabelsController.broadcastLabelsForDoc
+
 		webRouter.get    '/tag', AuthenticationController.requireLogin(), TagsController.getAllTags
 		webRouter.post   '/tag', AuthenticationController.requireLogin(), TagsController.createTag
 		webRouter.post   '/tag/:tag_id/rename', AuthenticationController.requireLogin(), TagsController.renameTag

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

@@ -10,10 +10,12 @@ define [
 	"ide/editor/directives/aceEditor/cursor-position/CursorPositionManager"
 	"ide/editor/directives/aceEditor/track-changes/TrackChangesManager"
 	"ide/editor/directives/aceEditor/metadata/MetadataManager"
+	"ide/editor/directives/aceEditor/labels/LabelsManager"
+	"ide/labels/servies/labels"
 	"ide/metadata/services/metadata"
 	"ide/graphics/services/graphics"
 	"ide/preamble/services/preamble"
-], (App, Ace, SearchBox, ModeList, UndoManager, AutoCompleteManager, SpellCheckManager, HighlightsManager, CursorPositionManager, TrackChangesManager, MetadataManager) ->
+], (App, Ace, SearchBox, ModeList, UndoManager, AutoCompleteManager, SpellCheckManager, HighlightsManager, CursorPositionManager, TrackChangesManager, MetadataManager, LabelsManager) ->
 	EditSession = ace.require('ace/edit_session').EditSession
 	ModeList = ace.require('ace/ext/modelist')
 
@@ -36,7 +38,7 @@ define [
 			return url
 
 
-	App.directive "aceEditor", ($timeout, $compile, $rootScope, event_tracking, localStorage, $cacheFactory, metadata, graphics, preamble) ->
+	App.directive "aceEditor", ($timeout, $compile, $rootScope, event_tracking, localStorage, $cacheFactory, labels, metadata, graphics, preamble) ->
 		monkeyPatchSearch($rootScope, $compile)
 
 		return  {
@@ -103,8 +105,9 @@ define [
 				highlightsManager     = new HighlightsManager(scope, editor, element)
 				cursorPositionManager = new CursorPositionManager(scope, editor, element, localStorage)
 				trackChangesManager   = new TrackChangesManager(scope, editor, element)
+				labelsManager = new LabelsManager(scope, editor, element, labels)
 				metadataManager = new MetadataManager(scope, editor, element, metadata)
-				autoCompleteManager = new AutoCompleteManager(scope, editor, element, metadataManager, graphics, preamble)
+				autoCompleteManager = new AutoCompleteManager(scope, editor, element, metadataManager, labelsManager, graphics, preamble)
 
 
 				# Prevert Ctrl|Cmd-S from triggering save dialog

+ 1 - 1
services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee

@@ -9,7 +9,7 @@ define [
 	aceSnippetManager = ace.require('ace/snippets').snippetManager
 
 	class AutoCompleteManager
-		constructor: (@$scope, @editor, @element, @metadataManager, @graphics, @preamble) ->
+		constructor: (@$scope, @editor, @element, @metadataManager, @labelsManager, @graphics, @preamble) ->
 
 			@monkeyPatchAutocomplete()
 

+ 13 - 0
services/web/public/coffee/ide/labels/LabelsManager.coffee

@@ -0,0 +1,13 @@
+define [], () ->
+
+	class LabelsManager
+
+		constructor: (@ide, @$scope, @labels) ->
+
+			@ide.socket.on 'broadcastDocLabels', (data) =>
+				@labels.onBroadcastDocLabels(data)
+			@$scope.$on 'entity:deleted', @labels.onEntityDeleted
+			@$scope.$on 'file:upload:complete', @labels.fileUploadComplete
+
+		loadProjectLabelsFromServer: () ->
+			@labels.loadProjectLabelsFromServer()

+ 44 - 0
services/web/public/coffee/ide/labels/services/labels.coffee

@@ -0,0 +1,44 @@
+define [
+	"base"
+], (App) ->
+
+	App.factory 'labels', ($http, ide) ->
+
+		state = {documents: {}}
+
+		labels = {
+			state: state
+		}
+
+		labels.onBroadcastDocLabels = (data) ->
+			if data.docId and data.labels
+				state.documents[data.docId] = data.labels
+
+		labels.onEntityDeleted = (e, entity) ->
+			if entity.type == 'doc'
+				delete state.documents[entity.id]
+
+		labels.onFileUploadComplete = (e, upload) ->
+			if upload.entity_type == 'doc'
+				labels.loadDocLabelsFromServer(upload.entity_id)
+
+		labels.getAllLabels = () ->
+			_.flatten(labels for docId, labels of state.documents)
+
+		labels.loadProjectLabelsFromServer = () ->
+			$http
+				.get("/project/#{window.project_id}/labels")
+				.then (response) ->
+					{ data } = response
+					if data.projectLabels
+						for docId, docLabels of data.projectLabels
+							state.documents[docId] = docLabels
+
+		labels.loadDocLabelsFromServer = (docId) ->
+			$http
+				.post(
+					"/project/#{window.project_id}/doc/#{docId}/labels",
+					{_csrf: window.csrfToken}
+				)
+
+		return labels