8
0
Эх сурвалжийг харах

Merge branch 'master' into memory-test

Maciej Gołaszewski 5 жил өмнө
parent
commit
1fbca057f3
32 өөрчлөгдсөн 695 нэмэгдсэн , 242 устгасан
  1. 2 0
      .travis.yml
  2. 6 5
      package.json
  3. 1 1
      packages/ckeditor5-code-block/src/codeblockediting.js
  4. 8 15
      packages/ckeditor5-code-block/src/converters.js
  5. 17 7
      packages/ckeditor5-code-block/tests/codeblockediting.js
  6. 66 1
      packages/ckeditor5-engine/docs/framework/guides/deep-dive/schema.md
  7. 18 3
      packages/ckeditor5-engine/src/model/model.js
  8. 105 31
      packages/ckeditor5-engine/src/model/schema.js
  9. 0 1
      packages/ckeditor5-highlight/src/highlightcommand.js
  10. 5 0
      packages/ckeditor5-mention/docs/_snippets/examples/chat-with-mentions.js
  11. 6 1
      packages/ckeditor5-mention/docs/_snippets/features/mention-customization.js
  12. 5 0
      packages/ckeditor5-mention/docs/examples/chat-with-mentions.md
  13. 15 1
      packages/ckeditor5-mention/docs/features/mentions.md
  14. 4 3
      packages/ckeditor5-mention/src/mention.js
  15. 2 2
      packages/ckeditor5-mention/src/mentionediting.js
  16. 4 1
      packages/ckeditor5-mention/tests/manual/mention-custom-view.js
  17. 2 2
      packages/ckeditor5-mention/tests/mention.js
  18. 1 1
      packages/ckeditor5-mention/tests/mentioncommand.js
  19. 15 9
      packages/ckeditor5-mention/tests/mentionediting.js
  20. 5 5
      packages/ckeditor5-mention/tests/mentionui.js
  21. 49 0
      packages/ckeditor5-paragraph/src/insertparagraphcommand.js
  22. 9 0
      packages/ckeditor5-paragraph/src/paragraph.js
  23. 101 0
      packages/ckeditor5-paragraph/tests/insertparagraphcommand.js
  24. 7 2
      packages/ckeditor5-paragraph/tests/paragraph.js
  25. 6 2
      packages/ckeditor5-theme-lark/theme/ckeditor5-widget/widget.css
  26. 18 0
      packages/ckeditor5-theme-lark/theme/ckeditor5-widget/widgettypearound.css
  27. 6 10
      packages/ckeditor5-widget/src/widgettypearound/widgettypearound.js
  28. 2 0
      packages/ckeditor5-widget/tests/manual/type-around.html
  29. 4 0
      packages/ckeditor5-widget/tests/manual/type-around.js
  30. 24 2
      packages/ckeditor5-widget/tests/widgettypearound/widgettypearound.js
  31. 14 0
      packages/ckeditor5-widget/theme/widgettypearound.css
  32. 168 137
      yarn.lock

+ 2 - 0
.travis.yml

@@ -13,6 +13,8 @@ cache:
 - node_modules
 before_install:
 - export START_TIME=$( date +%s )
+- export COVERALLS_SERVICE_JOB_ID=$( TRAVIS_JOB_ID )
+- export COVERALLS_SERVICE_NAME="CKEditor5 code coverage"
 - npm i -g yarn
 install:
 - yarn install

+ 6 - 5
package.json

@@ -77,11 +77,11 @@
   },
   "devDependencies": {
     "@ckeditor/ckeditor5-comments": "^19.0.1",
-    "@ckeditor/ckeditor5-dev-docs": "^11.1.0",
-    "@ckeditor/ckeditor5-dev-env": "^18.0.0",
-    "@ckeditor/ckeditor5-dev-tests": "^19.2.0",
-    "@ckeditor/ckeditor5-dev-utils": "^13.0.0",
-    "@ckeditor/ckeditor5-dev-webpack-plugin": "^9.0.0",
+    "@ckeditor/ckeditor5-dev-docs": "^20.0.0",
+    "@ckeditor/ckeditor5-dev-env": "^20.0.0",
+    "@ckeditor/ckeditor5-dev-tests": "^20.0.0",
+    "@ckeditor/ckeditor5-dev-utils": "^20.0.0",
+    "@ckeditor/ckeditor5-dev-webpack-plugin": "^20.0.0",
     "@ckeditor/ckeditor5-inspector": "^2.0.0",
     "@ckeditor/ckeditor5-react": "^1.1.3",
     "@ckeditor/ckeditor5-real-time-collaboration": "^19.0.1",
@@ -160,6 +160,7 @@
   },
   "eslintIgnore": [
     "build/**",
+    "packages/*/node_modules/**",
     "packages/*/build/**",
     "packages/*/src/lib/**",
     "coverage/**"

+ 1 - 1
packages/ckeditor5-code-block/src/codeblockediting.js

@@ -128,7 +128,7 @@ export default class CodeBlockEditing extends Plugin {
 		editor.editing.downcastDispatcher.on( 'insert:codeBlock', modelToViewCodeBlockInsertion( model, normalizedLanguagesDefs, true ) );
 		editor.data.downcastDispatcher.on( 'insert:codeBlock', modelToViewCodeBlockInsertion( model, normalizedLanguagesDefs ) );
 		editor.data.downcastDispatcher.on( 'insert:softBreak', modelToDataViewSoftBreakInsertion( model ), { priority: 'high' } );
-		editor.data.upcastDispatcher.on( 'element:pre', dataViewToModelCodeBlockInsertion( editor.data, normalizedLanguagesDefs ) );
+		editor.data.upcastDispatcher.on( 'element:pre', dataViewToModelCodeBlockInsertion( editor.editing.view, normalizedLanguagesDefs ) );
 
 		// Intercept the clipboard input (paste) when the selection is anchored in the code block and force the clipboard
 		// data to be pasted as a single plain text. Otherwise, the code lines will split the code block and

+ 8 - 15
packages/ckeditor5-code-block/src/converters.js

@@ -126,12 +126,12 @@ export function modelToDataViewSoftBreakInsertion( model ) {
  *
  *		<codeBlock language="javascript">foo();<softBreak></softBreak>bar();</codeBlock>
  *
- * @param {module:engine/controller/datacontroller~DataController} dataController
+ * @param {module:engine/view/view~View} editingView
  * @param {Array.<module:code-block/codeblock~CodeBlockLanguageDefinition>} languageDefs The normalized language
  * configuration passed to the feature.
  * @returns {Function} Returns a conversion callback.
  */
-export function dataViewToModelCodeBlockInsertion( dataController, languageDefs ) {
+export function dataViewToModelCodeBlockInsertion( editingView, languageDefs ) {
 	// Language names associated with CSS classes:
 	//
 	//		{
@@ -183,8 +183,12 @@ export function dataViewToModelCodeBlockInsertion( dataController, languageDefs
 			writer.setAttribute( 'language', defaultLanguageName, codeBlock );
 		}
 
-		const stringifiedElement = dataController.processor.toData( viewChild );
-		const textData = extractDataFromCodeElement( stringifiedElement );
+		// HTML elements are invalid content for `<code>`.
+		// Read only text nodes.
+		const textData = [ ...editingView.createRangeIn( viewChild ) ]
+			.filter( current => current.type === 'text' )
+			.map( ( { item } ) => item.data )
+			.join( '' );
 		const fragment = rawSnippetTextToModelDocumentFragment( writer, textData );
 
 		writer.append( fragment, codeBlock );
@@ -234,14 +238,3 @@ export function dataViewToModelCodeBlockInsertion( dataController, languageDefs
 		}
 	};
 }
-
-// Returns content of `<pre></pre>` with unescaped html inside.
-//
-// @param {String} stringifiedElement
-function extractDataFromCodeElement( stringifiedElement ) {
-	const data = new RegExp( /^<code[^>]*>([\S\s]*)<\/code>$/ ).exec( stringifiedElement )[ 1 ];
-
-	return data
-		.replace( /&lt;/g, '<' )
-		.replace( /&gt;/g, '>' );
-}

+ 17 - 7
packages/ckeditor5-code-block/tests/codeblockediting.js

@@ -889,29 +889,39 @@ describe( 'CodeBlockEditing', () => {
 			);
 		} );
 
+		// Undesired by expected. There is an issue with identifying the correct filler type.
+		// <code> is inline, so dom-to-view converter expects an inline filler.
+		it( 'should convert pre > code with only &nbsp; inside to a codeBlock with &nbsp;', () => {
+			editor.setData( '<pre><code>&nbsp;</code></pre>' );
+
+			expect( getModelData( model ) ).to.equal(
+				'<codeBlock language="plaintext">[]\u00a0</codeBlock>'
+			);
+		} );
+
 		it( 'should convert pre > code with HTML inside', () => {
 			editor.setData( '<pre><code><p>Foo</p>\n<p>Bar</p></code></pre>' );
 
 			expect( getModelData( model ) ).to.equal(
 				'<codeBlock language="plaintext">[]' +
-					'<p>Foo</p>' +
+					'Foo' +
 					'<softBreak></softBreak>' +
-					'<p>Bar</p>' +
+					'Bar' +
 				'</codeBlock>'
 			);
 		} );
 
-		it( 'should convert pre > code tag with HTML and nested pre > code tag', () => {
-			editor.setData( '<pre><code><p>Foo</p><pre>Bar</pre><p>Biz</p></code></pre>' );
+		it( 'should convert pre > code tag with HTML and nested pre > code tag and use only the text content of invalid HTML tags', () => {
+			editor.setData( '<pre><code><p>Foo</p><pre><code>Bar</code></pre><p>Biz</p></code></pre>' );
 
 			expect( getModelData( model ) ).to.equal(
-				'<codeBlock language="plaintext">[]<p>Foo</p><pre>Bar</pre><p>Biz</p></codeBlock>' );
+				'<codeBlock language="plaintext">[]FooBarBiz</codeBlock>' );
 		} );
 
 		it( 'should convert pre > code tag with escaped html content', () => {
-			editor.setData( '<pre><code>&lt;div&gt;&lt;p&gt;Foo&lt;/p&gt;&lt;/div&gt;</code></pre>' );
+			editor.setData( '<pre><code>&lt;div&gt;&lt;p&gt;Foo&apos;s&amp;&quot;bar&quot;&lt;/p&gt;&lt;/div&gt;</code></pre>' );
 
-			expect( getModelData( model ) ).to.equal( '<codeBlock language="plaintext">[]<div><p>Foo</p></div></codeBlock>' );
+			expect( getModelData( model ) ).to.equal( '<codeBlock language="plaintext">[]<div><p>Foo\'s&"bar"</p></div></codeBlock>' );
 		} );
 
 		it( 'should be overridable', () => {

+ 66 - 1
packages/ckeditor5-engine/docs/framework/guides/deep-dive/schema.md

@@ -8,7 +8,7 @@ This article assumes that you have already read the {@link framework/guides/arch
 
 ## Quick recap
 
-The editor's schema is available in the {@link module:engine/model/model~Model#schema `editor.model.schema`} property. It defines allowed model structures (how model elements can be nested) and allowed attributes (of both elements and text nodes). This information is later used by editing features and the editing engine to decide how to process the model, where to enable features, etc.
+The editor's schema is available in the {@link module:engine/model/model~Model#schema `editor.model.schema`} property. It defines allowed model structures (how model elements can be nested), allowed attributes (of both elements and text nodes), and other characteristics (inline vs. block, atomicity in regards of external actions). This information is later used by editing features and the editing engine to decide how to process the model, where to enable features, etc.
 
 Schema rules can be defined by using the {@link module:engine/model/schema~Schema#register `Schema#register()`} or {@link module:engine/model/schema~Schema#extend `Schema#extend()`} methods. The former can be used only once for a given item name which ensures that only a single editing feature can introduce this item. Similarly, `extend()` can only be used for defined items.
 
@@ -44,6 +44,71 @@ While this would be incorrect:
 </$root>
 ```
 
+## Defining additional semantics
+
+In addition to setting allowed structures, the schema can also define additional traits of model elements. By using the `is*` properties a feature author may declare how a certain element should be treated by other features and the engine.
+
+### Limit elements
+
+Consider a feature like an image caption. The caption text area should construct a boundary to some internal actions:
+
+* A selection that starts inside should not end outside.
+* Pressing <kbd>Backspace</kbd> or <kbd>Delete</kbd> should not delete the area. Pressing <kbd>Enter</kbd> should not split the area.
+
+It should also act as a boundary for external actions. This is mostly enforced by a selection post-fixer that ensures that a selection that starts outside, should not end inside. That means that most actions will either apply to the "outside" of such an element or to a content inside it.
+
+Taken these characteristics, the image caption should be defined as limit element by using the {@link module:engine/model/schema~SchemaItemDefinition#isLimit `isLimit`} property.
+
+```js
+schema.register( 'myCaption', {
+	isLimit: true
+} );
+```
+
+The engine and various features then check it via {@link module:engine/model/schema~Schema#isLimit `Schema#isLimit()`} and can act accordingly.
+
+<info-box>
+	"Limit element" does not mean "editable element". The concept of "editability" is reserved for the view and expressed by the {@link module:engine/view/editableelement~EditableElement `EditableElement` class}.
+</info-box>
+
+### Object elements
+
+For the image caption as in the example above it does not make much sense to select the caption box, then copy or drag it somewhere else.
+
+A caption without the image that it describes does not make much sense. However, the image is more self-sufficient. Most likely users should be able to select the entire image (with all its internals), then copy or move it around. {@link module:engine/model/schema~SchemaItemDefinition#isObject `isObject`} should be used to mark such behavior.
+
+```js
+schema.register( 'myImage', {
+	isObject: true
+} );
+```
+
+The {@link module:engine/model/schema~Schema#isObject `Schema#isObject()`} can later be used to check this property.
+
+<info-box>
+	Every "object" is also a "limit" element.
+
+	It means that for every element with `isObject` set to `true`, {@link module:engine/model/schema~Schema#isLimit `Schema#isLimit( element )`} will always return `true`.
+</info-box>
+
+### Block elements
+
+Generally speaking, content is usually made out of blocks like paragraphs, list items, images, headings, etc. All these elements should be marked as blocks by using {@link module:engine/model/schema~SchemaItemDefinition#isBlock `isBlock`}.
+
+It is important to remember that a block should not allow another block inside. Container elements like `<blockQuote>` which can contain other block elements should not be marked as blocks.
+
+<info-box>
+	There is also the `$block` generic item which has `isBlock` set to `true`. Most block type items will inherit from `$block` (through `inheritAllFrom`).
+</info-box>
+
+### Inline elements
+
+In the editor, all HTML formatting elements such as `<strong>` or `<code>` are represented by text attributes. Therefore, inline model elements are not to be used for this scenarios.
+
+Currently, the {@link module:engine/model/schema~SchemaItemDefinition#isInline `isInline`} property is used for the `$text` token (so, text nodes) and elements such as `<softBreak>` or placeholder elements such as in the {@link framework/guides/tutorials/implementing-an-inline-widget Implementing an inline widget} tutorial.
+
+The support for inline elements in CKEditor 5 is so far limited to self-contained elements. This is &mdash; all elements marked with `isInline` should also be marked with `isObject`.
+
 ## Generic items
 
 There are three basic generic items: `$root`, `$block` and `$text`. They are defined as follows:

+ 18 - 3
packages/ckeditor5-engine/src/model/model.js

@@ -370,13 +370,28 @@ export default class Model {
 	 *			editor.model.insertContent( writer.createText( 'x' ), writer.createPositionAt( doc.getRoot(), 2 ) );
 	 *		} );
 	 *
-	 * If an instance of {@link module:engine/model/selection~Selection} is passed as `selectable`
-	 * it will be moved to the target position (where the document selection should be moved after the insertion).
+	 * If you want the document selection to be moved to the inserted content, use the
+	 * {@link module:engine/model/writer~Writer#setSelection `setSelection()`} method of the writer after inserting
+	 * the content:
 	 *
 	 *		editor.model.change( writer => {
-	 *			// Insert text replacing the given selection instance.
+	 *			const paragraph = writer.createElement( 'paragraph' );
+	 *
+	 *			// Insert an empty paragraph at the beginning of the root.
+	 *			editor.model.insertContent( paragraph, writer.createPositionAt( editor.model.document.getRoot(), 0 ) );
+	 *
+	 *			// Move the document selection to the inserted paragraph.
+	 *			writer.setSelection( paragraph, 'in' );
+	 *		} );
+	 *
+	 * If an instance of the {@link module:engine/model/selection~Selection model selection} is passed as `selectable`,
+	 * the new content will be inserted at the passed selection (instead of document selection):
+	 *
+	 *		editor.model.change( writer => {
+	 *			// Create a selection in a paragraph that will be used as a place of insertion.
 	 *			const selection = writer.createSelection( paragraph, 'in' );
 	 *
+	 *			// Insert the new text at the created selection.
 	 *			editor.model.insertContent( writer.createText( 'x' ), selection );
 	 *
 	 *			// insertContent() modifies the passed selection instance so it can be used to set the document selection.

+ 105 - 31
packages/ckeditor5-engine/src/model/schema.js

@@ -153,7 +153,12 @@ export default class Schema {
 	}
 
 	/**
-	 * Returns all registered items.
+	 * Returns data of all registered items.
+	 *
+	 * This method should normally be used for reflection purposes (e.g. defining a clone of a certain element,
+	 * checking a list of all block elements, etc).
+	 * Use specific methods (such as {@link #checkChild `checkChild()`} or {@link #isLimit `isLimit()`})
+	 * in other cases.
 	 *
 	 * @returns {Object.<String,module:engine/model/schema~SchemaCompiledItemDefinition>}
 	 */
@@ -168,6 +173,11 @@ export default class Schema {
 	/**
 	 * Returns a definition of the given item or `undefined` if item is not registered.
 	 *
+	 * This method should normally be used for reflection purposes (e.g. defining a clone of a certain element,
+	 * checking a list of all block elements, etc).
+	 * Use specific methods (such as {@link #checkChild `checkChild()`} or {@link #isLimit `isLimit()`})
+	 * in other cases.
+	 *
 	 * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item
 	 * @returns {module:engine/model/schema~SchemaCompiledItemDefinition}
 	 */
@@ -210,6 +220,9 @@ export default class Schema {
 	 *		const paragraphElement = writer.createElement( 'paragraph' );
 	 *		schema.isBlock( paragraphElement ); // -> true
 	 *
+	 * See the {@glink framework/guides/deep-dive/schema#block-elements Block elements} section of the "Schema" deep dive}
+	 * guide for more details.
+	 *
 	 * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item
 	 */
 	isBlock( item ) {
@@ -219,15 +232,22 @@ export default class Schema {
 	}
 
 	/**
-	 * Returns `true` if the given item is defined to be
-	 * a limit element by {@link module:engine/model/schema~SchemaItemDefinition}'s `isLimit` or `isObject` property
-	 * (all objects are also limits).
+	 * Returns `true` if the given item should be treated as a limit element.
+	 *
+	 * It considers the item to be a limit element if its
+	 * {@link module:engine/model/schema~SchemaItemDefinition}'s
+	 * {@link module:engine/model/schema~SchemaItemDefinition#isLimit `isLimit`} or
+	 * {@link module:engine/model/schema~SchemaItemDefinition#isObject `isObject`} property
+	 * were set to `true`.
 	 *
 	 *		schema.isLimit( 'paragraph' ); // -> false
 	 *		schema.isLimit( '$root' ); // -> true
 	 *		schema.isLimit( editor.model.document.getRoot() ); // -> true
 	 *		schema.isLimit( 'image' ); // -> true
 	 *
+	 * See the {@glink framework/guides/deep-dive/schema#limit-elements Limit elements} section of the "Schema" deep dive}
+	 * guide for more details.
+	 *
 	 * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item
 	 */
 	isLimit( item ) {
@@ -241,8 +261,12 @@ export default class Schema {
 	}
 
 	/**
-	 * Returns `true` if the given item is defined to be
-	 * an object element by {@link module:engine/model/schema~SchemaItemDefinition}'s `isObject` property.
+	 * Returns `true` if the given item is should be treated as an object element.
+	 *
+	 * It considers the item to be an object element if its
+	 * {@link module:engine/model/schema~SchemaItemDefinition}'s
+	 * {@link module:engine/model/schema~SchemaItemDefinition#isObject `isObject`} property
+	 * were set to `true`.
 	 *
 	 *		schema.isObject( 'paragraph' ); // -> false
 	 *		schema.isObject( 'image' ); // -> true
@@ -250,6 +274,9 @@ export default class Schema {
 	 *		const imageElement = writer.createElement( 'image' );
 	 *		schema.isObject( imageElement ); // -> true
 	 *
+	 * See the {@glink framework/guides/deep-dive/schema#object-elements Object elements} section of the "Schema" deep dive}
+	 * guide for more details.
+	 *
 	 * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item
 	 */
 	isObject( item ) {
@@ -268,6 +295,9 @@ export default class Schema {
 	 *		const text = writer.createText('foo' );
 	 *		schema.isInline( text ); // -> true
 	 *
+	 * See the {@glink framework/guides/deep-dive/schema#inline-elements Inline elements} section of the "Schema" deep dive}
+	 * guide for more details.
+	 *
 	 * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item
 	 */
 	isInline( item ) {
@@ -712,8 +742,8 @@ export default class Schema {
 	 * as long as {@link module:engine/model/schema~Schema#isLimit limit element},
 	 * {@link module:engine/model/schema~Schema#isObject object element} or top-most ancestor won't be reached.
 	 *
-	 * @params {module:engine/model/position~Position} position Position from searching will start.
-	 * @params {module:engine/model/node~Node|String} node Node for which allowed parent should be found or its name.
+	 * @param {module:engine/model/position~Position} position Position from searching will start.
+	 * @param {module:engine/model/node~Node|String} node Node for which allowed parent should be found or its name.
 	 * @returns {module:engine/model/element~Element|null} element Allowed parent or null if nothing was found.
 	 */
 	findAllowedParent( position, node ) {
@@ -999,32 +1029,34 @@ mix( Schema, ObservableMixin );
  *
  * You can define the following rules:
  *
- * * `allowIn` &ndash; A string or an array of strings. Defines in which other items this item will be allowed.
- * * `allowAttributes` &ndash; A string or an array of strings. Defines allowed attributes of the given item.
- * * `allowContentOf` &ndash; A string or an array of strings. Inherits "allowed children" from other items.
- * * `allowWhere` &ndash; A string or an array of strings. Inherits "allowed in" from other items.
- * * `allowAttributesOf` &ndash; A string or an array of strings. Inherits attributes from other items.
- * * `inheritTypesFrom` &ndash; A string or an array of strings. Inherits `is*` properties of other items.
- * * `inheritAllFrom` &ndash; A string. A shorthand for `allowContentOf`, `allowWhere`, `allowAttributesOf`, `inheritTypesFrom`.
- * * Additionally, you can define the following `is*` properties: `isBlock`, `isLimit`, `isObject`, `isInline`. Read about them below.
+ * * {@link ~SchemaItemDefinition#allowIn `allowIn`} &ndash; Defines in which other items this item will be allowed.
+ * * {@link ~SchemaItemDefinition#allowAttributes `allowAttributes`} &ndash; Defines allowed attributes of the given item.
+ * * {@link ~SchemaItemDefinition#allowContentOf `allowContentOf`} &ndash; Inherits "allowed children" from other items.
+ * * {@link ~SchemaItemDefinition#allowWhere `allowWhere`} &ndash; Inherits "allowed in" from other items.
+ * * {@link ~SchemaItemDefinition#allowAttributesOf `allowAttributesOf`} &ndash; Inherits attributes from other items.
+ * * {@link ~SchemaItemDefinition#inheritTypesFrom `inheritTypesFrom`} &ndash; Inherits `is*` properties of other items.
+ * * {@link ~SchemaItemDefinition#inheritAllFrom `inheritAllFrom`} &ndash;
+ * A shorthand for `allowContentOf`, `allowWhere`, `allowAttributesOf`, `inheritTypesFrom`.
  *
- * # The is* properties
+ * # The `is*` properties
  *
- * There are 3 commonly used `is*` properties. Their role is to assign additional semantics to schema items.
+ * There are a couple commonly used `is*` properties. Their role is to assign additional semantics to schema items.
  * You can define more properties but you will also need to implement support for them in the existing editor features.
  *
- * * `isBlock` &ndash; Whether this item is paragraph-like. Generally speaking, content is usually made out of blocks
- * like paragraphs, list items, images, headings, etc. All these elements are marked as blocks. A block
- * should not allow another block inside. Note: There is also the `$block` generic item which has `isBlock` set to `true`.
- * Most block type items will inherit from `$block` (through `inheritAllFrom`).
- * * `isLimit` &ndash; It can be understood as whether this element should not be split by <kbd>Enter</kbd>.
- * Examples of limit elements: `$root`, table cell, image caption, etc. In other words, all actions that happen inside
- * a limit element are limited to its content. **Note:** All objects (`isObject`) are treated as limit elements, too.
- * * `isObject` &ndash; Whether an item is "self-contained" and should be treated as a whole. Examples of object elements:
- * `image`, `table`, `video`, etc. **Note:** An object is also a limit, so
+ * * {@link ~SchemaItemDefinition#isBlock `isBlock`} &ndash; Whether this item is paragraph-like.
+ * Generally speaking, content is usually made out of blocks like paragraphs, list items, images, headings, etc.
+ * * {@link ~SchemaItemDefinition#isInline `isInline`} &ndash; Whether an item is "text-like" and should be treated as an inline node.
+ * Examples of inline elements: `$text`, `softBreak` (`<br>`), etc.
+ * * {@link ~SchemaItemDefinition#isLimit `isLimit`} &ndash; It can be understood as whether this element
+ * should not be split by <kbd>Enter</kbd>. Examples of limit elements: `$root`, table cell, image caption, etc.
+ * In other words, all actions that happen inside a limit element are limited to its content.
+ * All objects are treated as limit elements, too.
+ * * {@link ~SchemaItemDefinition#isObject `isObject`} &ndash; Whether an item is "self-contained" and should be treated as a whole.
+ * Examples of object elements: `image`, `table`, `video`, etc. An object is also a limit, so
  * {@link module:engine/model/schema~Schema#isLimit `isLimit()`} returns `true` for object elements automatically.
- * * `isInline` &ndash; Whether an item is "text-like" and should be treated as an inline node. Examples of inline elements:
- * `$text`, `softBreak` (`<br>`), etc.
+ *
+ * Read more about the meaning of these types in the
+ * {@glink framework/guides/deep-dive/schema#defining-additional-semantics Dedicated section of the "Schema" deep dive} guide.
  *
  * # Generic items
  *
@@ -1047,7 +1079,7 @@ mix( Schema, ObservableMixin );
  * (paragraphs, lists items, headings, images) which, in turn, may contain text inside.
  *
  * By inheriting from the generic items you can define new items which will get extended by other editor features.
- * Read more about generic types in the {@glink framework/guides/deep-dive/schema Defining schema} guide.
+ * Read more about generic types in the {@glink framework/guides/deep-dive/schema Schema deep dive} guide.
  *
  * # Example definitions
  *
@@ -1107,10 +1139,52 @@ mix( Schema, ObservableMixin );
  * * If you want to publish your feature so other developers can use it, try to use
  * generic items as much as possible.
  * * Keep your model clean. Limit it to the actual data and store information in a normalized way.
- * * Remember about definining the `is*` properties. They do not affect the allowed structures, but they can
+ * * Remember about defining the `is*` properties. They do not affect the allowed structures, but they can
  * affect how the editor features treat your elements.
  *
  * @typedef {Object} module:engine/model/schema~SchemaItemDefinition
+ *
+ * @property {String|Array.<String>} allowIn Defines in which other items this item will be allowed.
+ * @property {String|Array.<String>} allowAttributes Defines allowed attributes of the given item.
+ * @property {String|Array.<String>} allowContentOf Inherits "allowed children" from other items.
+ * @property {String|Array.<String>} allowWhere Inherits "allowed in" from other items.
+ * @property {String|Array.<String>} allowAttributesOf Inherits attributes from other items.
+ * @property {String|Array.<String>} inheritTypesFrom Inherits `is*` properties of other items.
+ * @property {String} inheritAllFrom A shorthand for `allowContentOf`, `allowWhere`, `allowAttributesOf`, `inheritTypesFrom`.
+ *
+ * @property {Boolean} isBlock
+ * Whether this item is paragraph-like. Generally speaking, content is usually made out of blocks
+ * like paragraphs, list items, images, headings, etc. All these elements are marked as blocks. A block
+ * should not allow another block inside. Note: There is also the `$block` generic item which has `isBlock` set to `true`.
+ * Most block type items will inherit from `$block` (through `inheritAllFrom`).
+ *
+ * Read more about the block elements in the
+ * {@glink framework/guides/deep-dive/schema#block-elements Block elements} section of the "Schema" deep dive} guide.
+ *
+ * @property {Boolean} isInline
+ * Whether an item is "text-like" and should be treated as an inline node. Examples of inline elements:
+ * `$text`, `softBreak` (`<br>`), etc.
+ *
+ * Read more about the inline elements in the
+ * {@glink framework/guides/deep-dive/schema#inline-elements Inline elements} section of the "Schema" deep dive} guide.
+ *
+ * @property {Boolean} isLimit
+ * It can be understood as whether this element should not be split by <kbd>Enter</kbd>.
+ * Examples of limit elements: `$root`, table cell, image caption, etc. In other words, all actions that happen inside
+ * a limit element are limited to its content.
+ *
+ * Read more about the limit elements in the
+ * {@glink framework/guides/deep-dive/schema#limit-elements Limit elements} section of the "Schema" deep dive} guide.
+ *
+ * @property {Boolean} isObject
+ * Whether an item is "self-contained" and should be treated as a whole. Examples of object elements:
+ * `image`, `table`, `video`, etc.
+ *
+ * **Note:** An object is also a limit, so
+ * {@link module:engine/model/schema~Schema#isLimit `isLimit()`} returns `true` for object elements automatically.
+ *
+ * Read more about the object elements in the
+ * {@glink framework/guides/deep-dive/schema#object-elements Object elements} section of the "Schema" deep dive} guide.
  */
 
 /**

+ 0 - 1
packages/ckeditor5-highlight/src/highlightcommand.js

@@ -44,7 +44,6 @@ export default class HighlightCommand extends Command {
 	/**
 	 * Executes the command.
 	 *
-	 * @protected
 	 * @param {Object} [options] Options for the executed command.
 	 * @param {String} [options.value] The value to apply.
 	 *

+ 5 - 0
packages/ckeditor5-mention/docs/_snippets/examples/chat-with-mentions.js

@@ -146,6 +146,11 @@ function MentionLinks( editor ) {
 				class: 'mention',
 				'data-mention': modelAttributeValue.id,
 				href
+			}, {
+				// Make mention attribute to be wrapped by other attribute elements.
+				priority: 20,
+				// Prevent merging mentions together.
+				id: modelAttributeValue.uid
 			} );
 		},
 		converterPriority: 'high'

+ 6 - 1
packages/ckeditor5-mention/docs/_snippets/features/mention-customization.js

@@ -52,7 +52,7 @@ function MentionCustomization( editor ) {
 			value: viewItem => {
 				// The mention feature expects that the mention attribute value
 				// in the model is a plain object with a set of additional attributes.
-				// In order to create a proper object, use the toMentionAttribute() helper method:
+				// In order to create a proper object use the toMentionAttribute() helper method:
 				const mentionAttribute = editor.plugins.get( 'Mention' ).toMentionAttribute( viewItem, {
 					// Add any other properties that you need.
 					link: viewItem.getAttribute( 'href' ),
@@ -79,6 +79,11 @@ function MentionCustomization( editor ) {
 				'data-mention': modelAttributeValue.id,
 				'data-user-id': modelAttributeValue.userId,
 				'href': modelAttributeValue.link
+			}, {
+				// Make mention attribute to be wrapped by other attribute elements.
+				priority: 20,
+				// Prevent merging mentions together.
+				id: modelAttributeValue.uid
 			} );
 		},
 		converterPriority: 'high'

+ 5 - 0
packages/ckeditor5-mention/docs/examples/chat-with-mentions.md

@@ -327,6 +327,11 @@ function MentionLinks( editor ) {
 				class: 'mention',
 				'data-mention': modelAttributeValue.id,
 				href
+			}, {
+				// Make mention attribute to be wrapped by other attribute elements.
+				priority: 20,
+				// Prevent merging mentions together.
+				id: modelAttributeValue.uid
 			} );
 		},
 		converterPriority: 'high'

+ 15 - 1
packages/ckeditor5-mention/docs/features/mentions.md

@@ -180,7 +180,7 @@ A full, working demo with all possible customizations and its source code is ava
 
 ### Customizing the output
 
-In order to change the markup generated by the editor for mentions, you can overwrite the default converter of the mention feature. To do that, you must specify both {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher upcast} and {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher downcast} converters.
+In order to change the markup generated by the editor for mentions, you can overwrite the default converter of the mention feature. To do that, you must specify both {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher upcast} and {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher downcast} converters using {@link module:engine/view/attributeelement~AttributeElement}.
 
 The example below defines a plugin that overrides the default output:
 
@@ -196,6 +196,10 @@ To a link:
 
 The converters must be defined with a `'high'` priority to be executed before the {@link features/link link} feature's converter and before the default converter of the mention feature. A mention is stored in the model as a {@link framework/guides/architecture/editing-engine#text-attributes text attribute} that stores an object (see {@link module:mention/mention~MentionFeedItem}).
 
+To control how the mention element is wrapped by other attribute elements (like bold, italic, etc) set its {@link module:engine/view/attributeelement~AttributeElement#priority}. To replicate default plugin behavior and make mention to be wrapped by other elements set priority to `20`.
+
+By default, attribute elements that are next to each other and have the same value will be rendered as single HTML element. To prevent this the model attribute value object expose a unique id of each inserted mention to the model as `uid`. To prevent merging subsequent mentions set it as {@link module:engine/view/attributeelement~AttributeElement#id}.
+
 **Note:** The feature prevents copying fragments of existing mentions. If only a part of a mention is selected, it will be copied as plain text. The internal converter with the {@link module:engine/conversion/conversion~ConverterDefinition `'highest'` priority} controls this behaviour; thus, we do not recommend adding mention converters with the `'highest'` priority to avoid collisions and quirky results.
 
 ```js
@@ -254,6 +258,11 @@ function MentionCustomization( editor ) {
 				'data-mention': modelAttributeValue.id,
 				'data-user-id': modelAttributeValue.userId,
 				'href': modelAttributeValue.link
+			}, {
+				// Make mention attribute to be wrapped by other attribute elements.
+				priority: 20,
+				// Prevent merging mentions together.
+				id: modelAttributeValue.uid
 			} );
 		},
 		converterPriority: 'high'
@@ -341,6 +350,11 @@ function MentionCustomization( editor ) {
 				'data-mention': modelAttributeValue.id,
 				'data-user-id': modelAttributeValue.userId,
 				'href': modelAttributeValue.link
+			}, {
+				// Make mention attribute to be wrapped by other attribute elements.
+				priority: 20,
+				// Prevent merging mentions together.
+				id: modelAttributeValue.uid
 			} );
 		},
 		converterPriority: 'high'

+ 4 - 3
packages/ckeditor5-mention/src/mention.js

@@ -29,7 +29,7 @@ export default class Mention extends Plugin {
 	 *
 	 *		// For a view element: <span data-mention="@joe">@John Doe</span>
 	 *		// it will return:
-	 *		// { id: '@joe', userId: '1234', _uid: '7a7bc7...', _text: '@John Doe' }
+	 *		// { id: '@joe', userId: '1234', uid: '7a7bc7...', _text: '@John Doe' }
 	 *
 	 * @param {module:engine/view/element~Element} viewElement
 	 * @param {String|Object} [data] Additional data to be stored in the mention attribute.
@@ -225,8 +225,9 @@ export default class Mention extends Plugin {
  * See {@link module:mention/mention~Mention#toMentionAttribute `Mention#toMentionAttribute()`}.
  *
  * @interface module:mention/mention~MentionAttribute
- * @property {String} id The ID of a mention. It identifies the mention item in the mention feed.
- * @property {String} _uid An internal mention view item ID. Should be passed as an `option.id` when using
+ * @property {String} id The ID of a mention. It identifies the mention item in the mention feed. There can be multiple mentions
+ * in the document with the same ID (e.g. the same hashtag being mentioned).
+ * @property {String} uid A unique ID of this mention instance. Should be passed as an `option.id` when using
  * {@link module:engine/view/downcastwriter~DowncastWriter#createAttributeElement writer.createAttributeElement()}.
  * @property {String} _text Helper property that stores the text of the inserted mention. Used for detecting a broken mention
  * in the editing area.

+ 2 - 2
packages/ckeditor5-mention/src/mentionediting.js

@@ -69,7 +69,7 @@ export default class MentionEditing extends Plugin {
 }
 
 export function _addMentionAttributes( baseMentionData, data ) {
-	return Object.assign( { _uid: uid() }, baseMentionData, data || {} );
+	return Object.assign( { uid: uid() }, baseMentionData, data || {} );
 }
 
 /**
@@ -142,7 +142,7 @@ function createViewMentionElement( mention, viewWriter ) {
 	};
 
 	const options = {
-		id: mention._uid,
+		id: mention.uid,
 		priority: 20
 	};
 

+ 4 - 1
packages/ckeditor5-mention/tests/manual/mention-custom-view.js

@@ -50,7 +50,10 @@ class CustomMentionAttributeView extends Plugin {
 					class: 'mention',
 					'data-mention': modelAttributeValue.id,
 					'href': modelAttributeValue.link
-				}, { id: modelAttributeValue._uid } );
+				}, {
+					priority: 20,
+					id: modelAttributeValue.uid
+				} );
 			},
 			converterPriority: 'high'
 		} );

+ 2 - 2
packages/ckeditor5-mention/tests/mention.js

@@ -62,7 +62,7 @@ describe( 'Mention', () => {
 			const mentionAttribute = editor.plugins.get( 'Mention' ).toMentionAttribute( viewElement );
 
 			expect( mentionAttribute ).to.have.property( 'id', '@John' );
-			expect( mentionAttribute ).to.have.property( '_uid' );
+			expect( mentionAttribute ).to.have.property( 'uid' );
 			expect( mentionAttribute ).to.have.property( '_text', 'John Doe' );
 		} );
 
@@ -77,7 +77,7 @@ describe( 'Mention', () => {
 
 			expect( mentionAttribute ).to.have.property( 'id', '@John' );
 			expect( mentionAttribute ).to.have.property( 'foo', 'bar' );
-			expect( mentionAttribute ).to.have.property( '_uid' );
+			expect( mentionAttribute ).to.have.property( 'uid' );
 			expect( mentionAttribute ).to.have.property( '_text', 'John Doe' );
 		} );
 

+ 1 - 1
packages/ckeditor5-mention/tests/mentioncommand.js

@@ -167,7 +167,7 @@ describe( 'MentionCommand', () => {
 
 	function assertMention( textNode, id ) {
 		expect( textNode.hasAttribute( 'mention' ) ).to.be.true;
-		expect( textNode.getAttribute( 'mention' ) ).to.have.property( '_uid' );
+		expect( textNode.getAttribute( 'mention' ) ).to.have.property( 'uid' );
 		expect( textNode.getAttribute( 'mention' ) ).to.have.property( '_text', textNode.data );
 		expect( textNode.getAttribute( 'mention' ) ).to.have.property( 'id', id );
 	}

+ 15 - 9
packages/ckeditor5-mention/tests/mentionediting.js

@@ -77,7 +77,7 @@ describe( 'MentionEditing', () => {
 			expect( textNode.hasAttribute( 'mention' ) ).to.be.true;
 			expect( textNode.getAttribute( 'mention' ) ).to.have.property( 'id', '@John' );
 			expect( textNode.getAttribute( 'mention' ) ).to.have.property( '_text', '@John' );
-			expect( textNode.getAttribute( 'mention' ) ).to.have.property( '_uid' );
+			expect( textNode.getAttribute( 'mention' ) ).to.have.property( 'uid' );
 
 			const expectedView = '<p>foo <span class="mention" data-mention="@John">@John</span> bar</p>';
 
@@ -96,7 +96,7 @@ describe( 'MentionEditing', () => {
 			expect( textNode.hasAttribute( 'mention' ) ).to.be.true;
 			expect( textNode.getAttribute( 'mention' ) ).to.have.property( 'id', '@Ted Mosby' );
 			expect( textNode.getAttribute( 'mention' ) ).to.have.property( '_text', 'Ted Mosby' );
-			expect( textNode.getAttribute( 'mention' ) ).to.have.property( '_uid' );
+			expect( textNode.getAttribute( 'mention' ) ).to.have.property( 'uid' );
 
 			const expectedView = '<p>Hello <b class="mention" data-mention="@Ted Mosby">Ted Mosby</b></p>';
 
@@ -122,8 +122,8 @@ describe( 'MentionEditing', () => {
 			assertTextNode( paragraph.getChild( 0 ) );
 			assertTextNode( paragraph.getChild( 1 ) );
 
-			const firstMentionId = paragraph.getChild( 0 ).getAttribute( 'mention' )._uid;
-			const secondMentionId = paragraph.getChild( 1 ).getAttribute( 'mention' )._uid;
+			const firstMentionId = paragraph.getChild( 0 ).getAttribute( 'mention' ).uid;
+			const secondMentionId = paragraph.getChild( 1 ).getAttribute( 'mention' ).uid;
 
 			expect( firstMentionId ).to.not.equal( secondMentionId );
 
@@ -138,7 +138,7 @@ describe( 'MentionEditing', () => {
 				expect( textNode.hasAttribute( 'mention' ) ).to.be.true;
 				expect( textNode.getAttribute( 'mention' ) ).to.have.property( 'id', '@John' );
 				expect( textNode.getAttribute( 'mention' ) ).to.have.property( '_text', '@John' );
-				expect( textNode.getAttribute( 'mention' ) ).to.have.property( '_uid' );
+				expect( textNode.getAttribute( 'mention' ) ).to.have.property( 'uid' );
 			}
 		} );
 
@@ -151,7 +151,7 @@ describe( 'MentionEditing', () => {
 			expect( textNode.hasAttribute( 'mention' ) ).to.be.true;
 			expect( textNode.getAttribute( 'mention' ) ).to.have.property( 'id', '@John' );
 			expect( textNode.getAttribute( 'mention' ) ).to.have.property( '_text', '@Jo' );
-			expect( textNode.getAttribute( 'mention' ) ).to.have.property( '_uid' );
+			expect( textNode.getAttribute( 'mention' ) ).to.have.property( 'uid' );
 
 			const expectedView = '<p><span class="mention" data-mention="@John">@Jo</span></p>';
 
@@ -197,7 +197,10 @@ describe( 'MentionEditing', () => {
 						class: 'mention',
 						'data-mention': modelAttributeValue.id,
 						'href': modelAttributeValue.link
-					}, { id: modelAttributeValue._uid } );
+					}, {
+						priority: 20,
+						id: modelAttributeValue.uid
+					} );
 				},
 				converterPriority: 'high'
 			} );
@@ -312,7 +315,7 @@ describe( 'MentionEditing', () => {
 			expect( textNode.hasAttribute( 'mention' ) ).to.be.true;
 			expect( textNode.getAttribute( 'mention' ) ).to.have.property( 'id', '@John' );
 			expect( textNode.getAttribute( 'mention' ) ).to.have.property( '_text', '@John' );
-			expect( textNode.getAttribute( 'mention' ) ).to.have.property( '_uid' );
+			expect( textNode.getAttribute( 'mention' ) ).to.have.property( 'uid' );
 
 			model.change( writer => {
 				const paragraph = doc.getRoot().getChild( 0 );
@@ -677,7 +680,10 @@ function addCustomMentionConverters( editor ) {
 			return viewWriter.createAttributeElement( 'b', {
 				class: 'mention',
 				'data-mention': modelAttributeValue.id
-			}, { id: modelAttributeValue._uid } );
+			}, {
+				priority: 20,
+				id: modelAttributeValue.uid
+			} );
 		},
 		converterPriority: 'high'
 	} );

+ 5 - 5
packages/ckeditor5-mention/tests/mentionui.js

@@ -621,7 +621,7 @@ describe( 'MentionUI', () => {
 						writer.createPositionAt( doc.getRoot().getChild( 0 ), 9 )
 					);
 
-					writer.setAttribute( 'mention', { id: '@Lily', _uid: 1234 }, range );
+					writer.setAttribute( 'mention', { id: '@Lily', uid: 1234 }, range );
 				} );
 
 				return waitForDebounce()
@@ -651,7 +651,7 @@ describe( 'MentionUI', () => {
 						writer.createPositionAt( doc.getRoot().getChild( 0 ), 9 )
 					);
 
-					writer.setAttribute( 'mention', { id: '@Lily', _uid: 1234 }, range );
+					writer.setAttribute( 'mention', { id: '@Lily', uid: 1234 }, range );
 				} );
 
 				return waitForDebounce()
@@ -725,7 +725,7 @@ describe( 'MentionUI', () => {
 			it( 'should not show panel when selection is after existing mention', () => {
 				setData( model, '<paragraph>foo [@Lily] bar[]</paragraph>' );
 				model.change( writer => {
-					writer.setAttribute( 'mention', { id: '@Lily', _uid: 1234 }, doc.selection.getFirstRange() );
+					writer.setAttribute( 'mention', { id: '@Lily', uid: 1234 }, doc.selection.getFirstRange() );
 				} );
 
 				return waitForDebounce()
@@ -750,7 +750,7 @@ describe( 'MentionUI', () => {
 						writer.createPositionAt( doc.getRoot().getChild( 0 ), 4 ),
 						writer.createPositionAt( doc.getRoot().getChild( 0 ), 9 )
 					);
-					writer.setAttribute( 'mention', { id: '@Lily', _uid: 1234 }, range );
+					writer.setAttribute( 'mention', { id: '@Lily', uid: 1234 }, range );
 				} );
 
 				return waitForDebounce()
@@ -1295,7 +1295,7 @@ describe( 'MentionUI', () => {
 				setData( model, '<paragraph>foo [#101] bar</paragraph><paragraph></paragraph>' );
 
 				model.change( writer => {
-					writer.setAttribute( 'mention', { id: '#101', _uid: 1234 }, doc.selection.getFirstRange() );
+					writer.setAttribute( 'mention', { id: '#101', uid: 1234 }, doc.selection.getFirstRange() );
 				} );
 
 				// Increase the response time to extend the debounce time out.

+ 49 - 0
packages/ckeditor5-paragraph/src/insertparagraphcommand.js

@@ -0,0 +1,49 @@
+/**
+ * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+/**
+ * @module paragraph/insertparagraphcommand
+ */
+
+import Command from '@ckeditor/ckeditor5-core/src/command';
+
+/**
+ * The insert paragraph command. It inserts a new paragraph at a specific
+ * {@link module:engine/model/position~Position document position}.
+ *
+ *		// Insert a new paragraph before an element in the document.
+ *		editor.execute( 'insertParagraph', {
+ *			position: editor.model.createPositionBefore( element )
+ *		} );
+ *
+ * **Note**: This command moves the selection to the inserted paragraph.
+ *
+ * @extends module:core/command~Command
+ */
+export default class InsertParagraphCommand extends Command {
+	/**
+	 * Executes the command.
+	 *
+	 * @param {Object} options Options for the executed command.
+	 * @param {module:engine/model/position~Position} options.position The model position at which
+	 * the new paragraph will be inserted.
+	 * @fires execute
+	 */
+	execute( options ) {
+		const model = this.editor.model;
+
+		if ( !model.schema.checkChild( options.position, 'paragraph' ) ) {
+			return;
+		}
+
+		model.change( writer => {
+			const paragraph = writer.createElement( 'paragraph' );
+
+			model.insertContent( paragraph, options.position );
+
+			writer.setSelection( paragraph, 'in' );
+		} );
+	}
+}

+ 9 - 0
packages/ckeditor5-paragraph/src/paragraph.js

@@ -8,6 +8,7 @@
  */
 
 import ParagraphCommand from './paragraphcommand';
+import InsertParagraphCommand from './insertparagraphcommand';
 
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 
@@ -16,6 +17,13 @@ import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
  *
  * It introduces the `<paragraph>` element in the model which renders as a `<p>` element in the DOM and data.
  *
+ * It also brings two editors commands:
+ *
+ * * The {@link module:paragraph/paragraphcommand~ParagraphCommand `'paragraph'`} command that converts all
+ * blocks in the model selection into paragraphs.
+ * * The {@link module:paragraph/insertparagraphcommand~InsertParagraphCommand `'insertParagraph'`} command
+ * that inserts a new paragraph at a specified location in the model.
+ *
  * @extends module:core/plugin~Plugin
  */
 export default class Paragraph extends Plugin {
@@ -35,6 +43,7 @@ export default class Paragraph extends Plugin {
 		const data = editor.data;
 
 		editor.commands.add( 'paragraph', new ParagraphCommand( editor ) );
+		editor.commands.add( 'insertParagraph', new InsertParagraphCommand( editor ) );
 
 		// Schema.
 		model.schema.register( 'paragraph', { inheritAllFrom: '$block' } );

+ 101 - 0
packages/ckeditor5-paragraph/tests/insertparagraphcommand.js

@@ -0,0 +1,101 @@
+/**
+ * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltesteditor';
+import InsertParagraphCommand from '../src/insertparagraphcommand';
+
+import { setData, getData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
+
+describe( 'InsertParagraphCommand', () => {
+	let editor, model, document, command, root, schema;
+
+	beforeEach( () => {
+		return ModelTestEditor.create().then( newEditor => {
+			editor = newEditor;
+			model = editor.model;
+			document = model.document;
+			schema = model.schema;
+			command = new InsertParagraphCommand( editor );
+			root = document.getRoot();
+
+			editor.commands.add( 'insertParagraph', command );
+			schema.register( 'paragraph', { inheritAllFrom: '$block' } );
+			schema.register( 'heading1', { inheritAllFrom: '$block', allowIn: 'headersOnly' } );
+			schema.register( 'headersOnly', { inheritAllFrom: '$block' } );
+		} );
+	} );
+
+	afterEach( () => {
+		command.destroy();
+	} );
+
+	describe( 'execute()', () => {
+		it( 'should insert a paragraph at a specific document position and anchor the selection inside of it', () => {
+			setData( model, '<heading1>foo[]</heading1>' );
+
+			command.execute( {
+				position: model.createPositionBefore( root.getChild( 0 ) )
+			} );
+
+			expect( getData( model ) ).to.equal( '<paragraph>[]</paragraph><heading1>foo</heading1>' );
+		} );
+
+		it( 'should do nothing if the paragraph is not allowed at the provided position', () => {
+			setData( model, '<headersOnly><heading1>foo[]</heading1></headersOnly>' );
+
+			command.execute( {
+				position: model.createPositionBefore( root.getChild( 0 ).getChild( 0 ) )
+			} );
+
+			command.execute( {
+				position: model.createPositionAfter( root.getChild( 0 ).getChild( 0 ) )
+			} );
+
+			expect( getData( model ) ).to.equal( '<headersOnly><heading1>foo[]</heading1></headersOnly>' );
+		} );
+
+		describe( 'interation with existing paragraphs in the content', () => {
+			it( 'should insert a paragraph before another paragraph', () => {
+				setData( model, '<paragraph>foo[]</paragraph>' );
+
+				command.execute( {
+					position: model.createPositionBefore( root.getChild( 0 ) )
+				} );
+
+				expect( getData( model ) ).to.equal( '<paragraph>[]</paragraph><paragraph>foo</paragraph>' );
+			} );
+
+			it( 'should insert a paragraph after another paragraph', () => {
+				setData( model, '<paragraph>foo[]</paragraph>' );
+
+				command.execute( {
+					position: model.createPositionAfter( root.getChild( 0 ) )
+				} );
+
+				expect( getData( model ) ).to.equal( '<paragraph>foo</paragraph><paragraph>[]</paragraph>' );
+			} );
+
+			it( 'should not merge with a paragraph that precedes the position at which a new paragraph is inserted', () => {
+				setData( model, '<paragraph>bar</paragraph><heading1>foo[]</heading1>' );
+
+				command.execute( {
+					position: model.createPositionBefore( root.getChild( 1 ) )
+				} );
+
+				expect( getData( model ) ).to.equal( '<paragraph>bar</paragraph><paragraph>[]</paragraph><heading1>foo</heading1>' );
+			} );
+
+			it( 'should not merge with a paragraph that follows the position at which a new paragraph is inserted', () => {
+				setData( model, '<heading1>foo[]</heading1><paragraph>bar</paragraph>' );
+
+				command.execute( {
+					position: model.createPositionAfter( root.getChild( 0 ) )
+				} );
+
+				expect( getData( model ) ).to.equal( '<heading1>foo</heading1><paragraph>[]</paragraph><paragraph>bar</paragraph>' );
+			} );
+		} );
+	} );
+} );

+ 7 - 2
packages/ckeditor5-paragraph/tests/paragraph.js

@@ -5,6 +5,7 @@
 
 import Paragraph from '../src/paragraph';
 import ParagraphCommand from '../src/paragraphcommand';
+import InsertParagraphCommand from '../src/insertparagraphcommand';
 import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
 import {
 	getData as getModelData,
@@ -437,9 +438,13 @@ describe( 'Paragraph feature', () => {
 		} );
 	} );
 
-	describe( 'command', () => {
-		it( 'should be set in the editor', () => {
+	describe( 'commands', () => {
+		it( '"paragraph" command should be registered in the editor', () => {
 			expect( editor.commands.get( 'paragraph' ) ).to.be.instanceof( ParagraphCommand );
 		} );
+
+		it( '"insertParagraph" command should be registered in the editor', () => {
+			expect( editor.commands.get( 'insertParagraph' ) ).to.be.instanceof( InsertParagraphCommand );
+		} );
 	} );
 } );

+ 6 - 2
packages/ckeditor5-theme-lark/theme/ckeditor5-widget/widget.css

@@ -129,8 +129,12 @@
 
 	&:not(.ck-widget_selected) {
 		/* Disable visual effects of hover/active widget when CKEditor is in readOnly mode.
-		See: https://github.com/ckeditor/ckeditor5/issues/1261 */
-		--ck-widget-outline-thickness: 0;
+		 * See: https://github.com/ckeditor/ckeditor5/issues/1261
+		 *
+		 * Leave the unit because this custom property is used in calc() by other features.
+		 * See: https://github.com/ckeditor/ckeditor5/issues/6775
+		 */
+		--ck-widget-outline-thickness: 0px;
 	}
 
 	&.ck-widget_with-selection-handle {

+ 18 - 0
packages/ckeditor5-theme-lark/theme/ckeditor5-widget/widgettypearound.css

@@ -116,6 +116,24 @@
 	}
 }
 
+/*
+ * Hide type around buttons when the widget is selected as a child of a selected
+ * nested editable (e.g. mulit-cell table selection).
+ *
+ * See https://github.com/ckeditor/ckeditor5/issues/7263.
+ */
+.ck-editor__nested-editable.ck-editor__editable_selected {
+	& .ck-widget {
+		&.ck-widget_selected,
+		&:hover {
+			& > .ck-widget__type-around > .ck-widget__type-around__button {
+				pointer-events: none;
+				opacity: 0;
+			}
+		}
+	}
+}
+
 /*
  * Styles for the buttons when the widget is selected but the user clicked outside of the editor (blurred the editor).
  */

+ 6 - 10
packages/ckeditor5-widget/src/widgettypearound/widgettypearound.js

@@ -105,21 +105,17 @@ export default class WidgetTypeAround extends Plugin {
 	_insertParagraph( widgetViewElement, position ) {
 		const editor = this.editor;
 		const editingView = editor.editing.view;
-		let viewPosition;
+		const widgetModelElement = editor.editing.mapper.toModelElement( widgetViewElement );
+		let modelPosition;
 
 		if ( position === 'before' ) {
-			viewPosition = editingView.createPositionBefore( widgetViewElement );
+			modelPosition = editor.model.createPositionBefore( widgetModelElement );
 		} else {
-			viewPosition = editingView.createPositionAfter( widgetViewElement );
+			modelPosition = editor.model.createPositionAfter( widgetModelElement );
 		}
 
-		const modelPosition = editor.editing.mapper.toModelPosition( viewPosition );
-
-		editor.model.change( writer => {
-			const paragraph = writer.createElement( 'paragraph' );
-
-			writer.insert( paragraph, modelPosition );
-			writer.setSelection( paragraph, 0 );
+		editor.execute( 'insertParagraph', {
+			position: modelPosition
 		} );
 
 		editingView.focus();

+ 2 - 0
packages/ckeditor5-widget/tests/manual/type-around.html

@@ -21,6 +21,8 @@
 		}
 	</style>
 </head>
+<button id="toggleReadOnly" type="button">Toggle read–only mode</button>
+<hr />
 <div id="editor">
 	<figure class="image"><img src="sample.jpg" alt="bar">
 		<figcaption>Caption</figcaption>

+ 4 - 0
packages/ckeditor5-widget/tests/manual/type-around.js

@@ -90,6 +90,10 @@ class InlineWidget extends Plugin {
 	}
 }
 
+document.querySelector( '#toggleReadOnly' ).addEventListener( 'click', () => {
+	window.editor.isReadOnly = !window.editor.isReadOnly;
+} );
+
 ClassicEditor
 	.create( document.querySelector( '#editor' ), {
 		plugins: [ ArticlePluginSet, HorizontalLine, InlineWidget, MediaEmbed ],

+ 24 - 2
packages/ckeditor5-widget/tests/widgettypearound/widgettypearound.js

@@ -54,19 +54,41 @@ describe( 'WidgetTypeAround', () => {
 	} );
 
 	describe( '_insertParagraph()', () => {
-		it( 'should insert a paragraph with a selection before a widget when position is "before"', () => {
+		let executeSpy;
+
+		beforeEach( () => {
+			executeSpy = sinon.spy( editor, 'execute' );
+		} );
+
+		it( 'should execute the "insertParagraph" command when inserting a paragraph before the widget', () => {
 			setModelData( editor.model, '<blockWidget></blockWidget>' );
 
 			plugin._insertParagraph( viewRoot.getChild( 0 ), 'before' );
 
+			const spyExecutePosition = executeSpy.firstCall.args[ 1 ].position;
+			const positionBeforeWidget = editor.model.createPositionBefore( editor.model.document.getRoot().getChild( 0 ) );
+
+			sinon.assert.calledOnce( executeSpy );
+			sinon.assert.calledWith( executeSpy, 'insertParagraph' );
+
+			expect( spyExecutePosition.isEqual( positionBeforeWidget ) ).to.be.true;
+
 			expect( getModelData( editor.model ) ).to.equal( '<paragraph>[]</paragraph><blockWidget></blockWidget>' );
 		} );
 
-		it( 'should insert a paragraph with a selection after a widget when position is "after"', () => {
+		it( 'should execute the "insertParagraph" command when inserting a paragraph after the widget', () => {
 			setModelData( editor.model, '<blockWidget></blockWidget>' );
 
 			plugin._insertParagraph( viewRoot.getChild( 0 ), 'after' );
 
+			const spyExecutePosition = executeSpy.firstCall.args[ 1 ].position;
+			const positionAfterWidget = editor.model.createPositionAfter( editor.model.document.getRoot().getChild( 0 ) );
+
+			sinon.assert.calledOnce( executeSpy );
+			sinon.assert.calledWith( executeSpy, 'insertParagraph' );
+
+			expect( spyExecutePosition.isEqual( positionAfterWidget ) ).to.be.true;
+
 			expect( getModelData( editor.model ) ).to.equal( '<blockWidget></blockWidget><paragraph>[]</paragraph>' );
 		} );
 

+ 14 - 0
packages/ckeditor5-widget/theme/widgettypearound.css

@@ -65,3 +65,17 @@
 		}
 	}
 }
+
+/*
+ * Integration with the read-only mode of the editor.
+ */
+.ck.ck-editor__editable.ck-read-only .ck-widget__type-around {
+	display: none;
+}
+
+/*
+ * Integration with the restricted editing mode (feature) of the editor.
+ */
+.ck.ck-editor__editable.ck-restricted-editing_mode_restricted .ck-widget__type-around {
+	display: none;
+}

+ 168 - 137
yarn.lock

@@ -791,29 +791,30 @@
     date-fns "^1.29.0"
     lodash-es "^4.17.11"
 
-"@ckeditor/ckeditor5-dev-docs@^11.1.0":
-  version "11.1.1"
-  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-dev-docs/-/ckeditor5-dev-docs-11.1.1.tgz#ed497e51db0c60767de9cb4b28b62d189b74d718"
-  integrity sha512-ej7RJrJm+CPYhL3JbVxESOGc/zBRa9ZQ3a7x8QextoW/MfSWRoCDTnG3j0k2IlLDEHMcW1Nwcf9Vp3LC0A5l3w==
+"@ckeditor/ckeditor5-dev-docs@^20.0.0":
+  version "20.0.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-dev-docs/-/ckeditor5-dev-docs-20.0.0.tgz#8a63ef836bc92397acd5713fb63d8fc9513a586a"
+  integrity sha512-Kxdwi6xTj+8cCoC41uDsmJzZkX22wFFnMScQFPmoYN8Gub2JJWmbz1j2wQsDaOfx8Cx9QrDfpnbzGk0T6fqa4Q==
   dependencies:
-    "@ckeditor/ckeditor5-dev-utils" "^13.0.1"
-    "@ckeditor/jsdoc-plugins" "^3.0.9"
+    "@ckeditor/ckeditor5-dev-utils" "^20.0.0"
+    "@ckeditor/jsdoc-plugins" "^20.0.0"
     jsdoc ckeditor/jsdoc#node12
     map-stream "^0.0.7"
     tmp "^0.0.33"
     vinyl-fs "^3.0.2"
 
-"@ckeditor/ckeditor5-dev-env@^18.0.0":
-  version "18.0.1"
-  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-dev-env/-/ckeditor5-dev-env-18.0.1.tgz#f848863a82068fc7cbc67a68bcedcabad563bd11"
-  integrity sha512-vPrh8s3yJEVuba0Uo/7N1Ee0Err8Hmwc9+9RkjC/RvG+ome1E416Y6lqEY4MkdpF/KSjwi7OzPgx+OkCJUo1dA==
+"@ckeditor/ckeditor5-dev-env@^20.0.0":
+  version "20.0.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-dev-env/-/ckeditor5-dev-env-20.0.0.tgz#5ba722e156e1cf7f9d7404b4c58413ad69090d7f"
+  integrity sha512-OUBBoeIjIafZf6GyA7ybEM/vhyOZa1MuxdD4WiZKnHso+1n2CMvo31NjnU/67aN8PBvdo/HeP8ireap5JbcZ8g==
   dependencies:
-    "@ckeditor/ckeditor5-dev-utils" "^13.0.1"
+    "@ckeditor/ckeditor5-dev-utils" "^20.0.0"
     "@octokit/rest" "^16.28.2"
     chalk "^3.0.0"
     compare-func "^1.3.2"
     concat-stream "^2.0.0"
     conventional-changelog "^3.1.8"
+    conventional-changelog-writer "^4.0.16"
     conventional-commits-filter "^2.0.0"
     conventional-commits-parser "^3.0.0"
     del "^5.0.0"
@@ -827,14 +828,14 @@
     request "^2.83.0"
     semver "^6.2.0"
 
-"@ckeditor/ckeditor5-dev-tests@^19.2.0":
-  version "19.2.0"
-  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-dev-tests/-/ckeditor5-dev-tests-19.2.0.tgz#8cf0dda0ba1982834e3c09fa275db6f0805d6faf"
-  integrity sha512-7wPA9XvQCAXGs/kKtXQLgIw/+eVlVj//5zvql1DGStHRnFdZY3sSJCBBpZ5tPfxVUHgv4/cftaBOs3xgQQ+Tgw==
+"@ckeditor/ckeditor5-dev-tests@^20.0.0":
+  version "20.0.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-dev-tests/-/ckeditor5-dev-tests-20.0.0.tgz#eb1531ac56b914ecd9dd2fd168d7e14347dbdd70"
+  integrity sha512-KJsy+rdptjtXvtKT6TdheZvWZOP2rCRPtQ/nNQNBA3pJ9ZCdV687D2L7qRFBjdCUWey8HiCUSDHo6ZNDaL153w==
   dependencies:
     "@babel/core" "^7.0.0"
-    "@ckeditor/ckeditor5-dev-utils" "^13.0.1"
-    "@ckeditor/ckeditor5-dev-webpack-plugin" "^9.0.2"
+    "@ckeditor/ckeditor5-dev-utils" "^20.0.0"
+    "@ckeditor/ckeditor5-dev-webpack-plugin" "^20.0.0"
     "@ckeditor/ckeditor5-inspector" "^2.0.0"
     babel-core "^6.26.0"
     babel-loader "^8.0.2"
@@ -865,7 +866,6 @@
     minimist "^1.2.0"
     mkdirp "^0.5.1"
     mocha "^6.1.4"
-    mrgit "^1.0.0"
     postcss-loader "^3.0.0"
     raw-loader "^3.1.0"
     sinon "^7.3.2"
@@ -894,7 +894,38 @@
     shelljs "^0.8.1"
     through2 "^3.0.1"
 
-"@ckeditor/ckeditor5-dev-webpack-plugin@^9.0.0", "@ckeditor/ckeditor5-dev-webpack-plugin@^9.0.2":
+"@ckeditor/ckeditor5-dev-utils@^20.0.0":
+  version "20.0.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-dev-utils/-/ckeditor5-dev-utils-20.0.0.tgz#f4d467845b7d2a859edb41acf5297f693feed72d"
+  integrity sha512-dJTrmIixAgWrozC9JlMg8GOCXd5v36Wnat8auFTvrUnwf5DM8fGLZ1S+XXhYfOfQTCV8wxwSv+aC3FUHLcHy1A==
+  dependencies:
+    acorn "^6.2.1"
+    acorn-walk "^6.2.0"
+    chalk "^3.0.0"
+    cssnano "^4.0.0"
+    del "^5.0.0"
+    escodegen "^1.9.0"
+    fs-extra "^8.1.0"
+    javascript-stringify "^1.6.0"
+    pofile "^1.0.9"
+    postcss "^7.0.17"
+    postcss-import "^12.0.0"
+    postcss-mixins "^6.2.0"
+    postcss-nesting "^7.0.0"
+    shelljs "^0.8.1"
+    through2 "^3.0.1"
+
+"@ckeditor/ckeditor5-dev-webpack-plugin@^20.0.0":
+  version "20.0.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-dev-webpack-plugin/-/ckeditor5-dev-webpack-plugin-20.0.0.tgz#8ce4c2cd0db897b526275dab3370fc73b238c432"
+  integrity sha512-QRwls5WJZsW6vpKpiMOgOwWs64mR83YT1ywzwG2kXQc6iN4kesIDWL/U7g8ECABNbN4Jw+v0nv93YSOlnS1ieA==
+  dependencies:
+    "@ckeditor/ckeditor5-dev-utils" "^20.0.0"
+    chalk "^3.0.0"
+    rimraf "^2.6.2"
+    webpack-sources "^1.1.0"
+
+"@ckeditor/ckeditor5-dev-webpack-plugin@^9.0.0":
   version "9.0.2"
   resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-dev-webpack-plugin/-/ckeditor5-dev-webpack-plugin-9.0.2.tgz#4966947d2ec5315d9f41370a45750dee43a8d648"
   integrity sha512-724Qq5pipivr42Pn3cEV4SG+a57BR5oW/4kIDIFy9Y8cpwOZtpbfWizSYLtELICgmv1ARFbb3aVwANcjrb2bUw==
@@ -965,7 +996,15 @@
     "@ckeditor/ckeditor5-utils" "^19.0.0"
     lodash-es "^4.17.11"
 
-"@ckeditor/jsdoc-plugins@^3.0.1", "@ckeditor/jsdoc-plugins@^3.0.9":
+"@ckeditor/jsdoc-plugins@^20.0.0":
+  version "20.0.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/jsdoc-plugins/-/jsdoc-plugins-20.0.0.tgz#84e1cd03dde202abba43f4b75efd15d87fed26a3"
+  integrity sha512-DTxRfX71mecmzuAimT43Km5Hn+WW2kDqY2gpsKfO60PTga4B/prtD7dIIKnBTD/sQ1SJSyYZs4k0cgiBNB0NUQ==
+  dependencies:
+    fs-extra "^8.1.0"
+    lodash "^4.17.15"
+
+"@ckeditor/jsdoc-plugins@^3.0.1":
   version "3.0.9"
   resolved "https://registry.yarnpkg.com/@ckeditor/jsdoc-plugins/-/jsdoc-plugins-3.0.9.tgz#aa0d3a2997c786c5ca8447824eed4c623128ff14"
   integrity sha512-rR61hJaBKGOHNyUEZMF/ruK4bm7/C40cCHcoUJgRH+/GmxqPiJt4MqJ/T4x0+yGJ2OgdXQYdI2y44c39qjhNzg==
@@ -981,12 +1020,13 @@
     katex "^0.10.0"
 
 "@istanbuljs/load-nyc-config@^1.0.0":
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz#10602de5570baea82f8afbfa2630b24e7a8cfe5b"
-  integrity sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg==
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
+  integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==
   dependencies:
     camelcase "^5.3.1"
     find-up "^4.1.0"
+    get-package-type "^0.1.0"
     js-yaml "^3.13.1"
     resolve-from "^5.0.0"
 
@@ -1030,11 +1070,11 @@
     fastq "^1.6.0"
 
 "@octokit/auth-token@^2.4.0":
-  version "2.4.0"
-  resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.0.tgz#b64178975218b99e4dfe948253f0673cbbb59d9f"
-  integrity sha512-eoOVMjILna7FVQf96iWc3+ZtE/ZT6y8ob8ZzcqKY1ibSQCnu4O/B7pJvzMx5cyZ/RjAff6DAdEb0O0Cjcxidkg==
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.1.tgz#375d79eebd03750e6a9b0299e80b8167c7c85655"
+  integrity sha512-NB81O5h39KfHYGtgfWr2booRxp2bWOJoqbWwbyUg2hw6h35ArWYlAST5B3XwAkbdcx13yt84hFXyFP5X0QToWA==
   dependencies:
-    "@octokit/types" "^2.0.0"
+    "@octokit/types" "^4.0.1"
 
 "@octokit/endpoint@^6.0.1":
   version "6.0.1"
@@ -1075,18 +1115,18 @@
     once "^1.4.0"
 
 "@octokit/request-error@^2.0.0":
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.0.0.tgz#94ca7293373654400fbb2995f377f9473e00834b"
-  integrity sha512-rtYicB4Absc60rUv74Rjpzek84UbVHGHJRu4fNVlZ1mCcyUPPuzFfG9Rn6sjHrd95DEsmjSt1Axlc699ZlbDkw==
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.0.1.tgz#49bd71e811daffd5bdd06ef514ca47b5039682d1"
+  integrity sha512-5lqBDJ9/TOehK82VvomQ6zFiZjPeSom8fLkFVLuYL3sKiIb5RB8iN/lenLkY7oBmyQcGP7FBMGiIZTO8jufaRQ==
   dependencies:
-    "@octokit/types" "^2.0.0"
+    "@octokit/types" "^4.0.1"
     deprecation "^2.0.0"
     once "^1.4.0"
 
 "@octokit/request@^5.2.0":
-  version "5.4.2"
-  resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.2.tgz#74f8e5bbd39dc738a1b127629791f8ad1b3193ee"
-  integrity sha512-zKdnGuQ2TQ2vFk9VU8awFT4+EYf92Z/v3OlzRaSh4RIP0H6cvW1BFPXq4XYvNez+TPQjqN+0uSkCYnMFFhcFrw==
+  version "5.4.3"
+  resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.3.tgz#85b78ea4ae6e1c4ac2b02528102d4cd776145935"
+  integrity sha512-RtqMzF3mhqxmWoqVD84x2gdtbqn2inTBU/HPkWf5u0R5r7fBTaLPAcCBgukeI2gjTwD9ChL9Cu0MlTBs7B/tSw==
   dependencies:
     "@octokit/endpoint" "^6.0.1"
     "@octokit/request-error" "^2.0.0"
@@ -1126,6 +1166,13 @@
   dependencies:
     "@types/node" ">= 8"
 
+"@octokit/types@^4.0.1":
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/@octokit/types/-/types-4.0.1.tgz#dd32ff2407699f3a0c909cdd24de17b45b7d7051"
+  integrity sha512-Ho6h7w2h9y8RRE8r656hIj1oiSbwbIHJGF5r9G5FOwS2VdDPq8QLGvsG4x6pKHpvyGK7j+43sAc2cJKMiFoIJw==
+  dependencies:
+    "@types/node" ">= 8"
+
 "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
@@ -1187,9 +1234,9 @@
     any-observable "^0.3.0"
 
 "@sinonjs/commons@^1", "@sinonjs/commons@^1.3.0", "@sinonjs/commons@^1.4.0", "@sinonjs/commons@^1.7.0":
-  version "1.7.2"
-  resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.7.2.tgz#505f55c74e0272b43f6c52d81946bed7058fc0e2"
-  integrity sha512-+DUO6pnp3udV/v2VfUWgaY5BIE1IfT7lLfeDzPVeMT1XKkaAp9LgSI9x5RtrFQoZ9Oi0PgXQQHPaoKu7dCjVxw==
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.0.tgz#c8d68821a854c555bba172f3b06959a0039b236d"
+  integrity sha512-wEj54PfsZ5jGSwMX68G8ZXFawcSglQSXqCftWX3ec8MDUzQdHgcKvw97awHbY0efQEL5iKUOAmmVtoYgmrSG4Q==
   dependencies:
     type-detect "4.0.8"
 
@@ -1262,14 +1309,14 @@
   integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=
 
 "@types/node@*", "@types/node@>= 8":
-  version "14.0.1"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.1.tgz#5d93e0a099cd0acd5ef3d5bde3c086e1f49ff68c"
-  integrity sha512-FAYBGwC+W6F9+huFIDtn43cpy7+SzG+atzRiTfdp3inUKL2hXnd4rG8hylJLIh4+hqrQy1P17kvJByE/z825hA==
+  version "14.0.5"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.5.tgz#3d03acd3b3414cf67faf999aed11682ed121f22b"
+  integrity sha512-90hiq6/VqtQgX8Sp0EzeIsv3r+ellbGj4URKj5j30tLlZvRUpnAe9YbYnjl3pJM93GyXU0tghHhvXHq+5rnCKA==
 
 "@types/node@^13.7.0":
-  version "13.13.6"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.6.tgz#caa6756b64d30547a2082235531fa0dd8cba1b6e"
-  integrity sha512-zqRj8ugfROCjXCNbmPBe2mmQ0fJWP9lQaN519hwunOgpHgVykme4G6FW95++dyNFDvJUk4rtExkVkL0eciu5NA==
+  version "13.13.9"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.9.tgz#79df4ae965fb76d31943b54a6419599307a21394"
+  integrity sha512-EPZBIGed5gNnfWCiwEIwTE2Jdg4813odnG8iNPMQGrqVxrI+wL68SPtPeCX+ZxGBaA6pKAVc6jaKgP/Q0QzfdQ==
 
 "@types/normalize-package-data@^2.4.0":
   version "2.4.0"
@@ -1277,9 +1324,9 @@
   integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
 
 "@types/q@^1.5.1":
-  version "1.5.2"
-  resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8"
-  integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==
+  version "1.5.4"
+  resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24"
+  integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==
 
 "@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2":
   version "2.0.3"
@@ -1911,17 +1958,17 @@ atob@^2.1.2:
   integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
 
 autoprefixer@^9.5.1:
-  version "9.7.6"
-  resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.7.6.tgz#63ac5bbc0ce7934e6997207d5bb00d68fa8293a4"
-  integrity sha512-F7cYpbN7uVVhACZTeeIeealwdGM6wMtfWARVLTy5xmKtgVdBNJvbDRoCK3YO1orcs7gv/KwYlb3iXwu9Ug9BkQ==
+  version "9.8.0"
+  resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.0.tgz#68e2d2bef7ba4c3a65436f662d0a56a741e56511"
+  integrity sha512-D96ZiIHXbDmU02dBaemyAg53ez+6F5yZmapmgKcjm35yEe1uVDYI8hGW3VYoGRaG290ZFf91YxHrR518vC0u/A==
   dependencies:
-    browserslist "^4.11.1"
-    caniuse-lite "^1.0.30001039"
+    browserslist "^4.12.0"
+    caniuse-lite "^1.0.30001061"
     chalk "^2.4.2"
     normalize-range "^0.1.2"
     num2fraction "^1.2.2"
-    postcss "^7.0.27"
-    postcss-value-parser "^4.0.3"
+    postcss "^7.0.30"
+    postcss-value-parser "^4.1.0"
 
 aws-sign2@~0.7.0:
   version "0.7.0"
@@ -2211,14 +2258,14 @@ bluebird@~3.4.6:
   integrity sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=
 
 bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.4.0:
-  version "4.11.8"
-  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
-  integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==
+  version "4.11.9"
+  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828"
+  integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==
 
 bn.js@^5.1.1:
-  version "5.1.1"
-  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.1.tgz#48efc4031a9c4041b9c99c6941d903463ab62eb5"
-  integrity sha512-IUTD/REb78Z2eodka1QZyyEk66pciRcP6Sroka0aI3tG/iwIdYLrBD62RsubR7vqdt3WyX8p4jxeatzmRSphtA==
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.2.tgz#c9686902d3c9a27729f43ab10f9d79c2004da7b0"
+  integrity sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==
 
 body-parser@^1.16.1:
   version "1.19.0"
@@ -2336,9 +2383,9 @@ browserify-rsa@^4.0.0, browserify-rsa@^4.0.1:
     randombytes "^2.0.1"
 
 browserify-sign@^4.0.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.1.0.tgz#4fe971b379a5aeb4925e06779f9fa1f41d249d70"
-  integrity sha512-VYxo7cDCeYUoBZ0ZCy4UyEUCP3smyBd4DRQM5nrFS1jJjPJjX7rP3oLRpPoWfkhQfyJ0I9ZbHbKafrFD/SGlrg==
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.0.tgz#545d0b1b07e6b2c99211082bf1b12cce7a0b0e11"
+  integrity sha512-hEZC1KEeYuoHRqhGhTy6gWrpJA3ZDjFWv0DE61643ZnOXAKJb3u7yWcrU0mMc9SwAqK1n7myPGndkp0dFG7NFA==
   dependencies:
     bn.js "^5.1.1"
     browserify-rsa "^4.0.1"
@@ -2348,6 +2395,7 @@ browserify-sign@^4.0.0:
     inherits "^2.0.4"
     parse-asn1 "^5.1.5"
     readable-stream "^3.6.0"
+    safe-buffer "^5.2.0"
 
 browserify-zlib@^0.2.0:
   version "0.2.0"
@@ -2356,7 +2404,7 @@ browserify-zlib@^0.2.0:
   dependencies:
     pako "~1.0.5"
 
-browserslist@^4.0.0, browserslist@^4.11.1, browserslist@^4.8.5:
+browserslist@^4.0.0, browserslist@^4.11.1, browserslist@^4.12.0, browserslist@^4.8.5:
   version "4.12.0"
   resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.12.0.tgz#06c6d5715a1ede6c51fc39ff67fd647f740b656d"
   integrity sha512-UH2GkcEDSI0k/lRkuDSzFl9ZZ87skSy9w2XAn1MsZnL+4c4rqbBd3e82UWHbYDpztABrPBhZsTEeuxVfHppqDg==
@@ -2606,10 +2654,10 @@ caniuse-api@^3.0.0:
     lodash.memoize "^4.1.2"
     lodash.uniq "^4.5.0"
 
-caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001039, caniuse-lite@^1.0.30001043:
-  version "1.0.30001058"
-  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001058.tgz#9f8a318389e28f060272274ac93a661d17f8bf0d"
-  integrity sha512-UiRZmBYd1HdVVdFKy7PuLVx9e2NS7SMyx7QpWvFjiklYrLJKpLd19cRnRNqlw4zYa7vVejS3c8JUVobX241zHQ==
+caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001043, caniuse-lite@^1.0.30001061:
+  version "1.0.30001062"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001062.tgz#d814b648338504b315222ace6f1a533d9a55e390"
+  integrity sha512-ei9ZqeOnN7edDrb24QfJ0OZicpEbsWxv7WusOiQGz/f2SfvBgHHbOEwBJ8HKGVSyx8Z6ndPjxzR6m0NQq+0bfw==
 
 caseless@~0.12.0:
   version "0.12.0"
@@ -2770,7 +2818,7 @@ chokidar@^2.0.4, chokidar@^2.1.8:
   optionalDependencies:
     fsevents "^1.2.7"
 
-chokidar@^3.0.0, chokidar@^3.0.1, chokidar@^3.3.0:
+chokidar@^3.0.0, chokidar@^3.0.1, chokidar@^3.3.0, chokidar@^3.4.0:
   version "3.4.0"
   resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.0.tgz#b30611423ce376357c765b9b8f904b9fba3c0be8"
   integrity sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==
@@ -2853,13 +2901,6 @@ cli-cursor@^3.1.0:
   dependencies:
     restore-cursor "^3.1.0"
 
-cli-table@^0.3.1:
-  version "0.3.1"
-  resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23"
-  integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM=
-  dependencies:
-    colors "1.0.3"
-
 cli-truncate@^0.2.1:
   version "0.2.1"
   resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574"
@@ -3003,11 +3044,6 @@ color@^3.0.0:
     color-convert "^1.9.1"
     color-string "^1.5.2"
 
-colors@1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
-  integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=
-
 colors@^1.1.0, colors@^1.4.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
@@ -3051,9 +3087,9 @@ commonmark@^0.29.0:
     string.prototype.repeat "^0.2.0"
 
 compare-func@^1.3.1, compare-func@^1.3.2:
-  version "1.3.2"
-  resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-1.3.2.tgz#99dd0ba457e1f9bc722b12c08ec33eeab31fa648"
-  integrity sha1-md0LpFfh+bxyKxLAjsM+6rMfpkg=
+  version "1.3.4"
+  resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-1.3.4.tgz#6b07c4c5e8341119baf44578085bda0f4a823516"
+  integrity sha512-sq2sWtrqKPkEXAC8tEJA1+BqAH9GbFkGBtUOqrUX57VSfwp8xyktctk+uLoRy5eccTdxzDcVIztlYDpKs3Jv1Q==
   dependencies:
     array-ify "^1.0.0"
     dot-prop "^3.0.0"
@@ -4138,9 +4174,9 @@ ee-first@1.1.1:
   integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
 
 electron-to-chromium@^1.3.413:
-  version "1.3.437"
-  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.437.tgz#110f1cd407e5d09b43d5585e5f237b71063412cf"
-  integrity sha512-PBQn2q68ErqMyBUABh9Gh8R6DunGky8aB5y3N5lPM7OVpldwyUbAK5AX9WcwE/5F6ceqvQ+iQLYkJYRysAs6Bg==
+  version "1.3.450"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.450.tgz#ce783bbea201902e33d95cb776be6d8f4e9825e5"
+  integrity sha512-m6iTlzM12aBf0W8E+Lhj8tUsO5bsYXzGkQ7x4VEqLLwziFN5uecajjOKJaIR25xrHYwnwHteHy1yzJ+mN6QTWA==
 
 elegant-spinner@^1.0.1:
   version "1.0.1"
@@ -5124,11 +5160,6 @@ gaze@^1.0.0:
   dependencies:
     globule "^1.0.0"
 
-generic-pool@^3.7.1:
-  version "3.7.1"
-  resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.7.1.tgz#36fe5bb83e7e0e032e5d32cd05dc00f5ff119aa8"
-  integrity sha512-ug6DAZoNgWm6q5KhPFA+hzXfBLFQu5sTXxPpv44DmE0A2g+CiHoq9LTVdkXpZMkYVMoGw83F6W+WT0h0MFMK/w==
-
 gensync@^1.0.0-beta.1:
   version "1.0.0-beta.1"
   resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269"
@@ -5149,6 +5180,11 @@ get-own-enumerable-property-symbols@^3.0.0:
   resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
   integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==
 
+get-package-type@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a"
+  integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
+
 get-pkg-repo@^1.0.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-1.4.0.tgz#c73b489c06d80cc5536c2c853f9e05232056972d"
@@ -5886,9 +5922,9 @@ http-errors@1.7.2:
     toidentifier "1.0.0"
 
 http-proxy@^1.13.0, http-proxy@^1.18.0:
-  version "1.18.0"
-  resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a"
-  integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==
+  version "1.18.1"
+  resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549"
+  integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==
   dependencies:
     eventemitter3 "^4.0.0"
     follow-redirects "^1.0.0"
@@ -7104,7 +7140,7 @@ kind-of@^5.0.0:
   resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
   integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
 
-kind-of@^6.0.0, kind-of@^6.0.2:
+kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3:
   version "6.0.3"
   resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
   integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
@@ -8011,13 +8047,14 @@ minimist-options@^3.0.1:
     arrify "^1.0.1"
     is-plain-obj "^1.1.0"
 
-minimist-options@^4.0.1, minimist-options@^4.0.2:
-  version "4.0.2"
-  resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.0.2.tgz#29c4021373ded40d546186725e57761e4b1984a7"
-  integrity sha512-seq4hpWkYSUh1y7NXxzucwAN9yVlBc3Upgdjz8vLCP97jG8kaOmzYrVH/m7tQ1NYD1wdtZbSLfdy4zFmRWuc/w==
+minimist-options@^4.0.2:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619"
+  integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==
   dependencies:
     arrify "^1.0.1"
     is-plain-obj "^1.1.0"
+    kind-of "^6.0.3"
 
 minimist@1.2.0:
   version "1.2.0"
@@ -8140,16 +8177,16 @@ modify-values@^1.0.0:
   integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==
 
 moment-timezone@^0.5.21:
-  version "0.5.28"
-  resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.28.tgz#f093d789d091ed7b055d82aa81a82467f72e4338"
-  integrity sha512-TDJkZvAyKIVWg5EtVqRzU97w0Rb0YVbfpqyjgu6GwXCAohVRqwZjf4fOzDE6p1Ch98Sro/8hQQi65WDXW5STPw==
+  version "0.5.31"
+  resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.31.tgz#9c40d8c5026f0c7ab46eda3d63e49c155148de05"
+  integrity sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==
   dependencies:
     moment ">= 2.9.0"
 
 "moment@>= 2.9.0", moment@^2.10.6, moment@^2.22.2:
-  version "2.25.3"
-  resolved "https://registry.yarnpkg.com/moment/-/moment-2.25.3.tgz#252ff41319cf41e47761a1a88cab30edfe9808c0"
-  integrity sha512-PuYv0PHxZvzc15Sp8ybUCoQ+xpyPWvjOuK72a5ovzp2LI32rJXOiIfyoFoYvG3s6EwwrdkMyWuRiEHSZRLJNdg==
+  version "2.26.0"
+  resolved "https://registry.yarnpkg.com/moment/-/moment-2.26.0.tgz#5e1f82c6bafca6e83e808b30c8705eed0dcbd39a"
+  integrity sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw==
 
 move-concurrently@^1.0.1:
   version "1.0.1"
@@ -8163,21 +8200,6 @@ move-concurrently@^1.0.1:
     rimraf "^2.5.4"
     run-queue "^1.0.3"
 
-mrgit@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/mrgit/-/mrgit-1.0.0.tgz#8904707d6fca656000e64ab4ba12d28c444cbc05"
-  integrity sha512-peAgkA6+U8rgenoq1BBmzxczLs6778rGjU4SZdpm4AA8dXUhDWGC6Q0d3IwzKhdaaDAZ01WF4MPWQGhh9EXnMA==
-  dependencies:
-    chalk "^2.4.2"
-    cli-table "^0.3.1"
-    generic-pool "^3.7.1"
-    meow "^5.0.0"
-    minimatch "^3.0.4"
-    minimist "^1.2.0"
-    minimist-options "^4.0.1"
-    shelljs "^0.8.3"
-    upath "^1.1.2"
-
 ms@2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@@ -8355,9 +8377,9 @@ node-preload@^0.2.1:
     process-on-spawn "^1.0.0"
 
 node-releases@^1.1.53:
-  version "1.1.55"
-  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.55.tgz#8af23b7c561d8e2e6e36a46637bab84633b07cee"
-  integrity sha512-H3R3YR/8TjT5WPin/wOoHOUPHgvj8leuU/Keta/rwelEQN9pA/S2Dx8/se4pZ2LBxSd0nAGzsNzhqwa77v7F1w==
+  version "1.1.56"
+  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.56.tgz#bc054a417d316e3adac90eafb7e1932802f28705"
+  integrity sha512-EVo605FhWLygH8a64TjgpjyHYOihkxECwX1bHHr8tETJKWEiWS2YJjPbvsX2jFjnjTNEgBCmk9mLjKG1Mf11cw==
 
 node-sass-tilde-importer@^1.0.2:
   version "1.0.2"
@@ -9516,11 +9538,11 @@ postcss-sass@^0.4.1:
     postcss "^7.0.21"
 
 postcss-scss@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-2.0.0.tgz#248b0a28af77ea7b32b1011aba0f738bda27dea1"
-  integrity sha512-um9zdGKaDZirMm+kZFKKVsnKPF7zF7qBAtIfTSnZXD1jZ0JNZIxdB6TxQOjCnlSzLRInVl2v3YdBh/M881C4ug==
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-2.1.1.tgz#ec3a75fa29a55e016b90bf3269026c53c1d2b383"
+  integrity sha512-jQmGnj0hSGLd9RscFw9LyuSVAa5Bl1/KBPqG1NQw9w8ND55nY4ZEsdlVuYJvLPpV+y0nwTV5v/4rHPzZRihQbA==
   dependencies:
-    postcss "^7.0.0"
+    postcss "^7.0.6"
 
 postcss-selector-parser@^3.0.0, postcss-selector-parser@^3.1.0:
   version "3.1.2"
@@ -9576,7 +9598,7 @@ postcss-value-parser@^3.0.0, postcss-value-parser@^3.2.3, postcss-value-parser@^
   resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281"
   integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==
 
-postcss-value-parser@^4.0.2, postcss-value-parser@^4.0.3:
+postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb"
   integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==
@@ -9590,7 +9612,7 @@ postcss@^6.0.1, postcss@^6.0.23:
     source-map "^0.6.1"
     supports-color "^5.4.0"
 
-postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.18, postcss@^7.0.2, postcss@^7.0.21, postcss@^7.0.26, postcss@^7.0.27, postcss@^7.0.7:
+postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.18, postcss@^7.0.2, postcss@^7.0.21, postcss@^7.0.26, postcss@^7.0.27, postcss@^7.0.30, postcss@^7.0.6, postcss@^7.0.7:
   version "7.0.30"
   resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.30.tgz#cc9378beffe46a02cbc4506a0477d05fcea9a8e2"
   integrity sha512-nu/0m+NtIzoubO+xdAlwZl/u5S5vi/y6BCsoL8D+8IxsD3XvBS8X4YEADNIVXKVuQvduiucnRv+vPIqj56EGMQ==
@@ -11606,9 +11628,9 @@ terser-webpack-plugin@^2.2.1:
     webpack-sources "^1.4.3"
 
 terser@^4.1.2, terser@^4.6.12:
-  version "4.6.13"
-  resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.13.tgz#e879a7364a5e0db52ba4891ecde007422c56a916"
-  integrity sha512-wMvqukYgVpQlymbnNbabVZbtM6PN63AzqexpwJL8tbh/mRT9LE5o+ruVduAGL7D6Fpjl+Q+06U5I9Ul82odAhw==
+  version "4.7.0"
+  resolved "https://registry.yarnpkg.com/terser/-/terser-4.7.0.tgz#15852cf1a08e3256a80428e865a2fa893ffba006"
+  integrity sha512-Lfb0RiZcjRDXCC3OSHJpEkxJ9Qeqs6mp2v4jf2MHfy8vGERmVDuvjXdd/EnP5Deme5F2yBRBymKmKHCBg2echw==
   dependencies:
     commander "^2.20.0"
     source-map "~0.6.1"
@@ -12187,7 +12209,7 @@ unset-value@^1.0.0:
     has-value "^0.3.1"
     isobject "^3.0.0"
 
-upath@^1.1.1, upath@^1.1.2:
+upath@^1.1.1:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894"
   integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==
@@ -12449,14 +12471,23 @@ warehouse@^2.2.0:
     is-plain-object "^2.0.1"
     lodash "^4.2.1"
 
-watchpack@^1.6.1:
-  version "1.6.1"
-  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.1.tgz#280da0a8718592174010c078c7585a74cd8cd0e2"
-  integrity sha512-+IF9hfUFOrYOOaKyfaI7h7dquUIOgyEMoQMLA7OP5FxegKA2+XdXThAZ9TU2kucfhDH7rfMHs1oPYziVGWRnZA==
+watchpack-chokidar2@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz#9948a1866cbbd6cb824dea13a7ed691f6c8ddff0"
+  integrity sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA==
   dependencies:
     chokidar "^2.1.8"
+
+watchpack@^1.6.1:
+  version "1.7.2"
+  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.2.tgz#c02e4d4d49913c3e7e122c3325365af9d331e9aa"
+  integrity sha512-ymVbbQP40MFTp+cNMvpyBpBtygHnPzPkHqoIwRRj/0B8KhqQwV8LaKjtbaxF2lK4vl8zN9wCxS46IFCU5K4W0g==
+  dependencies:
     graceful-fs "^4.1.2"
     neo-async "^2.5.0"
+  optionalDependencies:
+    chokidar "^3.4.0"
+    watchpack-chokidar2 "^2.0.0"
 
 webpack-cli@^3.3.6:
   version "3.3.11"