diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d63445c59162..ce22a97342b2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -361,6 +361,7 @@ # Rich text editor team. /core/templates/dev/head/components/ck-editor-helpers/ck-editor-4-rte.directive.ts @aks681 +/core/templates/dev/head/components/ck-editor-helpers/ck-editor-5-rte.directive.ts @aks681 @NishealJ /core/templates/dev/head/directives/mathjax-bind.directive.ts @aks681 /core/templates/dev/head/mathjaxConfig.ts @aks681 /core/templates/dev/head/components/ck-editor-helpers/ck-editor-4-widgets.initializer.ts @aks681 diff --git a/assets/constants.js b/assets/constants.js index e1c5a635cbcd..35228a87f232 100644 --- a/assets/constants.js +++ b/assets/constants.js @@ -17,6 +17,10 @@ var constants = { // Whether to allow custom event reporting to Google Analytics. "CAN_SEND_ANALYTICS_EVENTS": false, + // This specifies the current editor in use and used to switch + // between CK4 & CK5. + "CURRENT_RTE_IS_CKEDITOR_4": true, + "ALL_CATEGORIES": ["Algebra", "Algorithms", "Architecture", "Arithmetic", "Art", "Astronomy", "Biology", "Business", "Calculus", "Chemistry", "Combinatorics", "Computing", "Economics", "Education", "Engineering", diff --git a/core/templates/dev/head/components/ck-editor-helpers/ck-editor-5-rte.directive.ts b/core/templates/dev/head/components/ck-editor-helpers/ck-editor-5-rte.directive.ts new file mode 100644 index 000000000000..45aa3d21ccea --- /dev/null +++ b/core/templates/dev/head/components/ck-editor-helpers/ck-editor-5-rte.directive.ts @@ -0,0 +1,105 @@ +// Copyright 2018 The Oppia Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Directive for CK Editor 5. + */ + +require('services/ContextService.ts'); +require('services/RteHelperService.ts'); + +const ClassicEditor = require( + '@ckeditor/ckeditor5-build-classic/build/ckeditor.js'); + +angular.module('oppia').directive('ckEditor5Rte', [ + 'ContextService', 'RteHelperService', 'PAGE_CONTEXT', + function(ContextService, RteHelperService, PAGE_CONTEXT) { + return { + restrict: 'E', + scope: { + uiConfig: '&' + }, + // This is the temmplate to which the CKE5 should be initalized. + // The first
is the container for CKE5, the second
+ // is for the editor tools bar, all the needed css for toolbar + // should be applied in the second div. The contenteditable
+ // is the editor text-area. + template: '
' + + '
' + + '
' + + '
', + require: '^ngModel', + + link: function(scope: ICustomScope, elem, attrs, ngModel) { + var _RICH_TEXT_COMPONENTS = RteHelperService.getRichTextComponents(); + var names = []; + var icons = []; + var canUseFs = ( + ContextService.getPageContext() === PAGE_CONTEXT.EXPLORATION_EDITOR || + ContextService.getPageContext() === PAGE_CONTEXT.TOPIC_EDITOR || + ContextService.getPageContext() === PAGE_CONTEXT.STORY_EDITOR || + ContextService.getPageContext() === PAGE_CONTEXT.SKILL_EDITOR); + _RICH_TEXT_COMPONENTS.forEach(function(componentDefn) { + var componentRequiresFsButFsCannotBeUsed = ( + !canUseFs && componentDefn.requiresFs); + if (!((scope.uiConfig() && + scope.uiConfig().hide_complex_extensions && + componentDefn.isComplex) || componentRequiresFsButFsCannotBeUsed)) { + names.push(componentDefn.id); + icons.push(componentDefn.iconDataUrl); + } + }); + + // Create rules to whitelist all the rich text components and their + // wrappers and overlays. See format of filtering + // rules here: http://docs.ckeditor.com/#!/guide/dev_allowed_content_rules + // Whitelist the component tags with any attributes and classes. + var componentRule = names.map(function(name) { + return 'oppia-noninteractive-' + name; + }).join(' ') + '(*)[*];'; + // Whitelist the inline component wrapper, which is a + // span with a "type" attribute. + var inlineWrapperRule = ' span[type];'; + // Whitelist the block component wrapper, which is a div + // with a "type" attribute and a CSS class. + var blockWrapperRule = ' div(oppia-rte-component-container)[type];'; + // Whitelist the transparent block component overlay, which is + // a div with a CSS class. + var blockOverlayRule = ' div(oppia-rte-component-overlay);'; + // Put all the rules together. + var extraAllowedContentRules = ( + componentRule + + inlineWrapperRule + blockWrapperRule + blockOverlayRule); + + var startupFocusEnabled = true; + if ( + scope.uiConfig() && + scope.uiConfig().startupFocusEnabled !== undefined) { + startupFocusEnabled = scope.uiConfig().startupFocusEnabled; + } + // CkEditor5 is initalized to the editable element which is passed + // through the create api. el[0] is the ck-editor-5-rte and + // el[0].children[0].children[1] is the contenteditable div which + // is defined in the template above. + var ck = ClassicEditor.create( + (elem[0].children[0].children[1])); + + // A RegExp for matching rich text components. + var componentRegExp = ( + /(<(oppia-noninteractive-(.+?))\b[^>]*>)[\s\S]*?<\/\2>/g + ); + } + }; + } +]); diff --git a/core/templates/dev/head/components/forms/schema-based-editors/schema-based-html-editor.directive.html b/core/templates/dev/head/components/forms/schema-based-editors/schema-based-html-editor.directive.html index 642798099f82..57660cc24525 100755 --- a/core/templates/dev/head/components/forms/schema-based-editors/schema-based-html-editor.directive.html +++ b/core/templates/dev/head/components/forms/schema-based-editors/schema-based-html-editor.directive.html @@ -1,6 +1,9 @@ - + + diff --git a/core/templates/dev/head/components/forms/schema-based-editors/schema-based-html-editor.directive.ts b/core/templates/dev/head/components/forms/schema-based-editors/schema-based-html-editor.directive.ts index 154c73602e8f..8f48c0bba915 100644 --- a/core/templates/dev/head/components/forms/schema-based-editors/schema-based-html-editor.directive.ts +++ b/core/templates/dev/head/components/forms/schema-based-editors/schema-based-html-editor.directive.ts @@ -33,6 +33,10 @@ angular.module('oppia').directive('schemaBasedHtmlEditor', [ '/components/forms/schema-based-editors/' + 'schema-based-html-editor.directive.html'), controllerAs: '$ctrl', - controller: [function() {}] + controller: ['$scope', 'CURRENT_RTE_IS_CKEDITOR_4', + function($scope, CURRENT_RTE_IS_CKEDITOR_4) { + var ctrl = this; + ctrl.currentRteIsCKEditor4 = CURRENT_RTE_IS_CKEDITOR_4; + }] }; }]); diff --git a/core/templates/dev/head/components/question-directives/question-player/question-player.directive.ts b/core/templates/dev/head/components/question-directives/question-player/question-player.directive.ts index 7fffcfd5feef..a8950bdfb2bb 100644 --- a/core/templates/dev/head/components/question-directives/question-player/question-player.directive.ts +++ b/core/templates/dev/head/components/question-directives/question-player/question-player.directive.ts @@ -17,6 +17,7 @@ */ require('components/ck-editor-helpers/ck-editor-4-rte.directive.ts'); +require('components/ck-editor-helpers/ck-editor-5-rte.directive.ts'); require('components/ck-editor-helpers/ck-editor-4-widgets.initializer.ts'); require('directives/angular-html-bind.directive.ts'); require('directives/mathjax-bind.directive.ts'); diff --git a/core/templates/dev/head/pages/creator-dashboard-page/suggestion-modal-for-creator-view/suggestion-modal-for-creator-view.directive.html b/core/templates/dev/head/pages/creator-dashboard-page/suggestion-modal-for-creator-view/suggestion-modal-for-creator-view.directive.html index 933b66e61b3a..adf8aa885137 100644 --- a/core/templates/dev/head/pages/creator-dashboard-page/suggestion-modal-for-creator-view/suggestion-modal-for-creator-view.directive.html +++ b/core/templates/dev/head/pages/creator-dashboard-page/suggestion-modal-for-creator-view/suggestion-modal-for-creator-view.directive.html @@ -19,7 +19,10 @@

Review Suggestion

- + + + +
diff --git a/core/templates/dev/head/pages/creator-dashboard-page/suggestion-modal-for-creator-view/suggestion-modal-for-creator-view.service.ts b/core/templates/dev/head/pages/creator-dashboard-page/suggestion-modal-for-creator-view/suggestion-modal-for-creator-view.service.ts index a236cbf2808d..50ba79c01aea 100644 --- a/core/templates/dev/head/pages/creator-dashboard-page/suggestion-modal-for-creator-view/suggestion-modal-for-creator-view.service.ts +++ b/core/templates/dev/head/pages/creator-dashboard-page/suggestion-modal-for-creator-view/suggestion-modal-for-creator-view.service.ts @@ -64,14 +64,14 @@ angular.module('oppia').factory('SuggestionModalForCreatorDashboardService', [ }, controller: [ '$log', '$scope', '$uibModalInstance', 'SuggestionModalService', - 'canReviewActiveThread', 'description', 'newContent', - 'oldContent', 'stateName', 'suggestionIsHandled', 'suggestionStatus', - 'suggestionType', + 'canReviewActiveThread', 'description', 'CURRENT_RTE_IS_CKEDITOR_4', + 'newContent', 'oldContent', 'stateName', 'suggestionIsHandled', + 'suggestionStatus', 'suggestionType', function( $log, $scope, $uibModalInstance, SuggestionModalService, - canReviewActiveThread, description, newContent, - oldContent, stateName, suggestionIsHandled, suggestionStatus, - suggestionType + canReviewActiveThread, description, CURRENT_RTE_IS_CKEDITOR_4, + newContent, oldContent, stateName, suggestionIsHandled, + suggestionStatus, suggestionType ) { $scope.isNotHandled = !suggestionIsHandled; $scope.canReject = $scope.isNotHandled; @@ -91,6 +91,8 @@ angular.module('oppia').factory('SuggestionModalForCreatorDashboardService', [ $scope.errorMessage = ''; } + $scope.currentRteIsCKEditor4 = CURRENT_RTE_IS_CKEDITOR_4; + $scope.oldContent = oldContent; $scope.newContent = newContent; $scope.stateName = stateName; diff --git a/core/templates/dev/head/pages/exploration-editor-page/exploration-editor-page.controller.ts b/core/templates/dev/head/pages/exploration-editor-page/exploration-editor-page.controller.ts index 3dbc72462eb8..88e30b5bcea6 100644 --- a/core/templates/dev/head/pages/exploration-editor-page/exploration-editor-page.controller.ts +++ b/core/templates/dev/head/pages/exploration-editor-page/exploration-editor-page.controller.ts @@ -20,6 +20,7 @@ // TODO(vojtechjelinek): this block of requires should be removed after we // introduce webpack for /extensions require('components/ck-editor-helpers/ck-editor-4-rte.directive.ts'); +require('components/ck-editor-helpers/ck-editor-5-rte.directive.ts'); require('components/ck-editor-helpers/ck-editor-4-widgets.initializer.ts'); require( 'components/forms/custom-forms-directives/apply-validation.directive.ts'); diff --git a/core/templates/dev/head/pages/exploration-player-page/exploration-player-page.controller.ts b/core/templates/dev/head/pages/exploration-player-page/exploration-player-page.controller.ts index 20f46a8e4e5c..eccf0ad65959 100644 --- a/core/templates/dev/head/pages/exploration-player-page/exploration-player-page.controller.ts +++ b/core/templates/dev/head/pages/exploration-player-page/exploration-player-page.controller.ts @@ -19,6 +19,7 @@ // TODO(vojtechjelinek): this block of requires should be removed after we // introduce webpack for /extensions require('components/ck-editor-helpers/ck-editor-4-rte.directive.ts'); +require('components/ck-editor-helpers/ck-editor-5-rte.directive.ts'); require('components/ck-editor-helpers/ck-editor-4-widgets.initializer.ts'); require('directives/angular-html-bind.directive.ts'); require('directives/mathjax-bind.directive.ts'); diff --git a/core/templates/dev/head/pages/exploration-player-page/suggestion-modal-for-learner-local-view/suggestion-modal-for-exploration-player.service.ts b/core/templates/dev/head/pages/exploration-player-page/suggestion-modal-for-learner-local-view/suggestion-modal-for-exploration-player.service.ts index 63dbf96f609b..4b75f3a339e9 100644 --- a/core/templates/dev/head/pages/exploration-player-page/suggestion-modal-for-learner-local-view/suggestion-modal-for-exploration-player.service.ts +++ b/core/templates/dev/head/pages/exploration-player-page/suggestion-modal-for-learner-local-view/suggestion-modal-for-exploration-player.service.ts @@ -38,12 +38,12 @@ angular.module('oppia').factory('SuggestionModalForExplorationPlayerService', [ resolve: {}, controller: [ '$scope', '$timeout', '$uibModalInstance', 'ExplorationEngineService', - 'PlayerPositionService', 'PlayerTranscriptService', - 'SuggestionModalService', + 'CURRENT_RTE_IS_CKEDITOR_4', 'PlayerPositionService', + 'PlayerTranscriptService', 'SuggestionModalService', function( $scope, $timeout, $uibModalInstance, ExplorationEngineService, - PlayerPositionService, PlayerTranscriptService, - SuggestionModalService) { + CURRENT_RTE_IS_CKEDITOR_4, PlayerPositionService, + PlayerTranscriptService, SuggestionModalService) { var stateName = PlayerPositionService.getCurrentStateName(); var displayedCard = PlayerTranscriptService.getCard( PlayerPositionService.getDisplayedCardIndex()); @@ -62,6 +62,9 @@ angular.module('oppia').factory('SuggestionModalForExplorationPlayerService', [ $scope.cancelSuggestion = function() { SuggestionModalService.cancelSuggestion($uibModalInstance); }; + + $scope.currentRteIsCKEditor4 = CURRENT_RTE_IS_CKEDITOR_4; + $scope.submitSuggestion = function() { var data = { target_id: ExplorationEngineService.getExplorationId(), diff --git a/core/templates/dev/head/pages/exploration-player-page/templates/exploration-player-suggestion-modal.directive.html b/core/templates/dev/head/pages/exploration-player-page/templates/exploration-player-suggestion-modal.directive.html index fcc53dfedd7e..dbbc54ce0f70 100644 --- a/core/templates/dev/head/pages/exploration-player-page/templates/exploration-player-suggestion-modal.directive.html +++ b/core/templates/dev/head/pages/exploration-player-page/templates/exploration-player-suggestion-modal.directive.html @@ -4,7 +4,10 @@

Suggest a Change