Explorar o código

Merge pull request #432 from sharelatex/es-modules

Set up compilation of ES code in modules and extract RT management code
Alasdair Smith %!s(int64=8) %!d(string=hai) anos
pai
achega
47e2d8c9f9

+ 2 - 0
services/web/.gitignore

@@ -49,6 +49,8 @@ TpdsWorker.js
 BackgroundJobsWorker.js
 UserAndProjectPopulator.coffee
 
+public/es/modules
+
 public/js/*.js
 public/js/*.map
 public/js/libs/sharejs.js

+ 9 - 2
services/web/Makefile.module

@@ -1,13 +1,16 @@
 MODULE_NAME := $(notdir $(shell pwd))
 MODULE_DIR := modules/$(MODULE_NAME)
 COFFEE := ../../node_modules/.bin/coffee
-APP_COFFEE_FILES := $(shell find app/coffee -name '*.coffee') \
+APP_COFFEE_FILES := $(shell [ -e app/coffee ] && find app/coffee -name '*.coffee') \
 	$(shell [ -e test/unit/coffee ] && find test/unit/coffee -name '*.coffee') \
 	$(shell [ -e test/acceptance/coffee ] && find test/acceptance/coffee -name '*.coffee')
 APP_JS_FILES := $(subst coffee,js,$(APP_COFFEE_FILES))
 IDE_COFFEE_FILES := $(shell [ -e public/coffee/ide ] && find public/coffee/ide -name '*.coffee')
 IDE_JS_FILES := $(subst public/coffee/ide,../../public/js/ide/$(MODULE_NAME),$(IDE_COFFEE_FILES))
 IDE_JS_FILES := $(subst coffee,js,$(IDE_JS_FILES))
+IDE_TEST_COFFEE_FILES := $(shell [ -e test/unit_frontend/coffee ] && find test/unit_frontend/coffee -name '*.coffee')
+IDE_TEST_JS_FILES := $(subst test/unit_frontend/coffee/ide,../../test/unit_frontend/js/ide/$(MODULE_NAME),$(IDE_TEST_COFFEE_FILES))
+IDE_TEST_JS_FILES := $(subst coffee,js,$(IDE_TEST_JS_FILES))
 MAIN_COFFEE_FILES := $(shell [ -e public/coffee/main ] && find public/coffee/main -name '*.coffee')
 MAIN_JS_FILES := $(subst public/coffee/main,../../public/js/main/$(MODULE_NAME),$(MAIN_COFFEE_FILES))
 MAIN_JS_FILES := $(subst coffee,js,$(MAIN_JS_FILES))
@@ -26,6 +29,10 @@ test/acceptance/js/%.js: test/acceptance/coffee/%.coffee
 	@mkdir -p $(dir $@)
 	$(COFFEE) --compile --print $< > $@
 
+../../test/unit_frontend/js/ide/$(MODULE_NAME)/%.js: test/unit_frontend/coffee/ide/%.coffee
+	@mkdir -p $(dir $@)
+	$(COFFEE) --compile --print $< > $@
+
 ../../public/js/ide/$(MODULE_NAME)/%.js: public/coffee/ide/%.coffee
 	@mkdir -p $(dir $@)
 	$(COFFEE) --compile --print $< > $@
@@ -37,7 +44,7 @@ test/acceptance/js/%.js: test/acceptance/coffee/%.coffee
 index.js: index.coffee
 	$(COFFEE) --compile --print $< > $@
 
-compile: $(APP_JS_FILES) $(IDE_JS_FILES) $(MAIN_JS_FILES) index.js
+compile: $(APP_JS_FILES) $(IDE_JS_FILES) $(MAIN_JS_FILES) $(IDE_TEST_JS_FILES) index.js
 	@echo > /dev/null
 
 compile_full:

+ 2 - 0
services/web/app/coffee/infrastructure/ExpressLocals.coffee

@@ -150,6 +150,8 @@ module.exports = (app, webRouter, privateApiRouter, publicApiRouter)->
 		res.locals.buildWebpackPath = (jsFile, opts = {}) ->
 			if Settings.webpack? and !Settings.useMinifiedJs
 				path = Path.join(jsPath, jsFile)
+				if opts.removeExtension == true
+					path = path.slice(0,-3)
 				return "#{Settings.webpack.url}/public#{path}"
 			else
 				return res.locals.buildJsPath(jsFile, opts)

+ 1 - 6
services/web/app/views/project/editor.pug

@@ -133,6 +133,7 @@ block requirejs
 				"fineuploader": "libs/#{lib('fineuploader')}",
 				"ide": "#{buildJsPath('ide.js', {hashedPath:settings.useMinifiedJs, removeExtension:true})}",
 				"libraries": "#{buildJsPath('libraries.js', {hashedPath:settings.useMinifiedJs, removeExtension:true})}",
+				!{moduleIncludes("editor:script", locals)}
 			},
 			"waitSeconds": 0,
 			"shim": {
@@ -159,12 +160,6 @@ block requirejs
 		window.pdfCMapsPath = "#{pdfCMapsPath}"
 		window.uiConfig = JSON.parse('!{JSON.stringify(uiConfig).replace(/\//g, "\\/")}');
 
-	if hasFeature('rich-text')
-		script(
-			src=buildWebpackPath('es/richText.js', {hashedPath:settings.useMinifiedJs})
-			type="text/javascript"
-		)
-
 	script(
 		data-main=buildJsPath("ide.js", {hashedPath:false}),
 		baseurl=fullJsPath,

+ 2 - 10
services/web/app/views/project/editor/editor.pug

@@ -30,9 +30,7 @@ div.full-size(
 				i.fa.fa-arrow-left
 				| &nbsp;&nbsp;#{translate("open_a_file_on_the_left")}
 
-		if hasFeature('rich-text')
-			.toolbar.toolbar-editor(ng-controller="EditorToolbarController")
-				button(ng-click="toggleRichText()") Rich Text
+		!= moduleIncludes('editor:toolbar', locals)
 
 		#editor(
 			ace-editor="editor",
@@ -68,13 +66,7 @@ div.full-size(
 			renderer-data="reviewPanel.rendererData"
 		)
 
-		if hasFeature('rich-text')
-			#editor-rich-text(
-				cm-editor,
-				ng-if="editor.richText"
-				ng-show="!!editor.sharejs_doc && !editor.opening"
-				sharejs-doc="editor.sharejs_doc"
-			)
+		!= moduleIncludes('editor:body', locals)
 
 		include ./review-panel
 

+ 4 - 2
services/web/karma.conf.js

@@ -25,13 +25,15 @@ module.exports = function (config) {
       { pattern: 'public/js/**/*.js', included: false },
       { pattern: 'test/unit_frontend/js/**/*.js', included: false },
       // Include ES test files
-      'test/unit_frontend/es/**/*.js'
+      'test/unit_frontend/es/**/*.js',
+      'modules/**/test/unit_frontend/es/**/*.js'
     ],
     middleware: ['fake-img'],
     preprocessors: {
       // Run ES test files through webpack (which will then include source
       // files in bundle)
-      'test/unit_frontend/es/**/*.js': ['webpack']
+      'test/unit_frontend/es/**/*.js': ['webpack'],
+      'modules/**/test/unit_frontend/es/**/*.js': ['webpack']
     },
     frameworks: ['requirejs', 'mocha', 'chai-sinon'],
     // Configure webpack in the tests

+ 0 - 2
services/web/public/coffee/ide/editor/EditorManager.coffee

@@ -1,9 +1,7 @@
 define [
 	"ide/editor/Document"
 	"ide/editor/directives/aceEditor"
-	"ide/editor/directives/cmEditor"
 	"ide/editor/controllers/SavingNotificationController"
-	"ide/editor/controllers/EditorToolbarController"
 ], (Document) ->
 	class EditorManager
 		constructor: (@ide, @$scope) ->

+ 0 - 7
services/web/public/coffee/ide/editor/controllers/EditorToolbarController.coffee

@@ -1,7 +0,0 @@
-define [
-	"base"
-	"ide/editor/Document"
-], (App, Document) ->
-  App.controller "EditorToolbarController", ($scope, ide) ->
-    $scope.toggleRichText = () ->
-      ide.editorManager.toggleRichText()

+ 0 - 33
services/web/public/coffee/ide/editor/directives/cmEditor.coffee

@@ -1,33 +0,0 @@
-define [
-  "base"
-], (App) ->
-  App.directive "cmEditor", () ->
-    return {
-      scope: {
-        sharejsDoc: "="
-      }
-
-      link: (scope, element, attrs) ->
-        cm = Frontend.richText.init(element.find('.cm-editor-wrapper')[0])
-
-        scope.$watch "sharejsDoc", (sharejsDoc, oldSharejsDoc) ->
-          if oldSharejsDoc?
-            detachFromCM(oldSharejsDoc)
-          if sharejsDoc?
-            attachToCM(sharejsDoc)
-
-        attachToCM = (sharejsDoc) ->
-          scope.$applyAsync () ->
-            Frontend.richText.openDoc(cm, sharejsDoc.getSnapshot())
-            sharejsDoc.attachToCM(cm)
-
-        detachFromCM = (sharejsDoc) ->
-          sharejsDoc.detachFromCM()
-
-        scope.$on 'destroy', () ->
-          detachFromCM(scope.sharejsDoc)
-
-      template: """
-        <div class="cm-editor-wrapper"></div>
-      """
-    }

+ 0 - 16
services/web/public/es/rich-text.js

@@ -1,16 +0,0 @@
-import CodeMirror, { Doc } from 'codemirror'
-
-export function init (rootEl) {
-  CodeMirror.defineMIME('application/x-tex', 'latex')
-  CodeMirror.defineMIME('application/x-latex', 'latex')
-
-  return CodeMirror(rootEl, {
-    mode: 'latex'
-  })
-}
-
-export function openDoc (cm, content) {
-  const newDoc = Doc(content, 'latex')
-  cm.swapDoc(newDoc)
-  return newDoc
-}

+ 0 - 58
services/web/test/unit_frontend/coffee/ide/editor/directives/cmEditorTests.coffee

@@ -1,58 +0,0 @@
-define ['ide/editor/directives/cmEditor'], () ->
-  describe 'cmEditor', () ->
-    beforeEach(module('SharelatexApp'))
-
-    beforeEach () ->
-      @richTextInit = sinon.stub()
-      @richTextOpenDoc = sinon.stub()
-      window.Frontend = {
-        richText: {
-          init: @richTextInit,
-          openDoc: @richTextOpenDoc
-        }
-      }
-
-    afterEach () -> window.Frontend = null
-
-    it 'inits Rich Text', () ->
-      inject ($compile, $rootScope) =>
-        $compile('<div cm-editor></div>')($rootScope)
-        expect(@richTextInit).to.have.been.called
-
-    it 'attaches to CM', () ->
-      inject ($compile, $rootScope, $browser) =>
-        getSnapshot = sinon.stub()
-        detachFromCM = sinon.stub()
-        attachToCM = sinon.stub()
-        $rootScope.sharejsDoc = {
-          getSnapshot: getSnapshot
-          detachFromCM: detachFromCM
-          attachToCM: attachToCM
-        }
-
-        $compile('<div cm-editor sharejs-doc="sharejsDoc"></div>')($rootScope)
-        $rootScope.$digest()
-        # Trigger $applyAsync to evaluate the expression, normally done in the
-        # next tick
-        $browser.defer.flush()
-
-        expect(detachFromCM).to.have.been.called
-        expect(getSnapshot).to.have.been.called
-        expect(@richTextOpenDoc).to.have.been.called
-        expect(attachToCM).to.have.been.called
-
-    it 'detaches from CM when destroyed', () ->
-      inject ($compile, $rootScope) =>
-        @richTextInit.returns({ setValue: sinon.stub() })
-        detachFromCM = sinon.stub()
-        $rootScope.sharejsDoc = {
-          getSnapshot: sinon.stub()
-          detachFromCM: detachFromCM
-          attachToCM: sinon.stub()
-        }
-
-        $compile('<div cm-editor sharejs-doc="sharejsDoc"></div>')($rootScope)
-        $rootScope.$digest()
-        $rootScope.$broadcast('destroy')
-
-        expect(detachFromCM).to.have.been.called

+ 0 - 0
services/web/test/unit_frontend/es/RichTextTests.js → services/web/test/unit_frontend/es/DummyTests.js


+ 16 - 3
services/web/webpack.config.js

@@ -1,11 +1,24 @@
+const fs = require('fs')
 const path = require('path')
 
+const MODULES_PATH = path.join(__dirname, '/modules')
+
+// Generate a hash of entry points, including modules
+const entryPoints = {}
+if (fs.existsSync(MODULES_PATH)) {
+	fs.readdirSync(MODULES_PATH).reduce((acc, module) => {
+		const entryPath = path.join(MODULES_PATH, module, '/public/es/index.js')
+		if (fs.existsSync(entryPath)) {
+			acc[module] = entryPath
+		}
+		return acc
+	}, entryPoints)
+}
+
 module.exports = {
 	// Defines the "entry point(s)" for the application - i.e. the file which
 	// bootstraps the application
-	entry: {
-		richText: './public/es/rich-text.js'
-	},
+	entry: entryPoints,
 
 	// Define where and how the bundle will be output to disk
 	// Note: webpack-dev-server does not write the bundle to disk, instead it is