diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..0915b6398 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = false + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index c06c48f74..3b962db99 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,7 +1,8 @@ { /** Enable ES6 features */ "parserOptions": { - "ecmaVersion": 6, + "ecmaVersion": 2017, + "sourceType": "module" }, "rules": { @@ -18,7 +19,7 @@ "no-shadow": 2, "no-undef-init": 2, "no-undef": 2, - "no-unused-vars": 1, + "no-unused-vars": 0, /** Style */ "array-bracket-spacing": [2, "never", { @@ -26,7 +27,10 @@ "objectsInArrays": true, "arraysInArrays": true }], - "quotes": [2, "single", "avoid-escape"], + "quotes": [2, "single", { + "avoidEscape": true, + "allowTemplateLiterals": true + }], "eqeqeq": 0, "brace-style": [2, "1tbs"], "comma-spacing": [2, { @@ -38,7 +42,7 @@ "no-nested-ternary": 1, "no-trailing-spaces": 2, "no-mixed-spaces-and-tabs": 2, - "padded-blocks": [2, "always"], + "padded-blocks": [2, "never"], "space-before-blocks": 1, "space-before-function-paren": [1, { "anonymous": "always", @@ -49,7 +53,7 @@ "markers": ["=", "!"] }], "semi": [2, "always"], - "indent": [2, 4, { + "indent": [2, 2, { "SwitchCase": 1 }], "camelcase": [2, { @@ -71,7 +75,14 @@ "FormData": true, "XMLHttpRequest": true, "ActiveXObject": true, - "RegExp": true - + "RegExp": true, + "Module": true, + "Node": true, + "Element": true, + "Proxy": true, + "Symbol": true, + "$": true, + "_": true, + "setTimeout": true } -} \ No newline at end of file +} diff --git a/.gitignore b/.gitignore index 93782c6ff..3c8ec3b7d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,5 @@ Thumbs.db /*.sublime-workspace node_modules/* -/server/ -/uploads/ -plugins/personality/ +npm-debug.log diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..9594c5902 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,21 @@ +[submodule "example/tools/inline-code"] + path = example/tools/inline-code + url = https://github.com/codex-editor/inline-code +[submodule "example/tools/header"] + path = example/tools/header + url = https://github.com/codex-editor/header +[submodule "example/tools/delimiter"] + path = example/tools/delimiter + url = https://github.com/codex-editor/delimiter +[submodule "example/tools/list"] + path = example/tools/list + url = https://github.com/codex-editor/list +[submodule "example/tools/quote"] + path = example/tools/quote + url = https://github.com/codex-editor/quote +[submodule "example/tools/simple-image"] + path = example/tools/simple-image + url = https://github.com/codex-editor/simple-image +[submodule "src/components/tools/paragraph"] + path = src/components/tools/paragraph + url = https://github.com/codex-editor/paragraph diff --git a/.jshintrc b/.jshintrc index 49d68f10b..6cc120829 100644 --- a/.jshintrc +++ b/.jshintrc @@ -12,11 +12,15 @@ // Define globals exposed by CodeX Team "predef": [ - "codex" + "codex", + "_", + "$", + "editorModules", + "Module" ], // Allow ES6. - "esversion": 6, + "esversion": 2017, /* * ENFORCING OPTIONS @@ -61,4 +65,4 @@ // Suppress warnings about == null comparisons. "eqnull": true -} \ No newline at end of file +} diff --git a/.postcssrc b/.postcssrc new file mode 100644 index 000000000..3780c0bce --- /dev/null +++ b/.postcssrc @@ -0,0 +1,16 @@ +plugins: + postcss-smart-import: {} + postcss-custom-properties: {} + postcss-apply: {} + postcss-custom-media: {} + postcss-media-minmax: {} + postcss-custom-selectors: {} + postcss-nested-ancestors: {} + postcss-nesting: {} + postcss-nested: {} + postcss-color-mod-function: {} + postcss-color-hex-alpha: {} + postcss-font-variant: {} + postcss-font-family-system-ui: {} + autoprefixer: + browsers: ['last 2 versions', '> 1%'] diff --git a/.stylelintrc b/.stylelintrc index 57c9fa2a2..23b203aab 100644 --- a/.stylelintrc +++ b/.stylelintrc @@ -1,12 +1,17 @@ { "rules": { - "at-rule-empty-line-before": [ "always", { - except: [ - "blockless-after-same-name-blockless", - "first-nested", - ], - ignore: ["after-comment"], - } ], + "at-rule-empty-line-before": [ + "always", + { + except: [ + "blockless-after-same-name-blockless", + "first-nested", + ], + ignore: [ + "after-comment" + ], + } + ], "at-rule-name-case": "lower", "at-rule-name-space-after": "always-single-line", "at-rule-semicolon-newline-after": "always", @@ -21,27 +26,42 @@ "color-hex-case": "lower", "color-hex-length": "short", "color-no-invalid-hex": true, - "comment-empty-line-before": [ "always", { - except: ["first-nested"], - ignore: ["stylelint-commands"], - } ], + "comment-empty-line-before": [ + "always", + { + except: [ + "first-nested" + ], + ignore: [ + "stylelint-commands" + ], + } + ], "comment-no-empty": true, "comment-whitespace-inside": "always", - "custom-property-empty-line-before": [ "always", { - except: [ - "after-custom-property", - "first-nested", - ], - ignore: [ - "after-comment", - "inside-single-line-block", - ], - } ], + "custom-property-empty-line-before": [ + "always", + { + except: [ + "after-custom-property", + "first-nested", + ], + ignore: [ + "after-comment", + "inside-single-line-block", + ], + } + ], "declaration-bang-space-after": "never", "declaration-bang-space-before": "always", - "declaration-block-no-duplicate-properties": [ true, { - ignore: ["consecutive-duplicates-with-different-values"], - } ], + "declaration-block-no-duplicate-properties": [ + true, + { + ignore: [ + "consecutive-duplicates-with-different-values" + ], + } + ], "declaration-block-no-redundant-longhand-properties": true, "declaration-block-no-shorthand-property-overrides": true, "declaration-block-semicolon-newline-after": "always-multi-line", @@ -52,16 +72,19 @@ "declaration-colon-newline-after": "always-multi-line", "declaration-colon-space-after": "always-single-line", "declaration-colon-space-before": "never", - "declaration-empty-line-before": [ "always", { - except: [ - "after-declaration", - "first-nested", - ], - ignore: [ - "after-comment", - "inside-single-line-block", - ], - } ], + "declaration-empty-line-before": [ + "always", + { + except: [ + "after-declaration", + "first-nested", + ], + ignore: [ + "after-comment", + "inside-single-line-block", + ], + } + ], "font-family-no-duplicate-names": true, "function-calc-no-unspaced-operator": true, "function-comma-newline-after": "always-multi-line", @@ -96,13 +119,17 @@ "number-no-trailing-zeros": true, "property-case": "lower", "property-no-unknown": true, - "rule-nested-empty-line-before": [ "always-multi-line", { - except: ["first-nested"], - ignore: ["after-comment"], - } ], - "rule-non-nested-empty-line-before": [ "always-multi-line", { - ignore: ["after-comment"], - } ], + "rule-empty-line-before": [ + "always-multi-line", + { + except: [ + "first-nested" + ], + ignore: [ + "after-comment" + ], + } + ], "selector-attribute-brackets-space-inside": "never", "selector-attribute-operator-space-after": "never", "selector-attribute-operator-space-before": "never", @@ -129,4 +156,4 @@ "value-list-comma-space-before": "never", "value-list-max-empty-lines": 0, }, -} \ No newline at end of file +} diff --git a/README.md b/README.md index e947177c9..116087dbc 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,222 @@ -### NOTE +
` where line breaks should be handled by default behaviour. |
+| `irreplaceable` | _Boolean_ | `false` | By default, **empty** `Blocks` can be **replaced** by other `Blocks` with the `Toolbox`. Some tools with media-content may prefer another behaviour. Pass `true` and `Toolbox` will add a new block below yours. |
+| `contentless` | _Boolean_ | `false` | Pass `true` for Tool which represents decorative empty `Blocks` |
+| `isInline` | _Boolean_ | `false` | Describes Tool as a [Tool for the Inline Toolbar](tools-inline.md) |
+
+### User configuration
+
+All Tools can be configured by users. You can set up some of available settings along with Tool's class
+to the `tools` property of Editor Config.
+
+```javascript
+var editor = new CodexEditor({
+ holderId : 'codex-editor',
+ tools: {
+ text: {
+ class: Text,
+ inlineToolbar : true,
+ // other settings..
+ },
+ header: Header
+ },
+ initialBlock : 'text',
+});
+```
+
+There are few options available by CodeX Editor.
+
+| Name | Type | Default Value | Description |
+| -- | -- | -- | -- |
+| `inlineToolbar` | _Boolean/Array_ | `false` | Pass `true` to enable the Inline Toolbar with all Tools, or pass an array with specified Tools list |
+| `config` | _Object_ | `null` | User's configuration for Plugin.
+
+### Paste handling
+
+CodeX Editor handles paste on Blocks and provides API for Tools to process the pasted data.
+
+When user pastes content into Editor, pasted content is splitted into blocks.
+
+1. If plain text has been pasted, it is split by new line characters
+2. If HTML string has been pasted, it is split by block tags
+
+Also Editor API allows you to define RegExp patterns to substitute them by your data.
+
+To provide paste handling for your Tool you need to define static getter `onPaste` in Tool class.
+`onPaste` getter should return object with fields described below.
+
+##### HTML tags handling
+
+To handle pasted HTML elements object returned from `onPaste` getter should contain following fields:
+
+| Name | Type | Description |
+| -- | -- | -- |
+| `handler(content: HTMLElement)` | `Function` | _Optional_. Pasted HTML elements handler. Gets one argument `content`. `content` is HTML element extracted from pasted data. Handler should return the same object as Tool's `save` method |
+| `tags` | `String[]` | _Optional_. Should contain all tag names you want to be extracted from pasted data and be passed to your `handler` method |
+
+
+For correct work you MUST provide `onPaste.handler` at least for `initialBlock` Tool.
+
+> Example
+
+Header tool can handle `H1`-`H6` tags using paste handling API
+
+```javascript
+static get onPaste() {
+ return {
+ tags: ['H1', 'H2', 'H3', 'H4', 'H5', 'H6'],
+ handler: (element) => ({
+ type: element.tagName,
+ text: element.innerHTML
+ })
+ }
+}
+```
+
+> One tag can be handled by one Tool only.
+
+##### Patterns handling
+
+Your Tool can analyze text by RegExp patterns to substitute pasted string with data you want. Object returned from `onPaste` getter should contain following fields to use patterns:
+
+| Name | Type | Description |
+| -- | -- | -- |
+| `patterns` | `Object` | _Optional_. `patterns` object contains RegExp patterns with their names as object's keys |
+| `patternHandler(text: string, key: string)` | `Function` | _Optional_. Gets pasted string and pattern name. Should return the same object as Tool `save` method |
+
+**Note** Editor will check pattern's full match, so don't forget to handle all available chars in there.
+
+Pattern will be processed only if paste was on `initialBlock` Tool and pasted string length is less than 450 characters.
+
+> Example
+
+You can handle youtube links and insert embeded video instead:
+
+```javascript
+static get onPaste() {
+ return {
+ patterns: {
+ youtube: /http(?:s?):\/\/(?:www\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-\_]*)(&(amp;)?[\w\?=]*)?/
+ },
+ patternHandler: (text, key) => {
+ const urlData = Youtube.onPaste.patterns[key].exec(text);
+
+ return {
+ iframe: Youtube.makeEmbededFromURL(urlData)
+ };
+ }
+ }
+}
+```
+
+> Both `onPaste.handler` and `onPaste.patternHandler` can be `async` or return a `Promise`.
+
+### Sanitize
diff --git a/docs/usage.md b/docs/usage.md
new file mode 100644
index 000000000..d45a3286e
--- /dev/null
+++ b/docs/usage.md
@@ -0,0 +1,58 @@
+# So how to use CodeX Editor
+
+## Basics
+
+CodeX Editor is a Block-Styled editor. Blocks is a structural units, of which the Entry is composed.
+For example, `Paragraph`, `Heading`, `Image`, `Video`, `List` are Blocks. Each Block is represented by a Plugin.
+We have [many](http://github.com/codex-editor) ready-to-use Plugins and the [simple API](tools.md) for creation new ones.
+
+So how to use the Editor after [Installation](installation.md).
+
+- Create new Blocks by Enter or with the Plus Button
+- Press `TAB` or click on the Plus Button to view the Toolbox
+- Press `TAB` again to leaf Toolbox and select a Block you need. Then press Enter.
+
+
+ ![](https://github.com/codex-editor/list/raw/master/assets/example.gif)
+
+- Select text fragment and apply a style or insert a link from the Inline Toolbar
+
+![](https://capella.pics/7ccbcfcd-1c49-4674-bea7-71021468a1bd.jpg)
+
+- Use «three-dots» button on the right to open Block Settings. From here, you can move and delete a Block
+or apply Tool's settings, if it provided. For example, set a Heading level or List style.
+
+![](https://capella.pics/01a55381-46cd-47c7-b92e-34765434f2ca.jpg)
+
+## Shortcuts
+
+We really appreciate shortcuts. So there are few presets.
+
+Action | Shortcut | Restrictions
+-- | -- | --
+`TAB` | Show/leaf a Toolbox. | On empty block
+`SHIFT+TAB` | Leaf back a Toolbox. | While Toolbox is opened
+`ENTER` | Create a Block | While Toolbox is opened and some Tool is selected
+`CMD+B` | Bold style | On selection
+`CMD+I` | Italic style | On selection
+`CMD+K` | Insert a link | On selection
+
+Also we support shortcuts on the all type of Tools. Specify a shortcut with the Tools configuration. For example:
+
+```js
+var editor = CodexEditor({
+ //...
+ tools: {
+ header: {
+ class: Header,
+ shortcut: 'CMD+SHIFT+H'
+ },
+ list: {
+ class: List,
+ shortcut: 'CMD+SHIFT+L'
+ }
+ }
+ //...
+ });
+
+```
diff --git a/example.html b/example.html
deleted file mode 100644
index 5f4732b31..000000000
--- a/example.html
+++ /dev/null
@@ -1,244 +0,0 @@
-
-
-
-
- CodeX Editor example
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/example/assets/demo.css b/example/assets/demo.css
new file mode 100644
index 000000000..47c4f2fd2
--- /dev/null
+++ b/example/assets/demo.css
@@ -0,0 +1,118 @@
+/**
+ * Styles for the example page
+ */
+body {
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
+ font-size: 14px;
+ line-height: 1.5em;
+ margin: 0;
+}
+
+.ce-example {
+ font-size: 15px;
+}
+
+.ce-example__header {
+ border-bottom: 1px solid #E8E8EB;
+ height: 50px;
+ line-height: 50px;
+ display: flex;
+ padding: 0 30px;
+ margin-bottom: 30px;
+}
+
+.ce-example__header a {
+ color: inherit;
+ text-decoration: none;
+}
+
+.ce-example__header-logo {
+ font-weight: bold;
+}
+
+.ce-example__header-menu {
+ margin-left: auto;
+}
+
+.ce-example__header-menu a {
+ margin-left: 20px;
+}
+
+.ce-example__content {
+ max-width: 1100px;
+ margin: 0 auto;
+}
+
+.ce-example__output {
+ background: #1B202B;
+ overflow-x: auto;
+ padding: 0 30px;
+}
+
+.ce-example__output-content {
+ max-width: 650px;
+ margin: 30px auto;
+ color: #ABADC3;
+ font-family: 'PT Mono', Menlo, Monaco, Consolas, Courier New, monospace;
+ font-size: 13.3px;
+}
+
+.ce-example__output-content:empty {
+ display: none;
+}
+
+.ce-example__button {
+ display: block;
+ margin: 50px auto;
+ max-width: 180px;
+ background: #4A9DF8;
+ padding: 17px 30px;
+ box-shadow: 0 6px 4px -4px rgba(137, 207, 255, 0.77);
+ cursor: pointer;
+ border-radius: 31px;
+ color: #fff;
+ font-family: 'PT Mono', Menlo, Monaco, Consolas, Courier New, monospace;
+ text-align: center;
+}
+
+.ce-example__button:hover {
+ background: #3D8DE5;
+}
+
+.ce-example__output-footer {
+ padding: 30px 0;
+ font-size: 14.2px;
+ letter-spacing: 0.3px;
+ text-align: center;
+}
+
+.ce-example__output-footer a {
+ color: #fff;
+ text-decoration: none;
+}
+
+@media all and (max-width: 680px){
+ .ce-example__header,
+ .ce-example__content{
+ padding: 0 20px;
+ }
+}
+
+/**
+ * JSON highlighter
+ */
+.sc_attr {
+ color: rgb(148, 162, 192);
+}
+.sc_key {
+ color: rgb(190, 213, 255);
+}
+.sc_toolname {
+ color: rgb(15, 205, 251);
+}
+.sc_tag {
+ color: rgb(4, 131, 216);
+}
+.sc_bool {
+ color: rgb(247, 60, 173);
+}
diff --git a/example/assets/json-preview.js b/example/assets/json-preview.js
new file mode 100644
index 000000000..daebdd742
--- /dev/null
+++ b/example/assets/json-preview.js
@@ -0,0 +1,45 @@
+/**
+ * Module to compose output JSON preview
+ */
+const cPreview = (function (module) {
+ /**
+ * Shows JSON in pretty preview
+ * @param {object} output - what to show
+ * @param {Element} holder - where to show
+ */
+ module.show = function(output, holder) {
+ /** Make JSON pretty */
+ output = JSON.stringify( output, null, 4 );
+ /** Encode HTML entities */
+ output = encodeHTMLEntities( output );
+ /** Stylize! */
+ output = stylize( output );
+ holder.innerHTML = output;
+ };
+
+ /**
+ * Converts '>', '<', '&' symbols to entities
+ */
+ function encodeHTMLEntities(string) {
+ return string.replace(/&/g, '&').replace(//g, '>');
+ }
+
+ /**
+ * Some styling magic
+ */
+ function stylize(string) {
+ /** Stylize JSON keys */
+ string = string.replace( /"(\w+)"\s?:/g, '"$1" :');
+ /** Stylize tool names */
+ string = string.replace( /"(text|quote|list|header|link|code|image|delimiter)"/g, '"$1"');
+ /** Stylize HTML tags */
+ string = string.replace( /(<[\/a-z]+(>)?)/gi, '$1' );
+ /** Stylize strings */
+ string = string.replace( /"([^"]+)"/gi, '"$1"' );
+ /** Boolean/Null */
+ string = string.replace( /\b(true|false|null)\b/gi, '$1' );
+ return string;
+ }
+
+ return module;
+})({});
diff --git a/example/example.html b/example/example.html
new file mode 100644
index 000000000..4883d07b0
--- /dev/null
+++ b/example/example.html
@@ -0,0 +1,231 @@
+
+
+
+
+ CodeX Editor 🤩🧦🤨 example
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/tools/delimiter b/example/tools/delimiter
new file mode 160000
index 000000000..489b87499
--- /dev/null
+++ b/example/tools/delimiter
@@ -0,0 +1 @@
+Subproject commit 489b87499ad9c60100e3dd0d832c78e3127536a5
diff --git a/example/tools/header b/example/tools/header
new file mode 160000
index 000000000..92e5373cf
--- /dev/null
+++ b/example/tools/header
@@ -0,0 +1 @@
+Subproject commit 92e5373cf8826492a96b6ca5070552ddf6aa749d
diff --git a/example/tools/inline-code b/example/tools/inline-code
new file mode 160000
index 000000000..286b1e1a0
--- /dev/null
+++ b/example/tools/inline-code
@@ -0,0 +1 @@
+Subproject commit 286b1e1a0d37e17175ebc28b00f8d4e1c68497a9
diff --git a/example/tools/list b/example/tools/list
new file mode 160000
index 000000000..7c5fb17b1
--- /dev/null
+++ b/example/tools/list
@@ -0,0 +1 @@
+Subproject commit 7c5fb17b11056171d121b7ce040b86b091b483bc
diff --git a/example/tools/paragraph b/example/tools/paragraph
new file mode 160000
index 000000000..67af23696
--- /dev/null
+++ b/example/tools/paragraph
@@ -0,0 +1 @@
+Subproject commit 67af23696c591b6dc922b3c6c1b43070293281ea
diff --git a/example/tools/quote b/example/tools/quote
new file mode 160000
index 000000000..293149cac
--- /dev/null
+++ b/example/tools/quote
@@ -0,0 +1 @@
+Subproject commit 293149cac0f352fc4debdd62558ca14e0448889a
diff --git a/example/tools/simple-image b/example/tools/simple-image
new file mode 160000
index 000000000..b3ba0e5de
--- /dev/null
+++ b/example/tools/simple-image
@@ -0,0 +1 @@
+Subproject commit b3ba0e5de15bed3d4354b4bf23f63158bd4167dd
diff --git a/fonts/codex_editor/codex-editor.eot b/fonts/codex_editor/codex-editor.eot
deleted file mode 100755
index 723ad6ab4..000000000
Binary files a/fonts/codex_editor/codex-editor.eot and /dev/null differ
diff --git a/fonts/codex_editor/codex-editor.svg b/fonts/codex_editor/codex-editor.svg
deleted file mode 100755
index 1ae6cabcc..000000000
--- a/fonts/codex_editor/codex-editor.svg
+++ /dev/null
@@ -1,72 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/fonts/codex_editor/codex-editor.ttf b/fonts/codex_editor/codex-editor.ttf
deleted file mode 100755
index e6c702655..000000000
Binary files a/fonts/codex_editor/codex-editor.ttf and /dev/null differ
diff --git a/fonts/codex_editor/codex-editor.woff b/fonts/codex_editor/codex-editor.woff
deleted file mode 100755
index 5ad5eaa51..000000000
Binary files a/fonts/codex_editor/codex-editor.woff and /dev/null differ
diff --git a/fonts/codex_editor/codex-editor.woff2 b/fonts/codex_editor/codex-editor.woff2
deleted file mode 100755
index 15066535f..000000000
Binary files a/fonts/codex_editor/codex-editor.woff2 and /dev/null differ
diff --git a/fonts/codex_editor/icon-hash.svg b/fonts/codex_editor/icon-hash.svg
deleted file mode 100644
index 60790072d..000000000
--- a/fonts/codex_editor/icon-hash.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
\ No newline at end of file
diff --git a/fonts/codex_editor/icon-plus.svg b/fonts/codex_editor/icon-plus.svg
deleted file mode 100644
index fdc0776c5..000000000
--- a/fonts/codex_editor/icon-plus.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
\ No newline at end of file
diff --git a/icons.css b/icons.css
deleted file mode 100644
index b8914486e..000000000
--- a/icons.css
+++ /dev/null
@@ -1,63 +0,0 @@
-@font-face {
- font-family: 'codex_editor';
- src: url('fonts/codex_editor/codex-editor.eot?20895205');
- src: url('fonts/codex_editor/codex-editor.eot?20895205#iefix') format('embedded-opentype'),
- url('fonts/codex_editor/codex-editor.woff?20895205') format('woff'),
- url('fonts/codex_editor/codex-editor.ttf?20895205') format('truetype'),
- url('fonts/codex_editor/codex-editor.svg?20895205#codex_editor') format('svg');
- font-weight: normal;
- font-style: normal;
-}
-[class^="ce-icon-"]:before,
-[class*="ce-icon-"]:before {
- font-family: "codex_editor";
- font-style: normal;
- font-weight: normal;
- speak: none;
-
- display: inline-block;
- text-decoration: inherit;
- width: 1em;
- margin-right: .2em;
- text-align: center;
- font-variant: normal;
- text-transform: none;
-
- line-height: 1em;
-
- /* Animation center compensation - margins should be symmetric */
- margin-left: .2em;
-
- -moz-osx-font-smoothing: grayscale;
-}
-.ce-icon-instagram:before { content: '\e800'; } /* '' */
-.ce-icon-picture:before { content: '\e801'; } /* '' */
-.ce-icon-cog:before { content: '\e802'; } /* '' */
-.ce-icon-link:before { content: '\e803'; } /* '' */
-.ce-icon-unlink:before { content: '\e804'; } /* '' */
-.ce-icon-code:before { content: '\e805'; } /* '' */
-.ce-icon-quote:before { content: '\e806'; } /* '' */
-.ce-icon-trash:before { content: '\e807'; } /* '' */
-.ce-icon-down-big:before { content: '\e808'; } /* '' */
-.ce-icon-up-big:before { content: '\e809'; } /* '' */
-.ce-icon-header:before { content: '\e80a'; } /* '' */
-.ce-icon-paragraph:before { content: '\e80b'; } /* '' */
-.ce-icon-align-left:before { content: '\e80c'; } /* '' */
-.ce-icon-align-center:before { content: '\e80d'; } /* '' */
-.ce-icon-align-right:before { content: '\e80e'; } /* '' */
-.ce-icon-font:before { content: '\e80f'; } /* '' */
-.ce-icon-bold:before { content: '\e810'; } /* '' */
-.ce-icon-medium:before { content: '\e811'; } /* '' */
-.ce-icon-italic:before { content: '\e812'; } /* '' */
-.ce-icon-list-bullet:before { content: '\e813'; } /* '' */
-.ce-icon-list-numbered:before { content: '\e814'; } /* '' */
-.ce-icon-strike:before { content: '\e815'; } /* '' */
-.ce-icon-underline:before { content: '\e816'; } /* '' */
-.ce-icon-table:before { content: '\e817'; } /* '' */
-.ce-icon-ellipsis-vert:before { content: '\e818'; } /* '' */
-.ce-icon-columns:before { content: '\e819'; } /* '' */
-.ce-icon-smile:before { content: '\e81a'; } /* '' */
-.ce-icon-newspaper:before { content: '\e81b'; } /* '' */
-.ce-icon-twitter:before { content: '\e81c'; } /* '' */
-.ce-icon-facebook-squared:before { content: '\e81d'; } /* '' */
-.ce-icon-vkontakte:before { content: '\e81e'; } /* '' */
diff --git a/modules/anchors.js b/modules/anchors.js
deleted file mode 100644
index d72deaa4a..000000000
--- a/modules/anchors.js
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
- * Codex Editor Anchors module
- *
- * @author Codex Team
- * @version 1.0
- */
-
-module.exports = function (anchors) {
-
- let editor = codex.editor;
-
- anchors.input = null;
- anchors.currentNode = null;
-
- anchors.settingsOpened = function (currentBlock) {
-
- anchors.currentNode = currentBlock;
- anchors.input.value = anchors.currentNode.dataset.anchor || '';
-
- };
-
- anchors.anchorChanged = function (e) {
-
- var newAnchor = e.target.value = anchors.rusToTranslit(e.target.value);
-
- anchors.currentNode.dataset.anchor = newAnchor;
-
- if (newAnchor.trim() !== '') {
-
- anchors.currentNode.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);
-
- } else {
-
- anchors.currentNode.classList.remove(editor.ui.className.BLOCK_WITH_ANCHOR);
-
- }
-
- };
-
- anchors.keyDownOnAnchorInput = function (e) {
-
- if (e.keyCode == editor.core.keys.ENTER) {
-
- e.preventDefault();
- e.stopPropagation();
-
- e.target.blur();
- editor.toolbar.settings.close();
-
- }
-
- };
-
- anchors.keyUpOnAnchorInput = function (e) {
-
- if (e.keyCode >= editor.core.keys.LEFT && e.keyCode <= editor.core.keys.DOWN) {
-
- e.stopPropagation();
-
- }
-
- };
-
- anchors.rusToTranslit = function (string) {
-
- var ru = [
- 'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й',
- 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф',
- 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ь', 'Ы', 'Ь', 'Э', 'Ю', 'Я'
- ],
- en = [
- 'A', 'B', 'V', 'G', 'D', 'E', 'E', 'Zh', 'Z', 'I', 'Y',
- 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'F',
- 'H', 'C', 'Ch', 'Sh', 'Sch', '', 'Y', '', 'E', 'Yu', 'Ya'
- ];
-
- for (var i = 0; i < ru.length; i++) {
-
- string = string.split(ru[i]).join(en[i]);
- string = string.split(ru[i].toLowerCase()).join(en[i].toLowerCase());
-
- }
-
- string = string.replace(/[^0-9a-zA-Z_]+/g, '-');
-
- return string;
-
- };
-
- return anchors;
-
-}({});
\ No newline at end of file
diff --git a/modules/callbacks.js b/modules/callbacks.js
deleted file mode 100644
index 443759ba4..000000000
--- a/modules/callbacks.js
+++ /dev/null
@@ -1,911 +0,0 @@
-/**
- * @module Codex Editor Callbacks module
- * @description Module works with editor added Elements
- *
- * @author Codex Team
- * @version 1.4.0
- */
-
-module.exports = (function (callbacks) {
-
- let editor = codex.editor;
-
- /**
- * used by UI module
- * @description Routes all keydowns on document
- * @param {Object} event
- */
- callbacks.globalKeydown = function (event) {
-
- switch (event.keyCode) {
- case editor.core.keys.ENTER : enterKeyPressed_(event); break;
- }
-
- };
-
- /**
- * used by UI module
- * @description Routes all keydowns on redactors area
- * @param {Object} event
- */
- callbacks.redactorKeyDown = function (event) {
-
- switch (event.keyCode) {
- case editor.core.keys.TAB : tabKeyPressedOnRedactorsZone_(event); break;
- case editor.core.keys.ENTER : enterKeyPressedOnRedactorsZone_(event); break;
- case editor.core.keys.ESC : escapeKeyPressedOnRedactorsZone_(event); break;
- default : defaultKeyPressedOnRedactorsZone_(event); break;
- }
-
- };
-
- /**
- * used by UI module
- * @description Routes all keyup events
- * @param {Object} event
- */
- callbacks.globalKeyup = function (event) {
-
- switch (event.keyCode) {
- case editor.core.keys.UP :
- case editor.core.keys.LEFT :
- case editor.core.keys.RIGHT :
- case editor.core.keys.DOWN : arrowKeyPressed_(event); break;
- }
-
- };
-
- /**
- * @param {Object} event
- * @private
- *
- * Handles behaviour when tab pressed
- * @description if Content is empty show toolbox (if it is closed) or leaf tools
- * uses Toolbars toolbox module to handle the situation
- */
- var tabKeyPressedOnRedactorsZone_ = function (event) {
-
- /**
- * Wait for solution. Would like to know the behaviour
- * @todo Add spaces
- */
- event.preventDefault();
-
-
- if (!editor.core.isBlockEmpty(editor.content.currentNode)) {
-
- return;
-
- }
-
- if ( !editor.toolbar.opened ) {
-
- editor.toolbar.open();
-
- }
-
- if (editor.toolbar.opened && !editor.toolbar.toolbox.opened) {
-
- editor.toolbar.toolbox.open();
-
- } else {
-
- editor.toolbar.toolbox.leaf();
-
- }
-
- };
-
- /**
- * Handles global EnterKey Press
- * @see enterPressedOnBlock_
- * @param {Object} event
- */
- var enterKeyPressed_ = function () {
-
- if (editor.content.editorAreaHightlighted) {
-
- /**
- * it means that we lose input index, saved index before is not correct
- * therefore we need to set caret when we insert new block
- */
- editor.caret.inputIndex = -1;
-
- enterPressedOnBlock_();
-
- }
-
- };
-
- /**
- * Callback for enter key pressing in first-level block area
- *
- * @param {Event} event
- * @private
- *
- * @description Inserts new block with initial type from settings
- */
- var enterPressedOnBlock_ = function () {
-
- var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;
-
- editor.content.insertBlock({
- type : NEW_BLOCK_TYPE,
- block : editor.tools[NEW_BLOCK_TYPE].render()
- }, true );
-
- editor.toolbar.move();
- editor.toolbar.open();
-
- };
-
-
- /**
- * ENTER key handler
- *
- * @param {Object} event
- * @private
- *
- * @description Makes new block with initial type from settings
- */
- var enterKeyPressedOnRedactorsZone_ = function (event) {
-
- if (event.target.contentEditable == 'true') {
-
- /** Update input index */
- editor.caret.saveCurrentInputIndex();
-
- }
-
- var currentInputIndex = editor.caret.getCurrentInputIndex() || 0,
- workingNode = editor.content.currentNode,
- tool = workingNode.dataset.tool,
- isEnterPressedOnToolbar = editor.toolbar.opened &&
- editor.toolbar.current &&
- event.target == editor.state.inputs[currentInputIndex];
-
- /** The list of tools which needs the default browser behaviour */
- var enableLineBreaks = editor.tools[tool].enableLineBreaks;
-
- /** This type of block creates when enter is pressed */
- var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;
-
- /**
- * When toolbar is opened, select tool instead of making new paragraph
- */
- if ( isEnterPressedOnToolbar ) {
-
- event.preventDefault();
-
- editor.toolbar.toolbox.toolClicked(event);
-
- editor.toolbar.close();
-
- /**
- * Stop other listeners callback executions
- */
- event.stopPropagation();
- event.stopImmediatePropagation();
-
- return;
-
- }
-
- /**
- * Allow paragraph lineBreaks with shift enter
- * Or if shiftkey pressed and enter and enabledLineBreaks, the let new block creation
- */
- if ( event.shiftKey || enableLineBreaks ) {
-
- event.stopPropagation();
- event.stopImmediatePropagation();
- return;
-
- }
-
- var currentSelection = window.getSelection(),
- currentSelectedNode = currentSelection.anchorNode,
- caretAtTheEndOfText = editor.caret.position.atTheEnd(),
- isTextNodeHasParentBetweenContenteditable = false;
-
- /**
- * Allow making new in same block by SHIFT+ENTER and forbids to prevent default browser behaviour
- */
- if ( event.shiftKey && !enableLineBreaks ) {
-
- editor.callback.enterPressedOnBlock(editor.content.currentBlock, event);
- event.preventDefault();
- return;
-
- }
-
- /**
- * Workaround situation when caret at the Text node that has some wrapper Elements
- * Split block cant handle this.
- * We need to save default behavior
- */
- isTextNodeHasParentBetweenContenteditable = currentSelectedNode && currentSelectedNode.parentNode.contentEditable != 'true';
-
- /**
- * Split blocks when input has several nodes and caret placed in textNode
- */
- if (
- currentSelectedNode.nodeType == editor.core.nodeTypes.TEXT &&
- !isTextNodeHasParentBetweenContenteditable &&
- !caretAtTheEndOfText
- ) {
-
- event.preventDefault();
-
- editor.core.log('Splitting Text node...');
-
- editor.content.splitBlock(currentInputIndex);
-
- /** Show plus button when next input after split is empty*/
- if (!editor.state.inputs[currentInputIndex + 1].textContent.trim()) {
-
- editor.toolbar.showPlusButton();
-
- }
-
- } else {
-
- var islastNode = editor.content.isLastNode(currentSelectedNode);
-
- if ( islastNode && caretAtTheEndOfText ) {
-
- event.preventDefault();
- event.stopPropagation();
- event.stopImmediatePropagation();
-
- editor.core.log('ENTER clicked in last textNode. Create new BLOCK');
-
- editor.content.insertBlock({
- type: NEW_BLOCK_TYPE,
- block: editor.tools[NEW_BLOCK_TYPE].render()
- }, true);
-
- editor.toolbar.move();
- editor.toolbar.open();
-
- /** Show plus button with empty block */
- editor.toolbar.showPlusButton();
-
- }
-
- }
-
- /** get all inputs after new appending block */
- editor.ui.saveInputs();
-
- };
-
- /**
- * Escape behaviour
- * @param event
- * @private
- *
- * @description Closes toolbox and toolbar. Prevents default behaviour
- */
- var escapeKeyPressedOnRedactorsZone_ = function (event) {
-
- /** Close all toolbar */
- editor.toolbar.close();
-
- /** Close toolbox */
- editor.toolbar.toolbox.close();
-
- event.preventDefault();
-
- };
-
- /**
- * @param {Event} event
- * @private
- *
- * closes and moves toolbar
- */
- var arrowKeyPressed_ = function (event) {
-
- editor.content.workingNodeChanged();
-
- /* Closing toolbar */
- editor.toolbar.close();
- editor.toolbar.move();
-
- };
-
- /**
- * @private
- * @param {Event} event
- *
- * @description Closes all opened bars from toolbar.
- * If block is mark, clears highlightning
- */
- var defaultKeyPressedOnRedactorsZone_ = function () {
-
- editor.toolbar.close();
-
- if (!editor.toolbar.inline.actionsOpened) {
-
- editor.toolbar.inline.close();
- editor.content.clearMark();
-
- }
-
- };
-
- /**
- * Handler when clicked on redactors area
- *
- * @protected
- * @param event
- *
- * @description Detects clicked area. If it is first-level block area, marks as detected and
- * on next enter press will be inserted new block
- * Otherwise, save carets position (input index) and put caret to the editable zone.
- *
- * @see detectWhenClickedOnFirstLevelBlockArea_
- *
- */
- callbacks.redactorClicked = function (event) {
-
- detectWhenClickedOnFirstLevelBlockArea_();
-
- editor.content.workingNodeChanged(event.target);
- editor.ui.saveInputs();
-
- var selectedText = editor.toolbar.inline.getSelectionText(),
- firstLevelBlock;
-
- /** If selection range took off, then we hide inline toolbar */
- if (selectedText.length === 0) {
-
- editor.toolbar.inline.close();
-
- }
-
- /** Update current input index in memory when caret focused into existed input */
- if (event.target.contentEditable == 'true') {
-
- editor.caret.saveCurrentInputIndex();
-
- }
-
- if (editor.content.currentNode === null) {
-
- /**
- * If inputs in redactor does not exits, then we put input index 0 not -1
- */
- var indexOfLastInput = editor.state.inputs.length > 0 ? editor.state.inputs.length - 1 : 0;
-
- /** If we have any inputs */
- if (editor.state.inputs.length) {
-
- /** getting firstlevel parent of input */
- firstLevelBlock = editor.content.getFirstLevelBlock(editor.state.inputs[indexOfLastInput]);
-
- }
-
- /** If input is empty, then we set caret to the last input */
- if (editor.state.inputs.length && editor.state.inputs[indexOfLastInput].textContent === '' && firstLevelBlock.dataset.tool == editor.settings.initialBlockPlugin) {
-
- editor.caret.setToBlock(indexOfLastInput);
-
- } else {
-
- /** Create new input when caret clicked in redactors area */
- var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;
-
- editor.content.insertBlock({
- type : NEW_BLOCK_TYPE,
- block : editor.tools[NEW_BLOCK_TYPE].render()
- });
-
- /** If there is no inputs except inserted */
- if (editor.state.inputs.length === 1) {
-
- editor.caret.setToBlock(indexOfLastInput);
-
- } else {
-
- /** Set caret to this appended input */
- editor.caret.setToNextBlock(indexOfLastInput);
-
- }
-
- }
-
- } else {
-
- /** Close all panels */
- editor.toolbar.settings.close();
- editor.toolbar.toolbox.close();
-
- }
-
- /**
- * Move toolbar and open
- */
- editor.toolbar.move();
- editor.toolbar.open();
-
- var inputIsEmpty = !editor.content.currentNode.textContent.trim(),
- currentNodeType = editor.content.currentNode.dataset.tool,
- isInitialType = currentNodeType == editor.settings.initialBlockPlugin;
-
-
- /** Hide plus buttons */
- editor.toolbar.hidePlusButton();
-
- if (!inputIsEmpty) {
-
- /** Mark current block */
- editor.content.markBlock();
-
- }
-
- if ( isInitialType && inputIsEmpty ) {
-
- /** Show plus button */
- editor.toolbar.showPlusButton();
-
- }
-
-
- };
-
- /**
- * This method allows to define, is caret in contenteditable element or not.
- *
- * @private
- *
- * @description Otherwise, if we get TEXT node from range container, that will means we have input index.
- * In this case we use default browsers behaviour (if plugin allows that) or overwritten action.
- * Therefore, to be sure that we've clicked first-level block area, we should have currentNode, which always
- * specifies to the first-level block. Other cases we just ignore.
- */
- var detectWhenClickedOnFirstLevelBlockArea_ = function () {
-
- var selection = window.getSelection(),
- anchorNode = selection.anchorNode,
- flag = false;
-
- if (selection.rangeCount === 0) {
-
- editor.content.editorAreaHightlighted = true;
-
- } else {
-
- if (!editor.core.isDomNode(anchorNode)) {
-
- anchorNode = anchorNode.parentNode;
-
- }
-
- /** Already founded, without loop */
- if (anchorNode.contentEditable == 'true') {
-
- flag = true;
-
- }
-
- while (anchorNode.contentEditable != 'true') {
-
- anchorNode = anchorNode.parentNode;
-
- if (anchorNode.contentEditable == 'true') {
-
- flag = true;
-
- }
-
- if (anchorNode == document.body) {
-
- break;
-
- }
-
- }
-
- /** If editable element founded, flag is "TRUE", Therefore we return "FALSE" */
- editor.content.editorAreaHightlighted = !flag;
-
- }
-
- };
-
- /**
- * Toolbar button click handler
- *
- * @param {Object} event - cursor to the button
- * @protected
- *
- * @description gets current tool and calls render method
- */
- callbacks.toolbarButtonClicked = function (event) {
-
- var button = this;
-
- editor.toolbar.current = button.dataset.type;
-
- editor.toolbar.toolbox.toolClicked(event);
- editor.toolbar.close();
-
- };
-
- /**
- * Show or Hide toolbox when plus button is clicked
- */
- callbacks.plusButtonClicked = function () {
-
- if (!editor.nodes.toolbox.classList.contains('opened')) {
-
- editor.toolbar.toolbox.open();
-
- } else {
-
- editor.toolbar.toolbox.close();
-
- }
-
- };
-
- /**
- * Block handlers for KeyDown events
- *
- * @protected
- * @param {Object} event
- *
- * Handles keydowns on block
- * @see blockRightOrDownArrowPressed_
- * @see backspacePressed_
- * @see blockLeftOrUpArrowPressed_
- */
- callbacks.blockKeydown = function (event) {
-
- let block = event.target; // event.target is input
-
- switch (event.keyCode) {
-
- case editor.core.keys.DOWN:
- case editor.core.keys.RIGHT:
- blockRightOrDownArrowPressed_(event);
- break;
-
- case editor.core.keys.BACKSPACE:
- backspacePressed_(block, event);
- break;
-
- case editor.core.keys.UP:
- case editor.core.keys.LEFT:
- blockLeftOrUpArrowPressed_(event);
- break;
-
- }
-
- };
-
- /**
- * RIGHT or DOWN keydowns on block
- *
- * @param {Object} event
- * @private
- *
- * @description watches the selection and gets closest editable element.
- * Uses method getDeepestTextNodeFromPosition to get the last node of next block
- * Sets caret if it is contenteditable
- */
- var blockRightOrDownArrowPressed_ = function (event) {
-
- var selection = window.getSelection(),
- inputs = editor.state.inputs,
- focusedNode = selection.anchorNode,
- focusedNodeHolder;
-
- /** Check for caret existance */
- if (!focusedNode) {
-
- return false;
-
- }
-
- /** Looking for closest (parent) contentEditable element of focused node */
- while (focusedNode.contentEditable != 'true') {
-
- focusedNodeHolder = focusedNode.parentNode;
- focusedNode = focusedNodeHolder;
-
- }
-
- /** Input index in DOM level */
- var editableElementIndex = 0;
-
- while (focusedNode != inputs[editableElementIndex]) {
-
- editableElementIndex ++;
-
- }
-
- /**
- * Founded contentEditable element doesn't have childs
- * Or maybe New created block
- */
- if (!focusedNode.textContent) {
-
- editor.caret.setToNextBlock(editableElementIndex);
- return;
-
- }
-
- /**
- * Do nothing when caret doesn not reaches the end of last child
- */
- var caretInLastChild = false,
- caretAtTheEndOfText = false;
-
- var lastChild,
- deepestTextnode;
-
- lastChild = focusedNode.childNodes[focusedNode.childNodes.length - 1 ];
-
- if (editor.core.isDomNode(lastChild)) {
-
- deepestTextnode = editor.content.getDeepestTextNodeFromPosition(lastChild, lastChild.childNodes.length);
-
- } else {
-
- deepestTextnode = lastChild;
-
- }
-
- caretInLastChild = selection.anchorNode == deepestTextnode;
- caretAtTheEndOfText = deepestTextnode.length == selection.anchorOffset;
-
- if ( !caretInLastChild || !caretAtTheEndOfText ) {
-
- editor.core.log('arrow [down|right] : caret does not reached the end');
- return false;
-
- }
-
- editor.caret.setToNextBlock(editableElementIndex);
-
- };
-
- /**
- * LEFT or UP keydowns on block
- *
- * @param {Object} event
- * @private
- *
- * watches the selection and gets closest editable element.
- * Uses method getDeepestTextNodeFromPosition to get the last node of previous block
- * Sets caret if it is contenteditable
- *
- */
- var blockLeftOrUpArrowPressed_ = function (event) {
-
- var selection = window.getSelection(),
- inputs = editor.state.inputs,
- focusedNode = selection.anchorNode,
- focusedNodeHolder;
-
- /** Check for caret existance */
- if (!focusedNode) {
-
- return false;
-
- }
-
- /**
- * LEFT or UP not at the beginning
- */
- if ( selection.anchorOffset !== 0) {
-
- return false;
-
- }
-
- /** Looking for parent contentEditable block */
- while (focusedNode.contentEditable != 'true') {
-
- focusedNodeHolder = focusedNode.parentNode;
- focusedNode = focusedNodeHolder;
-
- }
-
- /** Input index in DOM level */
- var editableElementIndex = 0;
-
- while (focusedNode != inputs[editableElementIndex]) {
-
- editableElementIndex ++;
-
- }
-
- /**
- * Do nothing if caret is not at the beginning of first child
- */
- var caretInFirstChild = false,
- caretAtTheBeginning = false;
-
- var firstChild,
- deepestTextnode;
-
- /**
- * Founded contentEditable element doesn't have childs
- * Or maybe New created block
- */
- if (!focusedNode.textContent) {
-
- editor.caret.setToPreviousBlock(editableElementIndex);
- return;
-
- }
-
- firstChild = focusedNode.childNodes[0];
-
- if (editor.core.isDomNode(firstChild)) {
-
- deepestTextnode = editor.content.getDeepestTextNodeFromPosition(firstChild, 0);
-
- } else {
-
- deepestTextnode = firstChild;
-
- }
-
- caretInFirstChild = selection.anchorNode == deepestTextnode;
- caretAtTheBeginning = selection.anchorOffset === 0;
-
- if ( caretInFirstChild && caretAtTheBeginning ) {
-
- editor.caret.setToPreviousBlock(editableElementIndex);
-
- }
-
- };
-
- /**
- * Handles backspace keydown
- *
- * @param {Element} block
- * @param {Object} event
- * @private
- *
- * @description if block is empty, delete the block and set caret to the previous block
- * If block is not empty, try to merge two blocks - current and previous
- * But it we try'n to remove first block, then we should set caret to the next block, not previous.
- * If we removed the last block, create new one
- */
- var backspacePressed_ = function (block, event) {
-
- var currentInputIndex = editor.caret.getCurrentInputIndex(),
- range,
- selectionLength,
- firstLevelBlocksCount;
-
- if (editor.core.isNativeInput(event.target)) {
-
- /** If input value is empty - remove block */
- if (event.target.value.trim() == '') {
-
- block.remove();
-
- } else {
-
- return;
-
- }
-
- }
-
- if (block.textContent.trim()) {
-
- range = editor.content.getRange();
- selectionLength = range.endOffset - range.startOffset;
-
- if (editor.caret.position.atStart() && !selectionLength && editor.state.inputs[currentInputIndex - 1]) {
-
- editor.content.mergeBlocks(currentInputIndex);
-
- } else {
-
- return;
-
- }
-
- }
-
- if (!selectionLength) {
-
- block.remove();
-
- }
-
-
- firstLevelBlocksCount = editor.nodes.redactor.childNodes.length;
-
- /**
- * If all blocks are removed
- */
- if (firstLevelBlocksCount === 0) {
-
- /** update currentNode variable */
- editor.content.currentNode = null;
-
- /** Inserting new empty initial block */
- editor.ui.addInitialBlock();
-
- /** Updating inputs state after deleting last block */
- editor.ui.saveInputs();
-
- /** Set to current appended block */
- window.setTimeout(function () {
-
- editor.caret.setToPreviousBlock(1);
-
- }, 10);
-
- } else {
-
- if (editor.caret.inputIndex !== 0) {
-
- /** Target block is not first */
- editor.caret.setToPreviousBlock(editor.caret.inputIndex);
-
- } else {
-
- /** If we try to delete first block */
- editor.caret.setToNextBlock(editor.caret.inputIndex);
-
- }
-
- }
-
- editor.toolbar.move();
-
- if (!editor.toolbar.opened) {
-
- editor.toolbar.open();
-
- }
-
- /** Updating inputs state */
- editor.ui.saveInputs();
-
- /** Prevent default browser behaviour */
- event.preventDefault();
-
- };
-
- /**
- * used by UI module
- * Clicks on block settings button
- *
- * @param {Object} event
- * @protected
- * @description Opens toolbar settings
- */
- callbacks.showSettingsButtonClicked = function (event) {
-
- /**
- * Get type of current block
- * It uses to append settings from tool.settings property.
- * ...
- * Type is stored in data-type attribute on block
- */
- var currentToolType = editor.content.currentNode.dataset.tool;
-
- editor.toolbar.settings.toggle(currentToolType);
-
- /** Close toolbox when settings button is active */
- editor.toolbar.toolbox.close();
- editor.toolbar.settings.hideRemoveActions();
-
- };
-
- return callbacks;
-
-})({});
\ No newline at end of file
diff --git a/modules/caret.js b/modules/caret.js
deleted file mode 100644
index 21b7599c6..000000000
--- a/modules/caret.js
+++ /dev/null
@@ -1,305 +0,0 @@
-/**
- * Codex Editor Caret Module
- *
- * @author Codex Team
- * @version 1.0
- */
-
-module.exports = (function (caret) {
-
- let editor = codex.editor;
-
- /**
- * @var {int} InputIndex - editable element in DOM
- */
- caret.inputIndex = null;
-
- /**
- * @var {int} offset - caret position in a text node.
- */
- caret.offset = null;
-
- /**
- * @var {int} focusedNodeIndex - we get index of child node from first-level block
- */
- caret.focusedNodeIndex = null;
-
- /**
- * Creates Document Range and sets caret to the element.
- * @protected
- * @uses caret.save — if you need to save caret position
- * @param {Element} el - Changed Node.
- */
- caret.set = function ( el, index, offset) {
-
- offset = offset || caret.offset || 0;
- index = index || caret.focusedNodeIndex || 0;
-
- var childs = el.childNodes,
- nodeToSet;
-
- if ( childs.length === 0 ) {
-
- nodeToSet = el;
-
- } else {
-
- nodeToSet = childs[index];
-
- }
-
- /** If Element is INPUT */
- if (el.contentEditable != 'true') {
-
- el.focus();
- return;
-
- }
-
- if (editor.core.isDomNode(nodeToSet)) {
-
- nodeToSet = editor.content.getDeepestTextNodeFromPosition(nodeToSet, nodeToSet.childNodes.length);
-
- }
-
- var range = document.createRange(),
- selection = window.getSelection();
-
- window.setTimeout(function () {
-
- range.setStart(nodeToSet, offset);
- range.setEnd(nodeToSet, offset);
-
- selection.removeAllRanges();
- selection.addRange(range);
-
- editor.caret.saveCurrentInputIndex();
-
- }, 20);
-
- };
-
- /**
- * @protected
- * Updates index of input and saves it in caret object
- */
- caret.saveCurrentInputIndex = function () {
-
- /** Index of Input that we paste sanitized content */
- var selection = window.getSelection(),
- inputs = editor.state.inputs,
- focusedNode = selection.anchorNode,
- focusedNodeHolder;
-
- if (!focusedNode) {
-
- return;
-
- }
-
- /** Looking for parent contentEditable block */
- while (focusedNode && focusedNode.contentEditable != 'true') {
-
- focusedNodeHolder = focusedNode.parentNode;
- focusedNode = focusedNodeHolder;
-
- }
-
- /** Input index in DOM level */
- var editableElementIndex = 0;
-
- while (focusedNode != inputs[editableElementIndex]) {
-
- editableElementIndex ++;
-
- }
-
- caret.inputIndex = editableElementIndex;
-
- };
-
- /**
- * Returns current input index (caret object)
- */
- caret.getCurrentInputIndex = function () {
-
- return caret.inputIndex;
-
- };
-
- /**
- * @param {int} index - index of first-level block after that we set caret into next input
- */
- caret.setToNextBlock = function (index) {
-
- var inputs = editor.state.inputs,
- nextInput = inputs[index + 1];
-
- if (!nextInput) {
-
- editor.core.log('We are reached the end');
- return;
-
- }
-
- /**
- * When new Block created or deleted content of input
- * We should add some text node to set caret
- */
- if (!nextInput.childNodes.length) {
-
- var emptyTextElement = document.createTextNode('');
-
- nextInput.appendChild(emptyTextElement);
-
- }
-
- editor.caret.inputIndex = index + 1;
- editor.caret.set(nextInput, 0, 0);
- editor.content.workingNodeChanged(nextInput);
-
- };
-
- /**
- * @param {int} index - index of target input.
- * Sets caret to input with this index
- */
- caret.setToBlock = function (index) {
-
- var inputs = editor.state.inputs,
- targetInput = inputs[index];
-
- if ( !targetInput ) {
-
- return;
-
- }
-
- /**
- * When new Block created or deleted content of input
- * We should add some text node to set caret
- */
- if (!targetInput.childNodes.length) {
-
- var emptyTextElement = document.createTextNode('');
-
- targetInput.appendChild(emptyTextElement);
-
- }
-
- editor.caret.inputIndex = index;
- editor.caret.set(targetInput, 0, 0);
- editor.content.workingNodeChanged(targetInput);
-
- };
-
- /**
- * @param {int} index - index of input
- */
- caret.setToPreviousBlock = function (index) {
-
- index = index || 0;
-
- var inputs = editor.state.inputs,
- previousInput = inputs[index - 1],
- lastChildNode,
- lengthOfLastChildNode,
- emptyTextElement;
-
-
- if (!previousInput) {
-
- editor.core.log('We are reached first node');
- return;
-
- }
-
- lastChildNode = editor.content.getDeepestTextNodeFromPosition(previousInput, previousInput.childNodes.length);
- lengthOfLastChildNode = lastChildNode.length;
-
- /**
- * When new Block created or deleted content of input
- * We should add some text node to set caret
- */
- if (!previousInput.childNodes.length) {
-
- emptyTextElement = document.createTextNode('');
- previousInput.appendChild(emptyTextElement);
-
- }
- editor.caret.inputIndex = index - 1;
- editor.caret.set(previousInput, previousInput.childNodes.length - 1, lengthOfLastChildNode);
- editor.content.workingNodeChanged(inputs[index - 1]);
-
- };
-
- caret.position = {
-
- atStart : function () {
-
- var selection = window.getSelection(),
- anchorOffset = selection.anchorOffset,
- anchorNode = selection.anchorNode,
- firstLevelBlock = editor.content.getFirstLevelBlock(anchorNode),
- pluginsRender = firstLevelBlock.childNodes[0];
-
- if (!editor.core.isDomNode(anchorNode)) {
-
- anchorNode = anchorNode.parentNode;
-
- }
-
- var isFirstNode = anchorNode === pluginsRender.childNodes[0],
- isOffsetZero = anchorOffset === 0;
-
- return isFirstNode && isOffsetZero;
-
- },
-
- atTheEnd : function () {
-
- var selection = window.getSelection(),
- anchorOffset = selection.anchorOffset,
- anchorNode = selection.anchorNode;
-
- /** Caret is at the end of input */
- return !anchorNode || !anchorNode.length || anchorOffset === anchorNode.length;
-
- }
- };
-
-
- /**
- * Inserts node at the caret location
- * @param {HTMLElement|DocumentFragment} node
- */
- caret.insertNode = function (node) {
-
- var selection, range,
- lastNode = node;
-
- if (node.nodeType == editor.core.nodeTypes.DOCUMENT_FRAGMENT) {
-
- lastNode = node.lastChild;
-
- }
-
- selection = window.getSelection();
-
- range = selection.getRangeAt(0);
- range.deleteContents();
-
- range.insertNode(node);
-
- range.setStartAfter(lastNode);
- range.collapse(true);
-
- selection.removeAllRanges();
- selection.addRange(range);
-
-
- };
-
- return caret;
-
-})({});
diff --git a/modules/content.js b/modules/content.js
deleted file mode 100644
index 1ed1a634d..000000000
--- a/modules/content.js
+++ /dev/null
@@ -1,805 +0,0 @@
-/**
- * Codex Editor Content Module
- * Works with DOM
- *
- * @module Codex Editor content module
- *
- * @author Codex Team
- * @version 1.3.13
- *
- * @description Module works with Elements that have been appended to the main DOM
- */
-
-module.exports = (function (content) {
-
- let editor = codex.editor;
-
- /**
- * Links to current active block
- * @type {null | Element}
- */
- content.currentNode = null;
-
- /**
- * clicked in redactor area
- * @type {null | Boolean}
- */
- content.editorAreaHightlighted = null;
-
- /**
- * @deprecated
- * Synchronizes redactor with original textarea
- */
- content.sync = function () {
-
- editor.core.log('syncing...');
-
- /**
- * Save redactor content to editor.state
- */
- editor.state.html = editor.nodes.redactor.innerHTML;
-
- };
-
- /**
- * Appends background to the block
- *
- * @description add CSS class to highlight visually first-level block area
- */
- content.markBlock = function () {
-
- editor.content.currentNode.classList.add(editor.ui.className.BLOCK_HIGHLIGHTED);
-
- };
-
- /**
- * Clear background
- *
- * @description clears styles that highlights block
- */
- content.clearMark = function () {
-
- if (editor.content.currentNode) {
-
- editor.content.currentNode.classList.remove(editor.ui.className.BLOCK_HIGHLIGHTED);
-
- }
-
- };
-
- /**
- * Finds first-level block
- *
- * @param {Element} node - selected or clicked in redactors area node
- * @protected
- *
- * @description looks for first-level block.
- * gets parent while node is not first-level
- */
- content.getFirstLevelBlock = function (node) {
-
- if (!editor.core.isDomNode(node)) {
-
- node = node.parentNode;
-
- }
-
- if (node === editor.nodes.redactor || node === document.body) {
-
- return null;
-
- } else {
-
- while(!node.classList.contains(editor.ui.className.BLOCK_CLASSNAME)) {
-
- node = node.parentNode;
-
- }
-
- return node;
-
- }
-
- };
-
- /**
- * Trigger this event when working node changed
- * @param {Element} targetNode - first-level of this node will be current
- * @protected
- *
- * @description If targetNode is first-level then we set it as current else we look for parents to find first-level
- */
- content.workingNodeChanged = function (targetNode) {
-
- /** Clear background from previous marked block before we change */
- editor.content.clearMark();
-
- if (!targetNode) {
-
- return;
-
- }
-
- content.currentNode = content.getFirstLevelBlock(targetNode);
-
- };
-
- /**
- * Replaces one redactor block with another
- * @protected
- * @param {Element} targetBlock - block to replace. Mostly currentNode.
- * @param {Element} newBlock
- * @param {string} newBlockType - type of new block; we need to store it to data-attribute
- *
- * [!] Function does not saves old block content.
- * You can get it manually and pass with newBlock.innerHTML
- */
- content.replaceBlock = function (targetBlock, newBlock) {
-
- if (!targetBlock || !newBlock) {
-
- editor.core.log('replaceBlock: missed params');
- return;
-
- }
-
- /** If target-block is not a frist-level block, then we iterate parents to find it */
- while(!targetBlock.classList.contains(editor.ui.className.BLOCK_CLASSNAME)) {
-
- targetBlock = targetBlock.parentNode;
-
- }
-
- /** Replacing */
- editor.nodes.redactor.replaceChild(newBlock, targetBlock);
-
- /**
- * Set new node as current
- */
- editor.content.workingNodeChanged(newBlock);
-
- /**
- * Add block handlers
- */
- editor.ui.addBlockHandlers(newBlock);
-
- /**
- * Save changes
- */
- editor.ui.saveInputs();
-
- };
-
- /**
- * @protected
- *
- * Inserts new block to redactor
- * Wrapps block into a DIV with BLOCK_CLASSNAME class
- *
- * @param blockData {object}
- * @param blockData.block {Element} element with block content
- * @param blockData.type {string} block plugin
- * @param needPlaceCaret {bool} pass true to set caret in new block
- *
- */
- content.insertBlock = function ( blockData, needPlaceCaret ) {
-
- var workingBlock = editor.content.currentNode,
- newBlockContent = blockData.block,
- blockType = blockData.type,
- isStretched = blockData.stretched;
-
- var newBlock = composeNewBlock_(newBlockContent, blockType, isStretched);
-
- if (workingBlock) {
-
- editor.core.insertAfter(workingBlock, newBlock);
-
- } else {
-
- /**
- * If redactor is empty, append as first child
- */
- editor.nodes.redactor.appendChild(newBlock);
-
- }
-
- /**
- * Block handler
- */
- editor.ui.addBlockHandlers(newBlock);
-
- /**
- * Set new node as current
- */
- editor.content.workingNodeChanged(newBlock);
-
- /**
- * Save changes
- */
- editor.ui.saveInputs();
-
-
- if ( needPlaceCaret ) {
-
- /**
- * If we don't know input index then we set default value -1
- */
- var currentInputIndex = editor.caret.getCurrentInputIndex() || -1;
-
-
- if (currentInputIndex == -1) {
-
-
- var editableElement = newBlock.querySelector('[contenteditable]'),
- emptyText = document.createTextNode('');
-
- editableElement.appendChild(emptyText);
- editor.caret.set(editableElement, 0, 0);
-
- editor.toolbar.move();
- editor.toolbar.showPlusButton();
-
-
- } else {
-
- if (currentInputIndex === editor.state.inputs.length - 1)
- return;
-
- /** Timeout for browsers execution */
- window.setTimeout(function () {
-
- /** Setting to the new input */
- editor.caret.setToNextBlock(currentInputIndex);
- editor.toolbar.move();
- editor.toolbar.open();
-
- }, 10);
-
- }
-
- }
-
- /**
- * Block is inserted, wait for new click that defined focusing on editors area
- * @type {boolean}
- */
- content.editorAreaHightlighted = false;
-
- };
-
- /**
- * Replaces blocks with saving content
- * @protected
- * @param {Element} noteToReplace
- * @param {Element} newNode
- * @param {Element} blockType
- */
- content.switchBlock = function (blockToReplace, newBlock, tool) {
-
- tool = tool || editor.content.currentNode.dataset.tool;
- var newBlockComposed = composeNewBlock_(newBlock, tool);
-
- /** Replacing */
- editor.content.replaceBlock(blockToReplace, newBlockComposed);
-
- /** Save new Inputs when block is changed */
- editor.ui.saveInputs();
-
- };
-
- /**
- * Iterates between child noted and looking for #text node on deepest level
- * @protected
- *
- * @param {Element} block - node where find
- * @param {int} postiton - starting postion
- * Example: childNodex.length to find from the end
- * or 0 to find from the start
- * @return {Text} block
- * @uses DFS
- */
- content.getDeepestTextNodeFromPosition = function (block, position) {
-
- /**
- * Clear Block from empty and useless spaces with trim.
- * Such nodes we should remove
- */
- var blockChilds = block.childNodes,
- index,
- node,
- text;
-
- for(index = 0; index < blockChilds.length; index++) {
-
- node = blockChilds[index];
-
- if (node.nodeType == editor.core.nodeTypes.TEXT) {
-
- text = node.textContent.trim();
-
- /** Text is empty. We should remove this child from node before we start DFS
- * decrease the quantity of childs.
- */
- if (text === '') {
-
- block.removeChild(node);
- position--;
-
- }
-
- }
-
- }
-
- if (block.childNodes.length === 0) {
-
- return document.createTextNode('');
-
- }
-
- /** Setting default position when we deleted all empty nodes */
- if ( position < 0 )
- position = 1;
-
- var lookingFromStart = false;
-
- /** For looking from START */
- if (position === 0) {
-
- lookingFromStart = true;
- position = 1;
-
- }
-
- while ( position ) {
-
- /** initial verticle of node. */
- if ( lookingFromStart ) {
-
- block = block.childNodes[0];
-
- } else {
-
- block = block.childNodes[position - 1];
-
- }
-
- if ( block.nodeType == editor.core.nodeTypes.TAG ) {
-
- position = block.childNodes.length;
-
- } else if (block.nodeType == editor.core.nodeTypes.TEXT ) {
-
- position = 0;
-
- }
-
- }
-
- return block;
-
- };
-
- /**
- * @private
- * @param {Element} block - current plugins render
- * @param {String} tool - plugins name
- * @param {Boolean} isStretched - make stretched block or not
- *
- * @description adds necessary information to wrap new created block by first-level holder
- */
- var composeNewBlock_ = function (block, tool, isStretched) {
-
- var newBlock = editor.draw.node('DIV', editor.ui.className.BLOCK_CLASSNAME, {}),
- blockContent = editor.draw.node('DIV', editor.ui.className.BLOCK_CONTENT, {});
-
- blockContent.appendChild(block);
- newBlock.appendChild(blockContent);
-
- if (isStretched) {
-
- blockContent.classList.add(editor.ui.className.BLOCK_STRETCHED);
-
- }
-
- newBlock.dataset.tool = tool;
- return newBlock;
-
- };
-
- /**
- * Returns Range object of current selection
- * @protected
- */
- content.getRange = function () {
-
- var selection = window.getSelection().getRangeAt(0);
-
- return selection;
-
- };
-
- /**
- * Divides block in two blocks (after and before caret)
- *
- * @protected
- * @param {int} inputIndex - target input index
- *
- * @description splits current input content to the separate blocks
- * When enter is pressed among the words, that text will be splited.
- */
- content.splitBlock = function (inputIndex) {
-
- var selection = window.getSelection(),
- anchorNode = selection.anchorNode,
- anchorNodeText = anchorNode.textContent,
- caretOffset = selection.anchorOffset,
- textBeforeCaret,
- textNodeBeforeCaret,
- textAfterCaret,
- textNodeAfterCaret;
-
- var currentBlock = editor.content.currentNode.querySelector('[contentEditable]');
-
-
- textBeforeCaret = anchorNodeText.substring(0, caretOffset);
- textAfterCaret = anchorNodeText.substring(caretOffset);
-
- textNodeBeforeCaret = document.createTextNode(textBeforeCaret);
-
- if (textAfterCaret) {
-
- textNodeAfterCaret = document.createTextNode(textAfterCaret);
-
- }
-
- var previousChilds = [],
- nextChilds = [],
- reachedCurrent = false;
-
- if (textNodeAfterCaret) {
-
- nextChilds.push(textNodeAfterCaret);
-
- }
-
- for ( var i = 0, child; !!(child = currentBlock.childNodes[i]); i++) {
-
- if ( child != anchorNode ) {
-
- if ( !reachedCurrent ) {
-
- previousChilds.push(child);
-
- } else {
-
- nextChilds.push(child);
-
- }
-
- } else {
-
- reachedCurrent = true;
-
- }
-
- }
-
- /** Clear current input */
- editor.state.inputs[inputIndex].innerHTML = '';
-
- /**
- * Append all childs founded before anchorNode
- */
- var previousChildsLength = previousChilds.length;
-
- for(i = 0; i < previousChildsLength; i++) {
-
- editor.state.inputs[inputIndex].appendChild(previousChilds[i]);
-
- }
-
- editor.state.inputs[inputIndex].appendChild(textNodeBeforeCaret);
-
- /**
- * Append text node which is after caret
- */
- var nextChildsLength = nextChilds.length,
- newNode = document.createElement('div');
-
- for(i = 0; i < nextChildsLength; i++) {
-
- newNode.appendChild(nextChilds[i]);
-
- }
-
- newNode = newNode.innerHTML;
-
- /** This type of block creates when enter is pressed */
- var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;
-
- /**
- * Make new paragraph with text after caret
- */
- editor.content.insertBlock({
- type : NEW_BLOCK_TYPE,
- block : editor.tools[NEW_BLOCK_TYPE].render({
- text : newNode
- })
- }, true );
-
- };
-
- /**
- * Merges two blocks — current and target
- * If target index is not exist, then previous will be as target
- *
- * @protected
- * @param {int} currentInputIndex
- * @param {int} targetInputIndex
- *
- * @description gets two inputs indexes and merges into one
- */
- content.mergeBlocks = function (currentInputIndex, targetInputIndex) {
-
- /** If current input index is zero, then prevent method execution */
- if (currentInputIndex === 0) {
-
- return;
-
- }
-
- var targetInput,
- currentInputContent = editor.state.inputs[currentInputIndex].innerHTML;
-
- if (!targetInputIndex) {
-
- targetInput = editor.state.inputs[currentInputIndex - 1];
-
- } else {
-
- targetInput = editor.state.inputs[targetInputIndex];
-
- }
-
- targetInput.innerHTML += currentInputContent;
-
- };
-
- /**
- * Iterates all right siblings and parents, which has right siblings
- * while it does not reached the first-level block
- *
- * @param {Element} node
- * @return {boolean}
- */
- content.isLastNode = function (node) {
-
- // console.log('погнали перебор родителей');
-
- var allChecked = false;
-
- while ( !allChecked ) {
-
- // console.log('Смотрим на %o', node);
- // console.log('Проверим, пустые ли соседи справа');
-
- if ( !allSiblingsEmpty_(node) ) {
-
- // console.log('Есть непустые соседи. Узел не последний. Выходим.');
- return false;
-
- }
-
- node = node.parentNode;
-
- /**
- * Проверяем родителей до тех пор, пока не найдем блок первого уровня
- */
- if ( node.classList.contains(editor.ui.className.BLOCK_CONTENT) ) {
-
- allChecked = true;
-
- }
-
- }
-
- return true;
-
- };
-
- /**
- * Checks if all element right siblings is empty
- * @param node
- */
- var allSiblingsEmpty_ = function (node) {
-
- /**
- * Нужно убедиться, что после пустого соседа ничего нет
- */
- var sibling = node.nextSibling;
-
- while ( sibling ) {
-
- if (sibling.textContent.length) {
-
- return false;
-
- }
-
- sibling = sibling.nextSibling;
-
- }
-
- return true;
-
- };
-
- /**
- * @public
- *
- * @param {string} htmlData - html content as string
- * @param {string} plainData - plain text
- * @return {string} - html content as string
- */
- content.wrapTextWithParagraphs = function (htmlData, plainData) {
-
- if (!htmlData.trim()) {
-
- return wrapPlainTextWithParagraphs(plainData);
-
- }
-
- var wrapper = document.createElement('DIV'),
- newWrapper = document.createElement('DIV'),
- i,
- paragraph,
- firstLevelBlocks = ['DIV', 'P'],
- blockTyped,
- node;
-
- /**
- * Make HTML Element to Wrap Text
- * It allows us to work with input data as HTML content
- */
- wrapper.innerHTML = htmlData;
- paragraph = document.createElement('P');
-
- for (i = 0; i < wrapper.childNodes.length; i++) {
-
- node = wrapper.childNodes[i];
-
- blockTyped = firstLevelBlocks.indexOf(node.tagName) != -1;
-
- /**
- * If node is first-levet
- * we add this node to our new wrapper
- */
- if ( blockTyped ) {
-
- /**
- * If we had splitted inline nodes to paragraph before
- */
- if ( paragraph.childNodes.length ) {
-
- newWrapper.appendChild(paragraph.cloneNode(true));
-
- /** empty paragraph */
- paragraph = null;
- paragraph = document.createElement('P');
-
- }
-
- newWrapper.appendChild(node.cloneNode(true));
-
- } else {
-
- /** Collect all inline nodes to one as paragraph */
- paragraph.appendChild(node.cloneNode(true));
-
- /** if node is last we should append this node to paragraph and paragraph to new wrapper */
- if ( i == wrapper.childNodes.length - 1 ) {
-
- newWrapper.appendChild(paragraph.cloneNode(true));
-
- }
-
- }
-
- }
-
- return newWrapper.innerHTML;
-
- };
-
- /**
- * Splits strings on new line and wraps paragraphs with
tag
- * @param plainText
- * @returns {string}
- */
- var wrapPlainTextWithParagraphs = function (plainText) {
-
- if (!plainText) return '';
-
- return '
' + plainText.split('\n\n').join('
') + '
';
-
- };
-
- /**
- * Finds closest Contenteditable parent from Element
- * @param {Element} node element looking from
- * @return {Element} node contenteditable
- */
- content.getEditableParent = function (node) {
-
- while (node && node.contentEditable != 'true') {
-
- node = node.parentNode;
-
- }
-
- return node;
-
- };
-
- /**
- * Clear editors content
- *
- * @param {Boolean} all — if true, delete all article data (content, id, etc.)
- */
- content.clear = function (all) {
-
- editor.nodes.redactor.innerHTML = '';
- editor.content.sync();
- editor.ui.saveInputs();
- if (all) {
-
- editor.state.blocks = {};
-
- } else if (editor.state.blocks) {
-
- editor.state.blocks.items = [];
-
- }
-
- editor.content.currentNode = null;
-
- };
-
- /**
- *
- * Load new data to editor
- * If editor is not empty, just append articleData.items
- *
- * @param articleData.items
- */
- content.load = function (articleData) {
-
- var currentContent = Object.assign({}, editor.state.blocks);
-
- editor.content.clear();
-
- if (!Object.keys(currentContent).length) {
-
- editor.state.blocks = articleData;
-
- } else if (!currentContent.items) {
-
- currentContent.items = articleData.items;
- editor.state.blocks = currentContent;
-
- } else {
-
- currentContent.items = currentContent.items.concat(articleData.items);
- editor.state.blocks = currentContent;
-
- }
-
- editor.renderer.makeBlocksFromData();
-
- };
-
- return content;
-
-})({});
\ No newline at end of file
diff --git a/modules/core.js b/modules/core.js
deleted file mode 100644
index ad4a08b8b..000000000
--- a/modules/core.js
+++ /dev/null
@@ -1,389 +0,0 @@
-/**
- * Codex Editor Core
- *
- * @author Codex Team
- * @version 1.1.3
- */
-
-module.exports = (function (core) {
-
- let editor = codex.editor;
-
- /**
- * @public
- *
- * Editor preparing method
- * @return Promise
- */
- core.prepare = function (userSettings) {
-
- return new Promise(function (resolve, reject) {
-
- if ( userSettings ) {
-
- editor.settings.tools = userSettings.tools || editor.settings.tools;
-
- }
-
- if (userSettings.data) {
-
- editor.state.blocks = userSettings.data;
-
- }
-
- if (userSettings.initialBlockPlugin) {
-
- editor.settings.initialBlockPlugin = userSettings.initialBlockPlugin;
-
- }
-
- if (userSettings.sanitizer) {
-
- editor.settings.sanitizer = userSettings.sanitizer;
-
- }
-
- editor.hideToolbar = userSettings.hideToolbar;
-
- editor.settings.placeholder = userSettings.placeholder || '';
-
- editor.nodes.holder = document.getElementById(userSettings.holderId || editor.settings.holderId);
-
- if (typeof editor.nodes.holder === undefined || editor.nodes.holder === null) {
-
- reject(Error("Holder wasn't found by ID: #" + userSettings.holderId));
-
- } else {
-
- resolve();
-
- }
-
- });
-
- };
-
- /**
- * Logging method
- * @param type = ['log', 'info', 'warn']
- */
- core.log = function (msg, type, arg) {
-
- type = type || 'log';
-
- if (!arg) {
-
- arg = msg || 'undefined';
- msg = '[codex-editor]: %o';
-
- } else {
-
- msg = '[codex-editor]: ' + msg;
-
- }
-
- try{
-
- if ( 'console' in window && window.console[ type ] ) {
-
- if ( arg ) window.console[ type ]( msg, arg );
- else window.console[ type ]( msg );
-
- }
-
- }catch(e) {}
-
- };
-
- /**
- * @protected
- *
- * Helper for insert one element after another
- */
- core.insertAfter = function (target, element) {
-
- target.parentNode.insertBefore(element, target.nextSibling);
-
- };
-
- /**
- * @const
- *
- * Readable DOM-node types map
- */
- core.nodeTypes = {
- TAG : 1,
- TEXT : 3,
- COMMENT : 8,
- DOCUMENT_FRAGMENT: 11
- };
-
- /**
- * @const
- * Readable keys map
- */
- core.keys = { BACKSPACE: 8, TAB: 9, ENTER: 13, SHIFT: 16, CTRL: 17, ALT: 18, ESC: 27, SPACE: 32, LEFT: 37, UP: 38, DOWN: 40, RIGHT: 39, DELETE: 46, META: 91 };
-
- /**
- * @protected
- *
- * Check object for DOM node
- */
- core.isDomNode = function (el) {
-
- return el && typeof el === 'object' && el.nodeType && el.nodeType == this.nodeTypes.TAG;
-
- };
-
- /**
- * Checks passed object for emptiness
- * @require ES5 - Object.keys
- * @param {object}
- */
- core.isEmpty = function ( obj ) {
-
- return Object.keys(obj).length === 0;
-
- };
-
- /**
- * Native Ajax
- * @param {String} settings.url - request URL
- * @param {function} settings.beforeSend - returned value will be passed as context to the Success, Error and Progress callbacks
- * @param {function} settings.success
- * @param {function} settings.progress
- */
- core.ajax = function (settings) {
-
- if (!settings || !settings.url) {
-
- return;
-
- }
-
- var XMLHTTP = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'),
- encodedString,
- isFormData,
- prop;
-
-
- settings.async = true;
- settings.type = settings.type || 'GET';
- settings.data = settings.data || '';
- settings['content-type'] = settings['content-type'] || 'application/json; charset=utf-8';
-
- if (settings.type == 'GET' && settings.data) {
-
- settings.url = /\?/.test(settings.url) ? settings.url + '&' + settings.data : settings.url + '?' + settings.data;
-
- } else {
-
- encodedString = '';
- for(prop in settings.data) {
-
- encodedString += (prop + '=' + encodeURIComponent(settings.data[prop]) + '&');
-
- }
-
- }
-
- if (settings.withCredentials) {
-
- XMLHTTP.withCredentials = true;
-
- }
-
- /**
- * Value returned in beforeSend funtion will be passed as context to the other response callbacks
- * If beforeSend returns false, AJAX will be blocked
- */
- let responseContext,
- beforeSendResult;
-
- if (typeof settings.beforeSend === 'function') {
-
- beforeSendResult = settings.beforeSend.call();
-
- if (beforeSendResult === false) {
-
- return;
-
- }
-
- }
-
- XMLHTTP.open( settings.type, settings.url, settings.async );
-
- /**
- * If we send FormData, we need no content-type header
- */
- isFormData = isFormData_(settings.data);
-
- if (!isFormData) {
-
- if (settings.type !== 'POST') {
-
- XMLHTTP.setRequestHeader('Content-type', settings['content-type']);
-
- } else {
-
- XMLHTTP.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
-
- }
-
- }
-
- XMLHTTP.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
-
- responseContext = beforeSendResult || XMLHTTP;
-
- if (typeof settings.progress === 'function') {
-
- XMLHTTP.upload.onprogress = settings.progress.bind(responseContext);
-
- }
-
- XMLHTTP.onreadystatechange = function () {
-
- if (XMLHTTP.readyState === 4) {
-
- if (XMLHTTP.status === 200) {
-
- if (typeof settings.success === 'function') {
-
- settings.success.call(responseContext, XMLHTTP.responseText);
-
- }
-
- } else {
-
- if (typeof settings.error === 'function') {
-
- settings.error.call(responseContext, XMLHTTP.responseText, XMLHTTP.status);
-
- }
-
- }
-
- }
-
- };
-
- if (isFormData) {
-
- // Sending FormData
- XMLHTTP.send(settings.data);
-
- } else {
-
- // POST requests
- XMLHTTP.send(encodedString);
-
- }
-
- return XMLHTTP;
-
- };
-
- /**
- * Appends script to head of document
- * @return Promise
- */
- core.importScript = function (scriptPath, instanceName) {
-
- return new Promise(function (resolve, reject) {
-
- let script;
-
- /** Script is already loaded */
- if ( !instanceName ) {
-
- reject('Instance name is missed');
-
- } else if ( document.getElementById(editor.scriptPrefix + instanceName) ) {
-
- resolve(scriptPath);
-
- }
-
- script = document.createElement('SCRIPT');
- script.async = true;
- script.defer = true;
- script.id = editor.scriptPrefix + instanceName;
-
- script.onload = function () {
-
- resolve(scriptPath);
-
- };
-
- script.onerror = function () {
-
- reject(scriptPath);
-
- };
-
- script.src = scriptPath;
- document.head.appendChild(script);
-
- });
-
- };
-
- /**
- * Function for checking is it FormData object to send.
- * @param {Object} object to check
- * @return boolean
- */
- var isFormData_ = function (object) {
-
- return object instanceof FormData;
-
- };
-
- /**
- * Check block
- * @param target
- * @description Checks target is it native input
- */
- core.isNativeInput = function (target) {
-
- var nativeInputAreas = ['INPUT', 'TEXTAREA'];
-
- return nativeInputAreas.indexOf(target.tagName) != -1;
-
- };
-
- /**
- * Check if block is empty
- * We should check block textContent, child native inputs and some exceptions like IMG and IFRAME
- *
- * @param block
- * @returns {boolean}
- */
- core.isBlockEmpty = function (block) {
-
- const EXCEPTION_TAGS = ['IMG', 'IFRAME'];
-
- var nativeInputs = block.querySelectorAll('textarea, input'),
- nativeInputsAreEmpty = true,
- textContentIsEmpty = !block.textContent.trim();
-
- Array.prototype.forEach.call(nativeInputs, function (input) {
-
- if (input.type == 'textarea' || input.type == 'text') {
-
- nativeInputsAreEmpty = nativeInputsAreEmpty && !input.value.trim();
-
- }
-
- });
-
- return textContentIsEmpty && nativeInputsAreEmpty && !EXCEPTION_TAGS.includes(block.tagName);
-
- };
-
-
- return core;
-
-})({});
diff --git a/modules/destroyer.js b/modules/destroyer.js
deleted file mode 100644
index 989f94780..000000000
--- a/modules/destroyer.js
+++ /dev/null
@@ -1,98 +0,0 @@
-/**
- * Codex Editor Destroyer module
- *
- * @auhor Codex Team
- * @version 1.0
- */
-
-module.exports = function (destroyer) {
-
- let editor = codex.editor;
-
- destroyer.removeNodes = function () {
-
- editor.nodes.wrapper.remove();
- editor.nodes.notifications.remove();
-
- };
-
- destroyer.destroyPlugins = function () {
-
- for (var tool in editor.tools) {
-
- if (typeof editor.tools[tool].destroy === 'function') {
-
- editor.tools[tool].destroy();
-
- }
-
- }
-
- };
-
- destroyer.destroyScripts = function () {
-
- var scripts = document.getElementsByTagName('SCRIPT');
-
- for (var i = 0; i < scripts.length; i++) {
-
- if (scripts[i].id.indexOf(editor.scriptPrefix) + 1) {
-
- scripts[i].remove();
- i--;
-
- }
-
- }
-
- };
-
-
- /**
- * Delete editor data from webpage.
- * You should send settings argument with boolean flags:
- * @param settings.ui- remove redactor event listeners and DOM nodes
- * @param settings.scripts - remove redactor scripts from DOM
- * @param settings.plugins - remove plugin's objects
- * @param settings.core - remove editor core. You can remove core only if UI and scripts flags is true
- * }
- *
- */
- destroyer.destroy = function (settings) {
-
- if (!settings || typeof settings !== 'object') {
-
- return;
-
- }
-
- if (settings.ui) {
-
- destroyer.removeNodes();
- editor.listeners.removeAll();
-
- }
-
- if (settings.scripts) {
-
- destroyer.destroyScripts();
-
- }
-
- if (settings.plugins) {
-
- destroyer.destroyPlugins();
-
- }
-
- if (settings.ui && settings.scripts && settings.core) {
-
- delete codex.editor;
-
- }
-
- };
-
- return destroyer;
-
-}({});
\ No newline at end of file
diff --git a/modules/draw.js b/modules/draw.js
deleted file mode 100644
index 9c0d87cd2..000000000
--- a/modules/draw.js
+++ /dev/null
@@ -1,316 +0,0 @@
-/**
- * Codex Editor Draw module
- *
- * @author Codex Team
- * @version 1.0.
- */
-
-module.exports = (function (draw) {
-
- /**
- * Base editor wrapper
- */
- draw.wrapper = function () {
-
- var wrapper = document.createElement('div');
-
- wrapper.className += 'codex-editor';
-
- return wrapper;
-
- };
-
- /**
- * Content-editable holder
- */
- draw.redactor = function () {
-
- var redactor = document.createElement('div');
-
- redactor.className += 'ce-redactor';
-
- return redactor;
-
- };
-
- draw.ceBlock = function () {
-
- var block = document.createElement('DIV');
-
- block.className += 'ce_block';
-
- return block;
-
- };
-
- /**
- * Empty toolbar with toggler
- */
- draw.toolbar = function () {
-
- var bar = document.createElement('div');
-
- bar.className += 'ce-toolbar';
-
- return bar;
-
- };
-
- draw.toolbarContent = function () {
-
- var wrapper = document.createElement('DIV');
-
- wrapper.classList.add('ce-toolbar__content');
-
- return wrapper;
-
- };
-
- /**
- * Inline toolbar
- */
- draw.inlineToolbar = function () {
-
- var bar = document.createElement('DIV');
-
- bar.className += 'ce-toolbar-inline';
-
- return bar;
-
- };
-
- /**
- * Wrapper for inline toobar buttons
- */
- draw.inlineToolbarButtons = function () {
-
- var wrapper = document.createElement('DIV');
-
- wrapper.className += 'ce-toolbar-inline__buttons';
-
- return wrapper;
-
- };
-
- /**
- * For some actions
- */
- draw.inlineToolbarActions = function () {
-
- var wrapper = document.createElement('DIV');
-
- wrapper.className += 'ce-toolbar-inline__actions';
-
- return wrapper;
-
- };
-
- draw.inputForLink = function () {
-
- var input = document.createElement('INPUT');
-
- input.type = 'input';
- input.className += 'inputForLink';
- input.placeholder = 'Вставьте ссылку ...';
- input.setAttribute('form', 'defaultForm');
-
- input.setAttribute('autofocus', 'autofocus');
-
- return input;
-
- };
-
- /**
- * @todo Desc
- */
- draw.blockButtons = function () {
-
- var block = document.createElement('div');
-
- block.className += 'ce-toolbar__actions';
-
- return block;
-
- };
-
- /**
- * Block settings panel
- */
- draw.blockSettings = function () {
-
- var settings = document.createElement('div');
-
- settings.className += 'ce-settings';
-
- return settings;
-
- };
-
- draw.defaultSettings = function () {
-
- var div = document.createElement('div');
-
- div.classList.add('ce-settings_default');
-
- return div;
-
- };
-
- draw.pluginsSettings = function () {
-
- var div = document.createElement('div');
-
- div.classList.add('ce-settings_plugin');
-
- return div;
-
- };
-
- draw.plusButton = function () {
-
- var button = document.createElement('span');
-
- button.className = 'ce-toolbar__plus';
- // button.innerHTML = '';
-
- return button;
-
- };
-
- /**
- * Settings button in toolbar
- */
- draw.settingsButton = function () {
-
- var toggler = document.createElement('span');
-
- toggler.className = 'ce-toolbar__settings-btn';
-
- /** Toggler button*/
- toggler.innerHTML = '';
-
- return toggler;
-
- };
-
- /**
- * Redactor tools wrapper
- */
-
- draw.toolbox = function () {
-
- var wrapper = document.createElement('div');
-
- wrapper.className = 'ce-toolbar__tools';
-
- return wrapper;
-
- };
-
- /**
- * @protected
- *
- * Draws tool buttons for toolbox
- *
- * @param {String} type
- * @param {String} classname
- * @returns {Element}
- */
- draw.toolbarButton = function (type, classname) {
-
- var button = document.createElement('li'),
- toolIcon = document.createElement('i'),
- toolTitle = document.createElement('span');
-
- button.dataset.type = type;
- button.setAttribute('title', type);
-
- toolIcon.classList.add(classname);
- toolTitle.classList.add('ce_toolbar_tools--title');
-
-
- button.appendChild(toolIcon);
- button.appendChild(toolTitle);
-
- return button;
-
- };
-
- /**
- * @protected
- *
- * Draws tools for inline toolbar
- *
- * @param {String} type
- * @param {String} classname
- */
- draw.toolbarButtonInline = function (type, classname) {
-
- var button = document.createElement('BUTTON'),
- toolIcon = document.createElement('I');
-
- button.type = 'button';
- button.dataset.type = type;
- toolIcon.classList.add(classname);
-
- button.appendChild(toolIcon);
-
- return button;
-
- };
-
- /**
- * Redactor block
- */
- draw.block = function (tagName, content) {
-
- var node = document.createElement(tagName);
-
- node.innerHTML = content || '';
-
- return node;
-
- };
-
- /**
- * Creates Node with passed tagName and className
- * @param {string} tagName
- * @param {string} className
- * @param {object} properties - allow to assign properties
- */
- draw.node = function ( tagName, className, properties ) {
-
- var el = document.createElement( tagName );
-
- if ( className ) el.className = className;
-
- if ( properties ) {
-
- for (var name in properties) {
-
- el[name] = properties[name];
-
- }
-
- }
-
- return el;
-
- };
-
- /**
- * Unavailable plugin block
- */
- draw.unavailableBlock = function () {
-
- var wrapper = document.createElement('DIV');
-
- wrapper.classList.add('cdx-unavailable-block');
-
- return wrapper;
-
- };
-
- return draw;
-
-})({});
\ No newline at end of file
diff --git a/modules/listeners.js b/modules/listeners.js
deleted file mode 100644
index 6b353ae25..000000000
--- a/modules/listeners.js
+++ /dev/null
@@ -1,192 +0,0 @@
-/**
- * Codex Editor Listeners module
- *
- * @author Codex Team
- * @version 1.0
- */
-
-/**
- * Module-decorator for event listeners assignment
- */
-module.exports = function (listeners) {
-
- var allListeners = [];
-
- /**
- * Search methods
- *
- * byElement, byType and byHandler returns array of suitable listeners
- * one and all takes element, eventType, and handler and returns first (all) suitable listener
- *
- */
- listeners.search = function () {
-
- var byElement = function (element, context) {
-
- var listenersOnElement = [];
-
- context = context || allListeners;
-
- for (var i = 0; i < context.length; i++) {
-
- var listener = context[i];
-
- if (listener.element === element) {
-
- listenersOnElement.push(listener);
-
- }
-
- }
-
- return listenersOnElement;
-
- };
-
- var byType = function (eventType, context) {
-
- var listenersWithType = [];
-
- context = context || allListeners;
-
- for (var i = 0; i < context.length; i++) {
-
- var listener = context[i];
-
- if (listener.type === eventType) {
-
- listenersWithType.push(listener);
-
- }
-
- }
-
- return listenersWithType;
-
- };
-
- var byHandler = function (handler, context) {
-
- var listenersWithHandler = [];
-
- context = context || allListeners;
-
- for (var i = 0; i < context.length; i++) {
-
- var listener = context[i];
-
- if (listener.handler === handler) {
-
- listenersWithHandler.push(listener);
-
- }
-
- }
-
- return listenersWithHandler;
-
- };
-
- var one = function (element, eventType, handler) {
-
- var result = allListeners;
-
- if (element)
- result = byElement(element, result);
-
- if (eventType)
- result = byType(eventType, result);
-
- if (handler)
- result = byHandler(handler, result);
-
- return result[0];
-
- };
-
- var all = function (element, eventType, handler) {
-
- var result = allListeners;
-
- if (element)
- result = byElement(element, result);
-
- if (eventType)
- result = byType(eventType, result);
-
- if (handler)
- result = byHandler(handler, result);
-
- return result;
-
- };
-
- return {
- byElement : byElement,
- byType : byType,
- byHandler : byHandler,
- one : one,
- all : all
- };
-
- }();
-
- listeners.add = function (element, eventType, handler, isCapture) {
-
- element.addEventListener(eventType, handler, isCapture);
-
- var data = {
- element: element,
- type: eventType,
- handler: handler
- };
-
- var alreadyAddedListener = listeners.search.one(element, eventType, handler);
-
- if (!alreadyAddedListener) {
-
- allListeners.push(data);
-
- }
-
- };
-
- listeners.remove = function (element, eventType, handler) {
-
- element.removeEventListener(eventType, handler);
-
- var existingListeners = listeners.search.all(element, eventType, handler);
-
- for (var i = 0; i < existingListeners.length; i++) {
-
- var index = allListeners.indexOf(existingListeners[i]);
-
- if (index > 0) {
-
- allListeners.splice(index, 1);
-
- }
-
- }
-
- };
-
- listeners.removeAll = function () {
-
- allListeners.map(function (current) {
-
- listeners.remove(current.element, current.type, current.handler);
-
- });
-
- };
-
- listeners.get = function (element, eventType, handler) {
-
- return listeners.search.all(element, eventType, handler);
-
- };
-
- return listeners;
-
-}({});
\ No newline at end of file
diff --git a/modules/notifications.js b/modules/notifications.js
deleted file mode 100644
index ffeda9b84..000000000
--- a/modules/notifications.js
+++ /dev/null
@@ -1,231 +0,0 @@
-/**
- * Codex Editor Notification Module
- *
- * @author Codex Team
- * @version 1.0
- */
-
-module.exports = (function (notifications) {
-
- let editor = codex.editor;
-
- var queue = [];
-
- var addToQueue = function (settings) {
-
- queue.push(settings);
-
- var index = 0;
-
- while ( index < queue.length && queue.length > 5) {
-
- if (queue[index].type == 'confirm' || queue[index].type == 'prompt') {
-
- index++;
- continue;
-
- }
-
- queue[index].close();
- queue.splice(index, 1);
-
- }
-
- };
-
- notifications.createHolder = function () {
-
- var holder = editor.draw.node('DIV', 'cdx-notifications-block');
-
- editor.nodes.notifications = document.body.appendChild(holder);
-
- return holder;
-
- };
-
-
- /**
- * Error notificator. Shows block with message
- * @protected
- */
- notifications.errorThrown = function (errorMsg, event) {
-
- editor.notifications.notification({message: 'This action is not available currently', type: event.type});
-
- };
-
- /**
- *
- * Appends notification
- *
- * settings = {
- * type - notification type (reserved types: alert, confirm, prompt). Just add class 'cdx-notification-'+type
- * message - notification message
- * okMsg - confirm button text (default - 'Ok')
- * cancelBtn - cancel button text (default - 'Cancel'). Only for confirm and prompt types
- * confirm - function-handler for ok button click
- * cancel - function-handler for cancel button click. Only for confirm and prompt types
- * time - time (in seconds) after which notification will close (default - 10s)
- * }
- *
- * @param settings
- */
- notifications.notification = function (constructorSettings) {
-
- /** Private vars and methods */
- var notification = null,
- cancel = null,
- type = null,
- confirm = null,
- inputField = null;
-
- var confirmHandler = function () {
-
- close();
-
- if (typeof confirm !== 'function' ) {
-
- return;
-
- }
-
- if (type == 'prompt') {
-
- confirm(inputField.value);
- return;
-
- }
-
- confirm();
-
- };
-
- var cancelHandler = function () {
-
- close();
-
- if (typeof cancel !== 'function' ) {
-
- return;
-
- }
-
- cancel();
-
- };
-
-
- /** Public methods */
- function create(settings) {
-
- if (!(settings && settings.message)) {
-
- editor.core.log('Can\'t create notification. Message is missed');
- return;
-
- }
-
- settings.type = settings.type || 'alert';
- settings.time = settings.time*1000 || 10000;
-
- var wrapper = editor.draw.node('DIV', 'cdx-notification'),
- message = editor.draw.node('DIV', 'cdx-notification__message'),
- input = editor.draw.node('INPUT', 'cdx-notification__input'),
- okBtn = editor.draw.node('SPAN', 'cdx-notification__ok-btn'),
- cancelBtn = editor.draw.node('SPAN', 'cdx-notification__cancel-btn');
-
- message.textContent = settings.message;
- okBtn.textContent = settings.okMsg || 'ОК';
- cancelBtn.textContent = settings.cancelMsg || 'Отмена';
-
- editor.listeners.add(okBtn, 'click', confirmHandler);
- editor.listeners.add(cancelBtn, 'click', cancelHandler);
-
- wrapper.appendChild(message);
-
- if (settings.type == 'prompt') {
-
- wrapper.appendChild(input);
-
- }
-
- wrapper.appendChild(okBtn);
-
- if (settings.type == 'prompt' || settings.type == 'confirm') {
-
- wrapper.appendChild(cancelBtn);
-
- }
-
- wrapper.classList.add('cdx-notification-' + settings.type);
- wrapper.dataset.type = settings.type;
-
- notification = wrapper;
- type = settings.type;
- confirm = settings.confirm;
- cancel = settings.cancel;
- inputField = input;
-
- if (settings.type != 'prompt' && settings.type != 'confirm') {
-
- window.setTimeout(close, settings.time);
-
- }
-
- };
-
- /**
- * Show notification block
- */
- function send() {
-
- editor.nodes.notifications.appendChild(notification);
- inputField.focus();
-
- editor.nodes.notifications.classList.add('cdx-notification__notification-appending');
-
- window.setTimeout(function () {
-
- editor.nodes.notifications.classList.remove('cdx-notification__notification-appending');
-
- }, 100);
-
- addToQueue({type: type, close: close});
-
- };
-
- /**
- * Remove notification block
- */
- function close() {
-
- notification.remove();
-
- };
-
-
- if (constructorSettings) {
-
- create(constructorSettings);
- send();
-
- }
-
- return {
- create: create,
- send: send,
- close: close
- };
-
- };
-
- notifications.clear = function () {
-
- editor.nodes.notifications.innerHTML = '';
- queue = [];
-
- };
-
- return notifications;
-
-})({});
\ No newline at end of file
diff --git a/modules/parser.js b/modules/parser.js
deleted file mode 100644
index 70debc9c2..000000000
--- a/modules/parser.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * Codex Editor Parser Module
- *
- * @author Codex Team
- * @version 1.1
- */
-
-module.exports = (function (parser) {
-
- let editor = codex.editor;
-
- /** inserting text */
- parser.insertPastedContent = function (blockType, tag) {
-
- editor.content.insertBlock({
- type : blockType.type,
- block : blockType.render({
- text : tag.innerHTML
- })
- });
-
- };
-
- /**
- * Check DOM node for display style: separated block or child-view
- */
- parser.isFirstLevelBlock = function (node) {
-
- return node.nodeType == editor.core.nodeTypes.TAG &&
- node.classList.contains(editor.ui.className.BLOCK_CLASSNAME);
-
- };
-
- return parser;
-
-})({});
diff --git a/modules/paste.js b/modules/paste.js
deleted file mode 100644
index ae8101856..000000000
--- a/modules/paste.js
+++ /dev/null
@@ -1,278 +0,0 @@
-/**
- * Codex Editor Paste module
- *
- * @author Codex Team
- * @version 1.1.1
- */
-
-module.exports = function (paste) {
-
- let editor = codex.editor;
-
- var patterns = [];
-
- paste.prepare = function () {
-
- var tools = editor.tools;
-
- for (var tool in tools) {
-
- if (!tools[tool].renderOnPastePatterns || !Array.isArray(tools[tool].renderOnPastePatterns)) {
-
- continue;
-
- }
-
- tools[tool].renderOnPastePatterns.map(function (pattern) {
-
-
- patterns.push(pattern);
-
- });
-
- }
-
- return Promise.resolve();
-
- };
-
- /**
- * Saves data
- * @param event
- */
- paste.pasted = function (event) {
-
- var clipBoardData = event.clipboardData || window.clipboardData,
- content = clipBoardData.getData('Text');
-
- var result = analize(content);
-
- if (result) {
-
- event.preventDefault();
- event.stopImmediatePropagation();
-
- }
-
- return result;
-
- };
-
- /**
- * Analizes pated string and calls necessary method
- */
-
- var analize = function (string) {
-
- var result = false,
- content = editor.content.currentNode,
- plugin = content.dataset.tool;
-
- patterns.map( function (pattern) {
-
- var execArray = pattern.regex.exec(string),
- match = execArray && execArray[0];
-
- if ( match && match === string.trim()) {
-
- /** current block is not empty */
- if ( content.textContent.trim() && plugin == editor.settings.initialBlockPlugin ) {
-
- pasteToNewBlock_();
-
- }
-
- pattern.callback(string, pattern);
- result = true;
-
- }
-
- });
-
- return result;
-
- };
-
- var pasteToNewBlock_ = function () {
-
- /** Create new initial block */
- editor.content.insertBlock({
-
- type : editor.settings.initialBlockPlugin,
- block : editor.tools[editor.settings.initialBlockPlugin].render({
- text : ''
- })
-
- }, false);
-
- };
-
- /**
- * This method prevents default behaviour.
- *
- * @param {Object} event
- * @protected
- *
- * @description We get from clipboard pasted data, sanitize, make a fragment that contains of this sanitized nodes.
- * Firstly, we need to memorize the caret position. We can do that by getting the range of selection.
- * After all, we insert clear fragment into caret placed position. Then, we should move the caret to the last node
- */
- paste.blockPasteCallback = function (event) {
-
-
- if (!needsToHandlePasteEvent(event.target)) {
-
- return;
-
- }
-
- /** Prevent default behaviour */
- event.preventDefault();
-
- /** get html pasted data - dirty data */
- var htmlData = event.clipboardData.getData('text/html'),
- plainData = event.clipboardData.getData('text/plain');
-
- /** Temporary DIV that is used to work with text's paragraphs as DOM-elements*/
- var paragraphs = editor.draw.node('DIV', '', {}),
- cleanData,
- wrappedData;
-
- /** Create fragment, that we paste to range after proccesing */
- cleanData = editor.sanitizer.clean(htmlData);
-
- /**
- * We wrap pasted text with tags to split it logically
- * @type {string}
- */
- wrappedData = editor.content.wrapTextWithParagraphs(cleanData, plainData);
- paragraphs.innerHTML = wrappedData;
-
- /**
- * If there only one paragraph, just insert in at the caret location
- */
- if (paragraphs.childNodes.length == 1) {
-
- emulateUserAgentBehaviour(paragraphs.firstChild);
- return;
-
- }
-
- insertPastedParagraphs(paragraphs.childNodes);
-
- };
-
- /**
- * Checks if we should handle paste event on block
- * @param block
- *
- * @return {boolean}
- */
- var needsToHandlePasteEvent = function (block) {
-
- /** If area is input or textarea then allow default behaviour */
- if ( editor.core.isNativeInput(block) ) {
-
- return false;
-
- }
-
- var editableParent = editor.content.getEditableParent(block);
-
- /** Allow paste when event target placed in Editable element */
- if (!editableParent) {
-
- return false;
-
- }
-
- return true;
-
- };
-
- /**
- * Inserts new initial plugin blocks with data in paragraphs
- *
- * @param {Array} paragraphs - array of paragraphs (
) whit content, that should be inserted
- */
- var insertPastedParagraphs = function (paragraphs) {
-
- var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin,
- currentNode = editor.content.currentNode;
-
-
- paragraphs.forEach(function (paragraph) {
-
- /** Don't allow empty paragraphs */
- if (editor.core.isBlockEmpty(paragraph)) {
-
- return;
-
- }
-
- editor.content.insertBlock({
- type : NEW_BLOCK_TYPE,
- block : editor.tools[NEW_BLOCK_TYPE].render({
- text : paragraph.innerHTML
- })
- });
-
- editor.caret.inputIndex++;
-
- });
-
- editor.caret.setToPreviousBlock(editor.caret.getCurrentInputIndex() + 1);
-
-
- /**
- * If there was no data in working node, remove it
- */
- if (editor.core.isBlockEmpty(currentNode)) {
-
- currentNode.remove();
- editor.ui.saveInputs();
-
- }
-
-
- };
-
- /**
- * Inserts node content at the caret position
- *
- * @param {Node} node - DOM node (could be DocumentFragment), that should be inserted at the caret location
- */
- var emulateUserAgentBehaviour = function (node) {
-
- var newNode;
-
- if (node.childElementCount) {
-
- newNode = document.createDocumentFragment();
-
- node.childNodes.forEach(function (current) {
-
- if (!editor.core.isDomNode(current) && current.data.trim() === '') {
-
- return;
-
- }
-
- newNode.appendChild(current.cloneNode(true));
-
- });
-
- } else {
-
- newNode = document.createTextNode(node.textContent);
-
- }
-
- editor.caret.insertNode(newNode);
-
- };
-
-
- return paste;
-
-}({});
\ No newline at end of file
diff --git a/modules/renderer.js b/modules/renderer.js
deleted file mode 100644
index 1704755b7..000000000
--- a/modules/renderer.js
+++ /dev/null
@@ -1,203 +0,0 @@
-/**
- * Codex Editor Renderer Module
- *
- * @author Codex Team
- * @version 1.0
- */
-
-module.exports = (function (renderer) {
-
- let editor = codex.editor;
-
- /**
- * Asyncronously parses input JSON to redactor blocks
- */
- renderer.makeBlocksFromData = function () {
-
- /**
- * If redactor is empty, add first paragraph to start writing
- */
- if (editor.core.isEmpty(editor.state.blocks) || !editor.state.blocks.items.length) {
-
- editor.ui.addInitialBlock();
- return;
-
- }
-
- Promise.resolve()
-
- /** First, get JSON from state */
- .then(function () {
-
- return editor.state.blocks;
-
- })
-
- /** Then, start to iterate they */
- .then(editor.renderer.appendBlocks)
-
- /** Write log if something goes wrong */
- .catch(function (error) {
-
- editor.core.log('Error while parsing JSON: %o', 'error', error);
-
- });
-
- };
-
- /**
- * Parses JSON to blocks
- * @param {object} data
- * @return Primise -> nodeList
- */
- renderer.appendBlocks = function (data) {
-
- var blocks = data.items;
-
- /**
- * Sequence of one-by-one blocks appending
- * Uses to save blocks order after async-handler
- */
- var nodeSequence = Promise.resolve();
-
- for (var index = 0; index < blocks.length ; index++ ) {
-
- /** Add node to sequence at specified index */
- editor.renderer.appendNodeAtIndex(nodeSequence, blocks, index);
-
- }
-
- };
-
- /**
- * Append node at specified index
- */
- renderer.appendNodeAtIndex = function (nodeSequence, blocks, index) {
-
- /** We need to append node to sequence */
- nodeSequence
-
- /** first, get node async-aware */
- .then(function () {
-
- return editor.renderer.getNodeAsync(blocks, index);
-
- })
-
- /**
- * second, compose editor-block from JSON object
- */
- .then(editor.renderer.createBlockFromData)
-
- /**
- * now insert block to redactor
- */
- .then(function (blockData) {
-
- /**
- * blockData has 'block', 'type' and 'stretched' information
- */
- editor.content.insertBlock(blockData);
-
- /** Pass created block to next step */
- return blockData.block;
-
- })
-
- /** Log if something wrong with node */
- .catch(function (error) {
-
- editor.core.log('Node skipped while parsing because %o', 'error', error);
-
- });
-
- };
-
- /**
- * Asynchronously returns block data from blocksList by index
- * @return Promise to node
- */
- renderer.getNodeAsync = function (blocksList, index) {
-
- return Promise.resolve().then(function () {
-
- return {
- tool : blocksList[index],
- position : index
- };
-
- });
-
- };
-
- /**
- * Creates editor block by JSON-data
- *
- * @uses render method of each plugin
- *
- * @param {Object} toolData.tool
- * { header : {
- * text: '',
- * type: 'H3', ...
- * }
- * }
- * @param {Number} toolData.position - index in input-blocks array
- * @return {Object} with type and Element
- */
- renderer.createBlockFromData = function ( toolData ) {
-
- /** New parser */
- var block,
- tool = toolData.tool,
- pluginName = tool.type;
-
- /** Get first key of object that stores plugin name */
- // for (var pluginName in blockData) break;
-
- /** Check for plugin existance */
- if (!editor.tools[pluginName]) {
-
- throw Error(`Plugin «${pluginName}» not found`);
-
- }
-
- /** Check for plugin having render method */
- if (typeof editor.tools[pluginName].render != 'function') {
-
- throw Error(`Plugin «${pluginName}» must have «render» method`);
-
- }
-
- if ( editor.tools[pluginName].available === false ) {
-
- block = editor.draw.unavailableBlock();
-
- block.innerHTML = editor.tools[pluginName].loadingMessage;
-
- /**
- * Saver will extract data from initial block data by position in array
- */
- block.dataset.inputPosition = toolData.position;
-
- } else {
-
- /** New Parser */
- block = editor.tools[pluginName].render(tool.data);
-
- }
-
- /** is first-level block stretched */
- var stretched = editor.tools[pluginName].isStretched || false;
-
- /** Retrun type and block */
- return {
- type : pluginName,
- block : block,
- stretched : stretched
- };
-
- };
-
- return renderer;
-
-})({});
\ No newline at end of file
diff --git a/modules/sanitizer.js b/modules/sanitizer.js
deleted file mode 100644
index fe7ed7fc3..000000000
--- a/modules/sanitizer.js
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * Codex Sanitizer
- */
-
-module.exports = (function (sanitizer) {
-
- /** HTML Janitor library */
- let janitor = require('html-janitor');
-
- /** Codex Editor */
- let editor = codex.editor;
-
- sanitizer.prepare = function () {
-
- if (editor.settings.sanitizer && !editor.core.isEmpty(editor.settings.sanitizer)) {
-
- Config.CUSTOM = editor.settings.sanitizer;
-
- }
-
- };
-
- /**
- * Basic config
- */
- var Config = {
-
- /** User configuration */
- CUSTOM : null,
-
- BASIC : {
-
- tags: {
- p: {},
- a: {
- href: true,
- target: '_blank',
- rel: 'nofollow'
- }
- }
- }
- };
-
- sanitizer.Config = Config;
-
- /**
- *
- * @param userCustomConfig
- * @returns {*}
- * @private
- *
- * @description If developer uses editor's API, then he can customize sane restrictions.
- * Or, sane config can be defined globally in editors initialization. That config will be used everywhere
- * At least, if there is no config overrides, that API uses BASIC Default configation
- */
- let init_ = function (userCustomConfig) {
-
- let configuration = userCustomConfig || Config.CUSTOM || Config.BASIC;
-
- return new janitor(configuration);
-
- };
-
- /**
- * Cleans string from unwanted tags
- * @protected
- * @param {String} dirtyString - taint string
- * @param {Object} customConfig - allowed tags
- */
- sanitizer.clean = function (dirtyString, customConfig) {
-
- let janitorInstance = init_(customConfig);
-
- return janitorInstance.clean(dirtyString);
-
- };
-
- return sanitizer;
-
-})({});
\ No newline at end of file
diff --git a/modules/saver.js b/modules/saver.js
deleted file mode 100644
index d33589310..000000000
--- a/modules/saver.js
+++ /dev/null
@@ -1,165 +0,0 @@
-/**
- * Codex Editor Saver
- *
- * @author Codex Team
- * @version 1.1.0
- */
-
-module.exports = (function (saver) {
-
- let editor = codex.editor;
-
- /**
- * @public
- * Save blocks
- */
- saver.save = function () {
-
- /** Save html content of redactor to memory */
- editor.state.html = editor.nodes.redactor.innerHTML;
-
- /** Clean jsonOutput state */
- editor.state.jsonOutput = [];
-
- return saveBlocks(editor.nodes.redactor.childNodes);
-
- };
-
- /**
- * @private
- * Save each block data
- *
- * @param blocks
- * @returns {Promise.}
- */
- let saveBlocks = function (blocks) {
-
- let data = [];
-
- for(let index = 0; index < blocks.length; index++) {
-
- data.push(getBlockData(blocks[index]));
-
- }
-
- return Promise.all(data)
- .then(makeOutput)
- .catch(editor.core.log);
-
- };
-
- /** Save and validate block data */
- let getBlockData = function (block) {
-
- return saveBlockData(block)
- .then(validateBlockData)
- .catch(editor.core.log);
-
- };
-
- /**
- * @private
- * Call block`s plugin save method and return saved data
- *
- * @param block
- * @returns {Object}
- */
- let saveBlockData = function (block) {
-
- let pluginName = block.dataset.tool;
-
- /** Check for plugin existence */
- if (!editor.tools[pluginName]) {
-
- editor.core.log(`Plugin «${pluginName}» not found`, 'error');
- return {data: null, pluginName: null};
-
- }
-
- /** Check for plugin having save method */
- if (typeof editor.tools[pluginName].save !== 'function') {
-
- editor.core.log(`Plugin «${pluginName}» must have save method`, 'error');
- return {data: null, pluginName: null};
-
- }
-
- /** Result saver */
- let blockContent = block.childNodes[0],
- pluginsContent = blockContent.childNodes[0],
- position = pluginsContent.dataset.inputPosition;
-
- /** If plugin wasn't available then return data from cache */
- if ( editor.tools[pluginName].available === false ) {
-
- return Promise.resolve({data: codex.editor.state.blocks.items[position].data, pluginName});
-
- }
-
- return Promise.resolve(pluginsContent)
- .then(editor.tools[pluginName].save)
- .then(data => Object({data, pluginName}));
-
- };
-
- /**
- * Call plugin`s validate method. Return false if validation failed
- *
- * @param data
- * @param pluginName
- * @returns {Object|Boolean}
- */
- let validateBlockData = function ({data, pluginName}) {
-
- if (!data || !pluginName) {
-
- return false;
-
- }
-
- if (editor.tools[pluginName].validate) {
-
- let result = editor.tools[pluginName].validate(data);
-
- /**
- * Do not allow invalid data
- */
- if (!result) {
-
- return false;
-
- }
-
- }
-
- return {data, pluginName};
-
-
- };
-
- /**
- * Compile article output
- *
- * @param savedData
- * @returns {{time: number, version, items: (*|Array)}}
- */
- let makeOutput = function (savedData) {
-
- savedData = savedData.filter(blockData => blockData);
-
- let items = savedData.map(blockData => Object({type: blockData.pluginName, data: blockData.data}));
-
- editor.state.jsonOutput = items;
-
- return {
- id: editor.state.blocks.id || null,
- time: +new Date(),
- version: editor.version,
- items
- };
-
- };
-
- return saver;
-
-})({});
diff --git a/modules/toolbar/inline.js b/modules/toolbar/inline.js
deleted file mode 100644
index 36e50024a..000000000
--- a/modules/toolbar/inline.js
+++ /dev/null
@@ -1,599 +0,0 @@
-/**
- * Inline toolbar
- *
- * Contains from tools:
- * Bold, Italic, Underline and Anchor
- *
- * @author Codex Team
- * @version 1.0
- */
-
-module.exports = (function (inline) {
-
- let editor = codex.editor;
-
- inline.buttonsOpened = null;
- inline.actionsOpened = null;
- inline.wrappersOffset = null;
-
- /**
- * saving selection that need for execCommand for styling
- *
- */
- inline.storedSelection = null;
-
- /**
- * @protected
- *
- * Open inline toobar
- */
- inline.show = function () {
-
- var currentNode = editor.content.currentNode,
- tool = currentNode.dataset.tool,
- plugin;
-
- /**
- * tool allowed to open inline toolbar
- */
- plugin = editor.tools[tool];
-
- if (!plugin.showInlineToolbar)
- return;
-
- var selectedText = inline.getSelectionText(),
- toolbar = editor.nodes.inlineToolbar.wrapper;
-
- if (selectedText.length > 0) {
-
- /** Move toolbar and open */
- editor.toolbar.inline.move();
-
- /** Open inline toolbar */
- toolbar.classList.add('opened');
-
- /** show buttons of inline toolbar */
- editor.toolbar.inline.showButtons();
-
- }
-
- };
-
- /**
- * @protected
- *
- * Closes inline toolbar
- */
- inline.close = function () {
-
- var toolbar = editor.nodes.inlineToolbar.wrapper;
-
- toolbar.classList.remove('opened');
-
- };
-
- /**
- * @private
- *
- * Moving toolbar
- */
- inline.move = function () {
-
- if (!this.wrappersOffset) {
-
- this.wrappersOffset = this.getWrappersOffset();
-
- }
-
- var coords = this.getSelectionCoords(),
- defaultOffset = 0,
- toolbar = editor.nodes.inlineToolbar.wrapper,
- newCoordinateX,
- newCoordinateY;
-
- if (!coords) {
-
- return;
-
- }
-
- if (toolbar.offsetHeight === 0) {
-
- defaultOffset = 40;
-
- }
-
- newCoordinateX = coords.x - this.wrappersOffset.left;
- newCoordinateY = coords.y + window.scrollY - this.wrappersOffset.top - defaultOffset - toolbar.offsetHeight;
-
- toolbar.style.transform = `translate3D(${Math.floor(newCoordinateX)}px, ${Math.floor(newCoordinateY)}px, 0)`;
-
- /** Close everything */
- editor.toolbar.inline.closeButtons();
- editor.toolbar.inline.closeAction();
-
- };
-
- /**
- * @private
- *
- * Tool Clicked
- */
-
- inline.toolClicked = function (event, type) {
-
- /**
- * For simple tools we use default browser function
- * For more complicated tools, we should write our own behavior
- */
- switch (type) {
- case 'createLink' : editor.toolbar.inline.createLinkAction(event, type); break;
- default : editor.toolbar.inline.defaultToolAction(type); break;
- }
-
- /**
- * highlight buttons
- * after making some action
- */
- editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);
-
- };
-
- /**
- * @private
- *
- * Saving wrappers offset in DOM
- */
- inline.getWrappersOffset = function () {
-
- var wrapper = editor.nodes.wrapper,
- offset = this.getOffset(wrapper);
-
- this.wrappersOffset = offset;
- return offset;
-
- };
-
- /**
- * @private
- *
- * Calculates offset of DOM element
- *
- * @param el
- * @returns {{top: number, left: number}}
- */
- inline.getOffset = function ( el ) {
-
- var _x = 0;
- var _y = 0;
-
- while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
-
- _x += (el.offsetLeft + el.clientLeft);
- _y += (el.offsetTop + el.clientTop);
- el = el.offsetParent;
-
- }
- return { top: _y, left: _x };
-
- };
-
- /**
- * @private
- *
- * Calculates position of selected text
- * @returns {{x: number, y: number}}
- */
- inline.getSelectionCoords = function () {
-
- var sel = document.selection, range;
- var x = 0, y = 0;
-
- if (sel) {
-
- if (sel.type != 'Control') {
-
- range = sel.createRange();
- range.collapse(true);
- x = range.boundingLeft;
- y = range.boundingTop;
-
- }
-
- } else if (window.getSelection) {
-
- sel = window.getSelection();
-
- if (sel.rangeCount) {
-
- range = sel.getRangeAt(0).cloneRange();
- if (range.getClientRects) {
-
- range.collapse(true);
- var rect = range.getClientRects()[0];
-
- if (!rect) {
-
- return;
-
- }
-
- x = rect.left;
- y = rect.top;
-
- }
-
- }
-
- }
- return { x: x, y: y };
-
- };
-
- /**
- * @private
- *
- * Returns selected text as String
- * @returns {string}
- */
- inline.getSelectionText = function () {
-
- var selectedText = '';
-
- // all modern browsers and IE9+
- if (window.getSelection) {
-
- selectedText = window.getSelection().toString();
-
- }
-
- return selectedText;
-
- };
-
- /** Opens buttons block */
- inline.showButtons = function () {
-
- var buttons = editor.nodes.inlineToolbar.buttons;
-
- buttons.classList.add('opened');
-
- editor.toolbar.inline.buttonsOpened = true;
-
- /** highlight buttons */
- editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);
-
- };
-
- /** Makes buttons disappear */
- inline.closeButtons = function () {
-
- var buttons = editor.nodes.inlineToolbar.buttons;
-
- buttons.classList.remove('opened');
-
- editor.toolbar.inline.buttonsOpened = false;
-
- };
-
- /** Open buttons defined action if exist */
- inline.showActions = function () {
-
- var action = editor.nodes.inlineToolbar.actions;
-
- action.classList.add('opened');
-
- editor.toolbar.inline.actionsOpened = true;
-
- };
-
- /** Close actions block */
- inline.closeAction = function () {
-
- var action = editor.nodes.inlineToolbar.actions;
-
- action.innerHTML = '';
- action.classList.remove('opened');
- editor.toolbar.inline.actionsOpened = false;
-
- };
-
-
- /**
- * Callback for keydowns in inline toolbar "Insert link..." input
- */
- let inlineToolbarAnchorInputKeydown_ = function (event) {
-
- if (event.keyCode != editor.core.keys.ENTER) {
-
- return;
-
- }
-
- let editable = editor.content.currentNode,
- storedSelection = editor.toolbar.inline.storedSelection;
-
- editor.toolbar.inline.restoreSelection(editable, storedSelection);
- editor.toolbar.inline.setAnchor(this.value);
-
- /**
- * Preventing events that will be able to happen
- */
- event.preventDefault();
- event.stopImmediatePropagation();
-
- editor.toolbar.inline.clearRange();
-
- };
-
- /** Action for link creation or for setting anchor */
- inline.createLinkAction = function (event) {
-
- var isActive = this.isLinkActive();
-
- var editable = editor.content.currentNode,
- storedSelection = editor.toolbar.inline.saveSelection(editable);
-
- /** Save globally selection */
- editor.toolbar.inline.storedSelection = storedSelection;
-
- if (isActive) {
-
-
- /**
- * Changing stored selection. if we want to remove anchor from word
- * we should remove anchor from whole word, not only selected part.
- * The solution is than we get the length of current link
- * Change start position to - end of selection minus length of anchor
- */
- editor.toolbar.inline.restoreSelection(editable, storedSelection);
-
- editor.toolbar.inline.defaultToolAction('unlink');
-
- } else {
-
- /** Create input and close buttons */
- var action = editor.draw.inputForLink();
-
- editor.nodes.inlineToolbar.actions.appendChild(action);
-
- editor.toolbar.inline.closeButtons();
- editor.toolbar.inline.showActions();
-
- /**
- * focus to input
- * Solution: https://developer.mozilla.org/ru/docs/Web/API/HTMLElement/focus
- * Prevents event after showing input and when we need to focus an input which is in unexisted form
- */
- action.focus();
- event.preventDefault();
-
- /** Callback to link action */
- editor.listeners.add(action, 'keydown', inlineToolbarAnchorInputKeydown_, false);
-
- }
-
- };
-
- inline.isLinkActive = function () {
-
- var isActive = false;
-
- editor.nodes.inlineToolbar.buttons.childNodes.forEach(function (tool) {
-
- var dataType = tool.dataset.type;
-
- if (dataType == 'link' && tool.classList.contains('hightlighted')) {
-
- isActive = true;
-
- }
-
- });
-
- return isActive;
-
- };
-
- /** default action behavior of tool */
- inline.defaultToolAction = function (type) {
-
- document.execCommand(type, false, null);
-
- };
-
- /**
- * @private
- *
- * Sets URL
- *
- * @param {String} url - URL
- */
- inline.setAnchor = function (url) {
-
- document.execCommand('createLink', false, url);
-
- /** Close after URL inserting */
- editor.toolbar.inline.closeAction();
-
- };
-
- /**
- * @private
- *
- * Saves selection
- */
- inline.saveSelection = function (containerEl) {
-
- var range = window.getSelection().getRangeAt(0),
- preSelectionRange = range.cloneRange(),
- start;
-
- preSelectionRange.selectNodeContents(containerEl);
- preSelectionRange.setEnd(range.startContainer, range.startOffset);
-
- start = preSelectionRange.toString().length;
-
- return {
- start: start,
- end: start + range.toString().length
- };
-
- };
-
- /**
- * @private
- *
- * Sets to previous selection (Range)
- *
- * @param {Element} containerEl - editable element where we restore range
- * @param {Object} savedSel - range basic information to restore
- */
- inline.restoreSelection = function (containerEl, savedSel) {
-
- var range = document.createRange(),
- charIndex = 0;
-
- range.setStart(containerEl, 0);
- range.collapse(true);
-
- var nodeStack = [ containerEl ],
- node,
- foundStart = false,
- stop = false,
- nextCharIndex;
-
- while (!stop && (node = nodeStack.pop())) {
-
- if (node.nodeType == 3) {
-
- nextCharIndex = charIndex + node.length;
-
- if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
-
- range.setStart(node, savedSel.start - charIndex);
- foundStart = true;
-
- }
- if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
-
- range.setEnd(node, savedSel.end - charIndex);
- stop = true;
-
- }
- charIndex = nextCharIndex;
-
- } else {
-
- var i = node.childNodes.length;
-
- while (i--) {
-
- nodeStack.push(node.childNodes[i]);
-
- }
-
- }
-
- }
-
- var sel = window.getSelection();
-
- sel.removeAllRanges();
- sel.addRange(range);
-
- };
-
- /**
- * @private
- *
- * Removes all ranges from window selection
- */
- inline.clearRange = function () {
-
- var selection = window.getSelection();
-
- selection.removeAllRanges();
-
- };
-
- /**
- * @private
- *
- * sets or removes hightlight
- */
- inline.hightlight = function (tool) {
-
- var dataType = tool.dataset.type;
-
- if (document.queryCommandState(dataType)) {
-
- editor.toolbar.inline.setButtonHighlighted(tool);
-
- } else {
-
- editor.toolbar.inline.removeButtonsHighLight(tool);
-
- }
-
- /**
- *
- * hightlight for anchors
- */
- var selection = window.getSelection(),
- tag = selection.anchorNode.parentNode;
-
- if (tag.tagName == 'A' && dataType == 'link') {
-
- editor.toolbar.inline.setButtonHighlighted(tool);
-
- }
-
- };
-
- /**
- * @private
- *
- * Mark button if text is already executed
- */
- inline.setButtonHighlighted = function (button) {
-
- button.classList.add('hightlighted');
-
- /** At link tool we also change icon */
- if (button.dataset.type == 'link') {
-
- var icon = button.childNodes[0];
-
- icon.classList.remove('ce-icon-link');
- icon.classList.add('ce-icon-unlink');
-
- }
-
- };
-
- /**
- * @private
- *
- * Removes hightlight
- */
- inline.removeButtonsHighLight = function (button) {
-
- button.classList.remove('hightlighted');
-
- /** At link tool we also change icon */
- if (button.dataset.type == 'link') {
-
- var icon = button.childNodes[0];
-
- icon.classList.remove('ce-icon-unlink');
- icon.classList.add('ce-icon-link');
-
- }
-
- };
-
-
- return inline;
-
-})({});
diff --git a/modules/toolbar/settings.js b/modules/toolbar/settings.js
deleted file mode 100644
index 307c719d3..000000000
--- a/modules/toolbar/settings.js
+++ /dev/null
@@ -1,172 +0,0 @@
-/**
- * Toolbar settings
- *
- * @version 1.0.5
- */
-
-module.exports = (function (settings) {
-
- let editor = codex.editor;
-
- settings.opened = false;
-
- settings.setting = null;
- settings.actions = null;
-
- /**
- * Append and open settings
- */
- settings.open = function (toolType) {
-
- /**
- * Append settings content
- * It's stored in tool.settings
- */
- if ( !editor.tools[toolType] || !editor.tools[toolType].makeSettings ) {
-
- return;
-
- }
-
- /**
- * Draw settings block
- */
- var settingsBlock = editor.tools[toolType].makeSettings();
-
- editor.nodes.pluginSettings.appendChild(settingsBlock);
-
-
- /** Open settings block */
- editor.nodes.blockSettings.classList.add('opened');
- this.opened = true;
-
- };
-
- /**
- * Close and clear settings
- */
- settings.close = function () {
-
- editor.nodes.blockSettings.classList.remove('opened');
- editor.nodes.pluginSettings.innerHTML = '';
-
- this.opened = false;
-
- };
-
- /**
- * @param {string} toolType - plugin type
- */
- settings.toggle = function ( toolType ) {
-
- if ( !this.opened ) {
-
- this.open(toolType);
-
- } else {
-
- this.close();
-
- }
-
- };
-
- /**
- * Here we will draw buttons and add listeners to components
- */
- settings.makeRemoveBlockButton = function () {
-
- var removeBlockWrapper = editor.draw.node('SPAN', 'ce-toolbar__remove-btn', {}),
- settingButton = editor.draw.node('SPAN', 'ce-toolbar__remove-setting', { innerHTML : '' }),
- actionWrapper = editor.draw.node('DIV', 'ce-toolbar__remove-confirmation', {}),
- confirmAction = editor.draw.node('DIV', 'ce-toolbar__remove-confirm', { textContent : 'Удалить блок' }),
- cancelAction = editor.draw.node('DIV', 'ce-toolbar__remove-cancel', { textContent : 'Отмена' });
-
- editor.listeners.add(settingButton, 'click', editor.toolbar.settings.removeButtonClicked, false);
-
- editor.listeners.add(confirmAction, 'click', editor.toolbar.settings.confirmRemovingRequest, false);
-
- editor.listeners.add(cancelAction, 'click', editor.toolbar.settings.cancelRemovingRequest, false);
-
- actionWrapper.appendChild(confirmAction);
- actionWrapper.appendChild(cancelAction);
-
- removeBlockWrapper.appendChild(settingButton);
- removeBlockWrapper.appendChild(actionWrapper);
-
- /** Save setting */
- editor.toolbar.settings.setting = settingButton;
- editor.toolbar.settings.actions = actionWrapper;
-
- return removeBlockWrapper;
-
- };
-
- settings.removeButtonClicked = function () {
-
- var action = editor.toolbar.settings.actions;
-
- if (action.classList.contains('opened')) {
-
- editor.toolbar.settings.hideRemoveActions();
-
- } else {
-
- editor.toolbar.settings.showRemoveActions();
-
- }
-
- editor.toolbar.toolbox.close();
- editor.toolbar.settings.close();
-
- };
-
- settings.cancelRemovingRequest = function () {
-
- editor.toolbar.settings.actions.classList.remove('opened');
-
- };
-
- settings.confirmRemovingRequest = function () {
-
- var currentBlock = editor.content.currentNode,
- firstLevelBlocksCount;
-
- currentBlock.remove();
-
- firstLevelBlocksCount = editor.nodes.redactor.childNodes.length;
-
- /**
- * If all blocks are removed
- */
- if (firstLevelBlocksCount === 0) {
-
- /** update currentNode variable */
- editor.content.currentNode = null;
-
- /** Inserting new empty initial block */
- editor.ui.addInitialBlock();
-
- }
-
- editor.ui.saveInputs();
-
- editor.toolbar.close();
-
- };
-
- settings.showRemoveActions = function () {
-
- editor.toolbar.settings.actions.classList.add('opened');
-
- };
-
- settings.hideRemoveActions = function () {
-
- editor.toolbar.settings.actions.classList.remove('opened');
-
- };
-
- return settings;
-
-})({});
diff --git a/modules/toolbar/toolbar.js b/modules/toolbar/toolbar.js
deleted file mode 100644
index e59b7d681..000000000
--- a/modules/toolbar/toolbar.js
+++ /dev/null
@@ -1,133 +0,0 @@
-/**
- * Codex Editor toolbar module
- *
- * Contains:
- * - Inline toolbox
- * - Toolbox within plus button
- * - Settings section
- *
- * @author Codex Team
- * @version 1.0
- */
-
-module.exports = (function (toolbar) {
-
- let editor = codex.editor;
-
- toolbar.settings = require('./settings');
- toolbar.inline = require('./inline');
- toolbar.toolbox = require('./toolbox');
-
- /**
- * Margin between focused node and toolbar
- */
- toolbar.defaultToolbarHeight = 49;
-
- toolbar.defaultOffset = 34;
-
- toolbar.opened = false;
-
- toolbar.current = null;
-
- /**
- * @protected
- */
- toolbar.open = function () {
-
- if (editor.hideToolbar) {
-
- return;
-
- }
-
- let toolType = editor.content.currentNode.dataset.tool;
-
- if (!editor.tools[toolType] || !editor.tools[toolType].makeSettings ) {
-
- editor.nodes.showSettingsButton.classList.add('hide');
-
- } else {
-
- editor.nodes.showSettingsButton.classList.remove('hide');
-
- }
-
- editor.nodes.toolbar.classList.add('opened');
- this.opened = true;
-
- };
-
- /**
- * @protected
- */
- toolbar.close = function () {
-
- editor.nodes.toolbar.classList.remove('opened');
-
- toolbar.opened = false;
- toolbar.current = null;
-
- for (var button in editor.nodes.toolbarButtons) {
-
- editor.nodes.toolbarButtons[button].classList.remove('selected');
-
- }
-
- /** Close toolbox when toolbar is not displayed */
- editor.toolbar.toolbox.close();
- editor.toolbar.settings.close();
-
- };
-
- toolbar.toggle = function () {
-
- if ( !this.opened ) {
-
- this.open();
-
- } else {
-
- this.close();
-
- }
-
- };
-
- toolbar.hidePlusButton = function () {
-
- editor.nodes.plusButton.classList.add('hide');
-
- };
-
- toolbar.showPlusButton = function () {
-
- editor.nodes.plusButton.classList.remove('hide');
-
- };
-
- /**
- * Moving toolbar to the specified node
- */
- toolbar.move = function () {
-
- /** Close Toolbox when we move toolbar */
- editor.toolbar.toolbox.close();
-
- if (!editor.content.currentNode) {
-
- return;
-
- }
-
- var newYCoordinate = editor.content.currentNode.offsetTop - (editor.toolbar.defaultToolbarHeight / 2) + editor.toolbar.defaultOffset;
-
- editor.nodes.toolbar.style.transform = `translate3D(0, ${Math.floor(newYCoordinate)}px, 0)`;
-
- /** Close trash actions */
- editor.toolbar.settings.hideRemoveActions();
-
- };
-
- return toolbar;
-
-})({});
diff --git a/modules/toolbar/toolbox.js b/modules/toolbar/toolbox.js
deleted file mode 100644
index cec3e980e..000000000
--- a/modules/toolbar/toolbox.js
+++ /dev/null
@@ -1,191 +0,0 @@
-/**
- * Codex Editor toolbox
- *
- * All tools be able to appended here
- *
- * @author Codex Team
- * @version 1.0
- */
-
-module.exports = (function (toolbox) {
-
- let editor = codex.editor;
-
- toolbox.opened = false;
- toolbox.openedOnBlock = null;
-
- /** Shows toolbox */
- toolbox.open = function () {
-
- /** Close setting if toolbox is opened */
- if (editor.toolbar.settings.opened) {
-
- editor.toolbar.settings.close();
-
- }
-
- /** Add 'toolbar-opened' class for current block **/
- toolbox.openedOnBlock = editor.content.currentNode;
- toolbox.openedOnBlock.classList.add('toolbar-opened');
-
- /** display toolbox */
- editor.nodes.toolbox.classList.add('opened');
-
- /** Animate plus button */
- editor.nodes.plusButton.classList.add('clicked');
-
- /** toolbox state */
- editor.toolbar.toolbox.opened = true;
-
- };
-
- /** Closes toolbox */
- toolbox.close = function () {
-
- /** Remove 'toolbar-opened' class from current block **/
- if (toolbox.openedOnBlock) toolbox.openedOnBlock.classList.remove('toolbar-opened');
- toolbox.openedOnBlock = null;
-
- /** Makes toolbox disappear */
- editor.nodes.toolbox.classList.remove('opened');
-
- /** Rotate plus button */
- editor.nodes.plusButton.classList.remove('clicked');
-
- /** toolbox state */
- editor.toolbar.toolbox.opened = false;
-
- editor.toolbar.current = null;
-
- };
-
- toolbox.leaf = function () {
-
- let currentTool = editor.toolbar.current,
- tools = Object.keys(editor.tools),
- barButtons = editor.nodes.toolbarButtons,
- nextToolIndex = 0,
- toolToSelect,
- visibleTool,
- tool;
-
- if ( !currentTool ) {
-
- /** Get first tool from object*/
- for(tool in editor.tools) {
-
- if (editor.tools[tool].displayInToolbox) {
-
- break;
-
- }
-
- nextToolIndex ++;
-
- }
-
- } else {
-
- nextToolIndex = (tools.indexOf(currentTool) + 1) % tools.length;
- visibleTool = tools[nextToolIndex];
-
- while (!editor.tools[visibleTool].displayInToolbox) {
-
- nextToolIndex = (nextToolIndex + 1) % tools.length;
- visibleTool = tools[nextToolIndex];
-
- }
-
- }
-
- toolToSelect = tools[nextToolIndex];
-
- for ( var button in barButtons ) {
-
- barButtons[button].classList.remove('selected');
-
- }
-
- barButtons[toolToSelect].classList.add('selected');
- editor.toolbar.current = toolToSelect;
-
- };
-
- /**
- * Transforming selected node type into selected toolbar element type
- * @param {event} event
- */
- toolbox.toolClicked = function (event) {
-
- /**
- * UNREPLACEBLE_TOOLS this types of tools are forbidden to replace even they are empty
- */
- var UNREPLACEBLE_TOOLS = ['image', 'link', 'list', 'instagram', 'twitter', 'embed'],
- tool = editor.tools[editor.toolbar.current],
- workingNode = editor.content.currentNode,
- currentInputIndex = editor.caret.inputIndex,
- newBlockContent,
- appendCallback,
- blockData;
-
- /** Make block from plugin */
- newBlockContent = tool.render();
-
- /** information about block */
- blockData = {
- block : newBlockContent,
- type : tool.type,
- stretched : false
- };
-
- if (
- workingNode &&
- UNREPLACEBLE_TOOLS.indexOf(workingNode.dataset.tool) === -1 &&
- workingNode.textContent.trim() === ''
- ) {
-
- /** Replace current block */
- editor.content.switchBlock(workingNode, newBlockContent, tool.type);
-
- } else {
-
- /** Insert new Block from plugin */
- editor.content.insertBlock(blockData);
-
- /** increase input index */
- currentInputIndex++;
-
- }
-
- /** Fire tool append callback */
- appendCallback = tool.appendCallback;
-
- if (appendCallback && typeof appendCallback == 'function') {
-
- appendCallback.call(event);
-
- }
-
- window.setTimeout(function () {
-
- /** Set caret to current block */
- editor.caret.setToBlock(currentInputIndex);
-
- }, 10);
-
-
- /**
- * Changing current Node
- */
- editor.content.workingNodeChanged();
-
- /**
- * Move toolbar when node is changed
- */
- editor.toolbar.move();
-
- };
-
- return toolbox;
-
-})({});
\ No newline at end of file
diff --git a/modules/tools.js b/modules/tools.js
deleted file mode 100644
index 044e06747..000000000
--- a/modules/tools.js
+++ /dev/null
@@ -1,153 +0,0 @@
-/**
-* Module working with plugins
-*/
-module.exports = (function () {
-
- let editor = codex.editor;
-
- /**
- * Initialize plugins before using
- * Ex. Load scripts or call some internal methods
- * @return Promise
- */
- function prepare() {
-
- return new Promise(function (resolve_, reject_) {
-
- Promise.resolve()
-
- /**
- * Compose a sequence of plugins that requires preparation
- */
- .then(function () {
-
- let pluginsRequiresPreparation = [],
- allPlugins = editor.tools;
-
- for ( let pluginName in allPlugins ) {
-
- let plugin = allPlugins[pluginName];
-
- if (plugin.prepare && typeof plugin.prepare != 'function' || !plugin.prepare) {
-
- continue;
-
- }
-
- pluginsRequiresPreparation.push(plugin);
-
- }
-
- /**
- * If no one passed plugins requires preparation, finish prepare() and go ahead
- */
- if (!pluginsRequiresPreparation.length) {
-
- resolve_();
-
- }
-
- return pluginsRequiresPreparation;
-
- })
-
- /** Wait plugins while they prepares */
- .then(waitAllPluginsPreparation_)
-
- .then(function () {
-
- editor.core.log('Plugins loaded', 'info');
- resolve_();
-
- }).catch(function (error) {
-
- reject_(error);
-
- });
-
- });
-
- }
-
- /**
- * @param {array} plugins - list of tools that requires preparation
- * @return {Promise} resolved while all plugins will be ready or failed
- */
- function waitAllPluginsPreparation_(plugins) {
-
- /**
- * @calls allPluginsProcessed__ when all plugins prepared or failed
- */
- return new Promise (function (allPluginsProcessed__) {
-
- /**
- * pluck each element from queue
- * First, send resolved Promise as previous value
- * Each plugins "prepare" method returns a Promise, that's why
- * reduce current element will not be able to continue while can't get
- * a resolved Promise
- *
- * If last plugin is "prepared" then go to the next stage of initialization
- */
- plugins.reduce(function (previousValue, plugin, iteration) {
-
- return previousValue.then(function () {
-
- /**
- * Wait till plugins prepared
- * @calls pluginIsReady__ when plugin is ready or failed
- */
- return new Promise ( function (pluginIsReady__) {
-
- callPluginsPrepareMethod_( plugin )
-
- .then( pluginIsReady__ )
- .then( function () {
-
- plugin.available = true;
-
- })
-
- .catch(function (error) {
-
- editor.core.log(`Plugin «${plugin.type}» was not loaded. Preparation failed because %o`, 'warn', error);
- plugin.available = false;
- plugin.loadingMessage = error;
-
- /** Go ahead even some plugin has problems */
- pluginIsReady__();
-
- })
-
- .then(function () {
-
- /** If last plugin has problems then just ignore and continue */
- if (iteration == plugins.length - 1) {
-
- allPluginsProcessed__();
-
- }
-
- });
-
- });
-
- });
-
- }, Promise.resolve() );
-
- });
-
- }
-
- var callPluginsPrepareMethod_ = function (plugin) {
-
- return plugin.prepare( plugin.config || {} );
-
- };
-
- return {
- prepare: prepare
- };
-
-}());
\ No newline at end of file
diff --git a/modules/transport.js b/modules/transport.js
deleted file mode 100644
index 7f659e373..000000000
--- a/modules/transport.js
+++ /dev/null
@@ -1,136 +0,0 @@
-/**
- *
- * Codex.Editor Transport Module
- *
- * @copyright 2017 Codex-Team
- * @version 1.2.0
- */
-
-module.exports = (function (transport) {
-
- let editor = codex.editor;
-
-
- /**
- * @private {Object} current XmlHttpRequest instance
- */
- var currentRequest = null;
-
-
- /**
- * @type {null} | {DOMElement} input - keeps input element in memory
- */
- transport.input = null;
-
- /**
- * @property {Object} arguments - keep plugin settings and defined callbacks
- */
- transport.arguments = null;
-
- /**
- * Prepares input element where will be files
- */
- transport.prepare = function () {
-
- let input = editor.draw.node( 'INPUT', '', { type : 'file' } );
-
- editor.listeners.add(input, 'change', editor.transport.fileSelected);
- editor.transport.input = input;
-
- };
-
- /** Clear input when files is uploaded */
- transport.clearInput = function () {
-
- /** Remove old input */
- transport.input = null;
-
- /** Prepare new one */
- transport.prepare();
-
- };
-
- /**
- * Callback for file selection
- * @param {Event} event
- */
- transport.fileSelected = function () {
-
- var input = this,
- i,
- files = input.files,
- formData = new FormData();
-
- if (editor.transport.arguments.multiple === true) {
-
- for ( i = 0; i < files.length; i++) {
-
- formData.append('files[]', files[i], files[i].name);
-
- }
-
- } else {
-
- formData.append('files', files[0], files[0].name);
-
- }
-
- currentRequest = editor.core.ajax({
- type : 'POST',
- data : formData,
- url : editor.transport.arguments.url,
- beforeSend : editor.transport.arguments.beforeSend,
- success : editor.transport.arguments.success,
- error : editor.transport.arguments.error,
- progress : editor.transport.arguments.progress
- });
-
- /** Clear input */
- transport.clearInput();
-
- };
-
- /**
- * Use plugin callbacks
- * @protected
- *
- * @param {Object} args - can have :
- * @param {String} args.url - fetch URL
- * @param {Function} args.beforeSend - function calls before sending ajax
- * @param {Function} args.success - success callback
- * @param {Function} args.error - on error handler
- * @param {Function} args.progress - xhr onprogress handler
- * @param {Boolean} args.multiple - allow select several files
- * @param {String} args.accept - adds accept attribute
- */
- transport.selectAndUpload = function (args) {
-
- transport.arguments = args;
-
- if ( args.multiple === true) {
-
- transport.input.setAttribute('multiple', 'multiple');
-
- }
-
- if ( args.accept ) {
-
- transport.input.setAttribute('accept', args.accept);
-
- }
-
- transport.input.click();
-
- };
-
- transport.abort = function () {
-
- currentRequest.abort();
-
- currentRequest = null;
-
- };
-
- return transport;
-
-})({});
\ No newline at end of file
diff --git a/modules/ui.js b/modules/ui.js
deleted file mode 100644
index 736e8f1d1..000000000
--- a/modules/ui.js
+++ /dev/null
@@ -1,431 +0,0 @@
-/**
- * Codex Editor UI module
- *
- * @author Codex Team
- * @version 1.2.0
- */
-
-module.exports = (function (ui) {
-
- let editor = codex.editor;
-
- /**
- * Basic editor classnames
- */
- ui.className = {
-
- /**
- * @const {string} BLOCK_CLASSNAME - redactor blocks name
- */
- BLOCK_CLASSNAME : 'ce-block',
-
- /**
- * @const {String} wrapper for plugins content
- */
- BLOCK_CONTENT : 'ce-block__content',
-
- /**
- * @const {String} BLOCK_STRETCHED - makes block stretched
- */
- BLOCK_STRETCHED : 'ce-block--stretched',
-
- /**
- * @const {String} BLOCK_HIGHLIGHTED - adds background
- */
- BLOCK_HIGHLIGHTED : 'ce-block--focused',
-
- /**
- * @const {String} - for all default settings
- */
- SETTINGS_ITEM : 'ce-settings__item'
-
- };
-
- /**
- * @protected
- *
- * Making main interface
- */
- ui.prepare = function () {
-
- return new Promise(function (resolve) {
-
- let wrapper = editor.draw.wrapper(),
- redactor = editor.draw.redactor(),
- toolbar = makeToolBar_();
-
- wrapper.appendChild(toolbar);
- wrapper.appendChild(redactor);
-
- /** Save created ui-elements to static nodes state */
- editor.nodes.wrapper = wrapper;
- editor.nodes.redactor = redactor;
-
- /** Append editor wrapper with redactor zone into holder */
- editor.nodes.holder.appendChild(wrapper);
-
- resolve();
-
- })
-
- /** Add toolbox tools */
- .then(addTools_)
-
- /** Make container for inline toolbar */
- .then(makeInlineToolbar_)
-
- /** Add inline toolbar tools */
- .then(addInlineToolbarTools_)
-
- /** Draw wrapper for notifications */
- .then(makeNotificationHolder_)
-
- /** Add eventlisteners to redactor elements */
- .then(bindEvents_)
-
- .catch( function () {
-
- editor.core.log("Can't draw editor interface");
-
- });
-
- };
-
- /**
- * @private
- * Draws inline toolbar zone
- */
- var makeInlineToolbar_ = function () {
-
- var container = editor.draw.inlineToolbar();
-
- /** Append to redactor new inline block */
- editor.nodes.inlineToolbar.wrapper = container;
-
- /** Draw toolbar buttons */
- editor.nodes.inlineToolbar.buttons = editor.draw.inlineToolbarButtons();
-
- /** Buttons action or settings */
- editor.nodes.inlineToolbar.actions = editor.draw.inlineToolbarActions();
-
- /** Append to inline toolbar buttons as part of it */
- editor.nodes.inlineToolbar.wrapper.appendChild(editor.nodes.inlineToolbar.buttons);
- editor.nodes.inlineToolbar.wrapper.appendChild(editor.nodes.inlineToolbar.actions);
-
- editor.nodes.wrapper.appendChild(editor.nodes.inlineToolbar.wrapper);
-
- };
-
- var makeToolBar_ = function () {
-
- let toolbar = editor.draw.toolbar(),
- blockButtons = makeToolbarSettings_(),
- toolbarContent = makeToolbarContent_();
-
- /** Appending first-level block buttons */
- toolbar.appendChild(blockButtons);
-
- /** Append toolbarContent to toolbar */
- toolbar.appendChild(toolbarContent);
-
- /** Make toolbar global */
- editor.nodes.toolbar = toolbar;
-
- return toolbar;
-
- };
-
- var makeToolbarContent_ = function () {
-
- let toolbarContent = editor.draw.toolbarContent(),
- toolbox = editor.draw.toolbox(),
- plusButton = editor.draw.plusButton();
-
- /** Append plus button */
- toolbarContent.appendChild(plusButton);
-
- /** Appending toolbar tools */
- toolbarContent.appendChild(toolbox);
-
- /** Make Toolbox and plusButton global */
- editor.nodes.toolbox = toolbox;
- editor.nodes.plusButton = plusButton;
-
- return toolbarContent;
-
- };
-
- var makeToolbarSettings_ = function () {
-
- let blockSettings = editor.draw.blockSettings(),
- blockButtons = editor.draw.blockButtons(),
- defaultSettings = editor.draw.defaultSettings(),
- showSettingsButton = editor.draw.settingsButton(),
- showTrashButton = editor.toolbar.settings.makeRemoveBlockButton(),
- pluginSettings = editor.draw.pluginsSettings();
-
- /** Add default and plugins settings */
- blockSettings.appendChild(pluginSettings);
- blockSettings.appendChild(defaultSettings);
-
- /**
- * Make blocks buttons
- * This block contains settings button and remove block button
- */
- blockButtons.appendChild(showSettingsButton);
- blockButtons.appendChild(showTrashButton);
- blockButtons.appendChild(blockSettings);
-
- /** Make BlockSettings, PluginSettings, DefaultSettings global */
- editor.nodes.blockSettings = blockSettings;
- editor.nodes.pluginSettings = pluginSettings;
- editor.nodes.defaultSettings = defaultSettings;
- editor.nodes.showSettingsButton = showSettingsButton;
- editor.nodes.showTrashButton = showTrashButton;
-
- return blockButtons;
-
- };
-
- /** Draw notifications holder */
- var makeNotificationHolder_ = function () {
-
- /** Append block with notifications to the document */
- editor.nodes.notifications = editor.notifications.createHolder();
-
- };
-
- /**
- * @private
- * Append tools passed in editor.tools
- */
- var addTools_ = function () {
-
- var tool,
- toolName,
- toolButton;
-
- for ( toolName in editor.settings.tools ) {
-
- tool = editor.settings.tools[toolName];
-
- editor.tools[toolName] = tool;
-
- if (!tool.iconClassname && tool.displayInToolbox) {
-
- editor.core.log('Toolbar icon classname missed. Tool %o skipped', 'warn', toolName);
- continue;
-
- }
-
- if (typeof tool.render != 'function') {
-
- editor.core.log('render method missed. Tool %o skipped', 'warn', toolName);
- continue;
-
- }
-
- if (!tool.displayInToolbox) {
-
- continue;
-
- } else {
-
- /** if tools is for toolbox */
- toolButton = editor.draw.toolbarButton(toolName, tool.iconClassname);
-
- editor.nodes.toolbox.appendChild(toolButton);
-
- editor.nodes.toolbarButtons[toolName] = toolButton;
-
- }
-
- }
-
- };
-
- var addInlineToolbarTools_ = function () {
-
- var tools = {
-
- bold: {
- icon : 'ce-icon-bold',
- command : 'bold'
- },
-
- italic: {
- icon : 'ce-icon-italic',
- command : 'italic'
- },
-
- link: {
- icon : 'ce-icon-link',
- command : 'createLink'
- }
- };
-
- var toolButton,
- tool;
-
- for(var name in tools) {
-
- tool = tools[name];
-
- toolButton = editor.draw.toolbarButtonInline(name, tool.icon);
-
- editor.nodes.inlineToolbar.buttons.appendChild(toolButton);
- /**
- * Add callbacks to this buttons
- */
- editor.ui.setInlineToolbarButtonBehaviour(toolButton, tool.command);
-
- }
-
- };
-
- /**
- * @private
- * Bind editor UI events
- */
- var bindEvents_ = function () {
-
- editor.core.log('ui.bindEvents fired', 'info');
-
- // window.addEventListener('error', function (errorMsg, url, lineNumber) {
- // editor.notifications.errorThrown(errorMsg, event);
- // }, false );
-
- /** All keydowns on Document */
- editor.listeners.add(document, 'keydown', editor.callback.globalKeydown, false);
-
- /** All keydowns on Redactor zone */
- editor.listeners.add(editor.nodes.redactor, 'keydown', editor.callback.redactorKeyDown, false);
-
- /** All keydowns on Document */
- editor.listeners.add(document, 'keyup', editor.callback.globalKeyup, false );
-
- /**
- * Mouse click to radactor
- */
- editor.listeners.add(editor.nodes.redactor, 'click', editor.callback.redactorClicked, false );
-
- /**
- * Clicks to the Plus button
- */
- editor.listeners.add(editor.nodes.plusButton, 'click', editor.callback.plusButtonClicked, false);
-
- /**
- * Clicks to SETTINGS button in toolbar
- */
- editor.listeners.add(editor.nodes.showSettingsButton, 'click', editor.callback.showSettingsButtonClicked, false );
-
- /** Bind click listeners on toolbar buttons */
- for (var button in editor.nodes.toolbarButtons) {
-
- editor.listeners.add(editor.nodes.toolbarButtons[button], 'click', editor.callback.toolbarButtonClicked, false);
-
- }
-
- };
-
- ui.addBlockHandlers = function (block) {
-
- if (!block) return;
-
- /**
- * Block keydowns
- */
- editor.listeners.add(block, 'keydown', editor.callback.blockKeydown, false);
-
- /**
- * Pasting content from another source
- * We have two type of sanitization
- * First - uses deep-first search algorithm to get sub nodes,
- * sanitizes whole Block_content and replaces cleared nodes
- * This method is deprecated
- * Method is used in editor.callback.blockPaste(event)
- *
- * Secont - uses Mutation observer.
- * Observer "observe" DOM changes and send changings to callback.
- * Callback gets changed node, not whole Block_content.
- * Inserted or changed node, which we've gotten have been cleared and replaced with diry node
- *
- * Method is used in editor.callback.blockPasteViaSanitize(event)
- *
- * @uses html-janitor
- * @example editor.callback.blockPasteViaSanitize(event), the second method.
- *
- */
- editor.listeners.add(block, 'paste', editor.paste.blockPasteCallback, false);
-
- /**
- * Show inline toolbar for selected text
- */
- editor.listeners.add(block, 'mouseup', editor.toolbar.inline.show, false);
- editor.listeners.add(block, 'keyup', editor.toolbar.inline.show, false);
-
- };
-
- /** getting all contenteditable elements */
- ui.saveInputs = function () {
-
- var redactor = editor.nodes.redactor;
-
- editor.state.inputs = [];
-
- /** Save all inputs in global variable state */
- var inputs = redactor.querySelectorAll('[contenteditable], input, textarea');
-
- Array.prototype.map.call(inputs, function (current) {
-
- if (!current.type || current.type == 'text' || current.type == 'textarea') {
-
- editor.state.inputs.push(current);
-
- }
-
- });
-
- };
-
- /**
- * Adds first initial block on empty redactor
- */
- ui.addInitialBlock = function () {
-
- var initialBlockType = editor.settings.initialBlockPlugin,
- initialBlock;
-
- if ( !editor.tools[initialBlockType] ) {
-
- editor.core.log('Plugin %o was not implemented and can\'t be used as initial block', 'warn', initialBlockType);
- return;
-
- }
-
- initialBlock = editor.tools[initialBlockType].render();
-
- initialBlock.setAttribute('data-placeholder', editor.settings.placeholder);
-
- editor.content.insertBlock({
- type : initialBlockType,
- block : initialBlock
- });
-
- editor.content.workingNodeChanged(initialBlock);
-
- };
-
- ui.setInlineToolbarButtonBehaviour = function (button, type) {
-
- editor.listeners.add(button, 'mousedown', function (event) {
-
- editor.toolbar.inline.toolClicked(event, type);
-
- }, false);
-
- };
-
- return ui;
-
-})({});
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index f5d6410d3..000000000
--- a/package-lock.json
+++ /dev/null
@@ -1,5018 +0,0 @@
-{
- "name": "codex.editor",
- "version": "1.7.8",
- "lockfileVersion": 1,
- "requires": true,
- "dependencies": {
- "acorn": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz",
- "integrity": "sha512-o96FZLJBPY1lvTuJylGA9Bk3t/GKPPJG8H0ydQQl01crzwJgspa4AEIq/pVTXigmK0PHVQhiAtn8WMBLL9D2WA==",
- "dev": true
- },
- "acorn-jsx": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
- "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=",
- "dev": true,
- "requires": {
- "acorn": "3.3.0"
- },
- "dependencies": {
- "acorn": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
- "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=",
- "dev": true
- }
- }
- },
- "ajv": {
- "version": "4.11.8",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
- "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
- "dev": true,
- "requires": {
- "co": "4.6.0",
- "json-stable-stringify": "1.0.1"
- }
- },
- "ajv-keywords": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz",
- "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=",
- "dev": true
- },
- "align-text": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
- "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
- "dev": true,
- "requires": {
- "kind-of": "3.2.2",
- "longest": "1.0.1",
- "repeat-string": "1.6.1"
- }
- },
- "alphanum-sort": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz",
- "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=",
- "dev": true
- },
- "amdefine": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
- "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
- "dev": true
- },
- "ansi-escapes": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz",
- "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=",
- "dev": true
- },
- "ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
- "dev": true
- },
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
- "dev": true
- },
- "anymatch": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
- "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
- "dev": true,
- "requires": {
- "micromatch": "2.3.11",
- "normalize-path": "2.1.1"
- }
- },
- "argparse": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz",
- "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=",
- "dev": true,
- "requires": {
- "sprintf-js": "1.0.3"
- }
- },
- "arr-diff": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
- "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
- "dev": true,
- "requires": {
- "arr-flatten": "1.1.0"
- }
- },
- "arr-flatten": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
- "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
- "dev": true
- },
- "array-union": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
- "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
- "dev": true,
- "requires": {
- "array-uniq": "1.0.3"
- }
- },
- "array-uniq": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
- "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
- "dev": true
- },
- "array-unique": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
- "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
- "dev": true
- },
- "arrify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
- "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
- "dev": true
- },
- "assert": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz",
- "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=",
- "dev": true,
- "requires": {
- "util": "0.10.3"
- }
- },
- "async": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
- "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
- "dev": true
- },
- "async-each": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
- "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=",
- "dev": true
- },
- "autoprefixer": {
- "version": "6.7.7",
- "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz",
- "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=",
- "dev": true,
- "requires": {
- "browserslist": "1.7.7",
- "caniuse-db": "1.0.30000746",
- "normalize-range": "0.1.2",
- "num2fraction": "1.2.2",
- "postcss": "5.2.18",
- "postcss-value-parser": "3.3.0"
- }
- },
- "babel-code-frame": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
- "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
- "dev": true,
- "requires": {
- "chalk": "1.1.3",
- "esutils": "2.0.2",
- "js-tokens": "3.0.2"
- }
- },
- "babel-core": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz",
- "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=",
- "dev": true,
- "requires": {
- "babel-code-frame": "6.26.0",
- "babel-generator": "6.26.0",
- "babel-helpers": "6.24.1",
- "babel-messages": "6.23.0",
- "babel-register": "6.26.0",
- "babel-runtime": "6.26.0",
- "babel-template": "6.26.0",
- "babel-traverse": "6.26.0",
- "babel-types": "6.26.0",
- "babylon": "6.18.0",
- "convert-source-map": "1.5.0",
- "debug": "2.6.9",
- "json5": "0.5.1",
- "lodash": "4.17.4",
- "minimatch": "3.0.4",
- "path-is-absolute": "1.0.1",
- "private": "0.1.7",
- "slash": "1.0.0",
- "source-map": "0.5.7"
- }
- },
- "babel-generator": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz",
- "integrity": "sha1-rBriAHC3n248odMmlhMFN3TyDcU=",
- "dev": true,
- "requires": {
- "babel-messages": "6.23.0",
- "babel-runtime": "6.26.0",
- "babel-types": "6.26.0",
- "detect-indent": "4.0.0",
- "jsesc": "1.3.0",
- "lodash": "4.17.4",
- "source-map": "0.5.7",
- "trim-right": "1.0.1"
- }
- },
- "babel-helper-call-delegate": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz",
- "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=",
- "dev": true,
- "requires": {
- "babel-helper-hoist-variables": "6.24.1",
- "babel-runtime": "6.26.0",
- "babel-traverse": "6.26.0",
- "babel-types": "6.26.0"
- }
- },
- "babel-helper-define-map": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz",
- "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=",
- "dev": true,
- "requires": {
- "babel-helper-function-name": "6.24.1",
- "babel-runtime": "6.26.0",
- "babel-types": "6.26.0",
- "lodash": "4.17.4"
- }
- },
- "babel-helper-function-name": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
- "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=",
- "dev": true,
- "requires": {
- "babel-helper-get-function-arity": "6.24.1",
- "babel-runtime": "6.26.0",
- "babel-template": "6.26.0",
- "babel-traverse": "6.26.0",
- "babel-types": "6.26.0"
- }
- },
- "babel-helper-get-function-arity": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz",
- "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0",
- "babel-types": "6.26.0"
- }
- },
- "babel-helper-hoist-variables": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz",
- "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0",
- "babel-types": "6.26.0"
- }
- },
- "babel-helper-optimise-call-expression": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz",
- "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0",
- "babel-types": "6.26.0"
- }
- },
- "babel-helper-regex": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz",
- "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0",
- "babel-types": "6.26.0",
- "lodash": "4.17.4"
- }
- },
- "babel-helper-replace-supers": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz",
- "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=",
- "dev": true,
- "requires": {
- "babel-helper-optimise-call-expression": "6.24.1",
- "babel-messages": "6.23.0",
- "babel-runtime": "6.26.0",
- "babel-template": "6.26.0",
- "babel-traverse": "6.26.0",
- "babel-types": "6.26.0"
- }
- },
- "babel-helpers": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
- "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0",
- "babel-template": "6.26.0"
- }
- },
- "babel-loader": {
- "version": "6.4.1",
- "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-6.4.1.tgz",
- "integrity": "sha1-CzQRLVsHSKjc2/Uaz2+b1C1QuMo=",
- "dev": true,
- "requires": {
- "find-cache-dir": "0.1.1",
- "loader-utils": "0.2.17",
- "mkdirp": "0.5.1",
- "object-assign": "4.1.1"
- }
- },
- "babel-messages": {
- "version": "6.23.0",
- "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
- "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0"
- }
- },
- "babel-plugin-check-es2015-constants": {
- "version": "6.22.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz",
- "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-arrow-functions": {
- "version": "6.22.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
- "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-block-scoped-functions": {
- "version": "6.22.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz",
- "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-block-scoping": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz",
- "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0",
- "babel-template": "6.26.0",
- "babel-traverse": "6.26.0",
- "babel-types": "6.26.0",
- "lodash": "4.17.4"
- }
- },
- "babel-plugin-transform-es2015-classes": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz",
- "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=",
- "dev": true,
- "requires": {
- "babel-helper-define-map": "6.26.0",
- "babel-helper-function-name": "6.24.1",
- "babel-helper-optimise-call-expression": "6.24.1",
- "babel-helper-replace-supers": "6.24.1",
- "babel-messages": "6.23.0",
- "babel-runtime": "6.26.0",
- "babel-template": "6.26.0",
- "babel-traverse": "6.26.0",
- "babel-types": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-computed-properties": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz",
- "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0",
- "babel-template": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-destructuring": {
- "version": "6.23.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz",
- "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-duplicate-keys": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz",
- "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0",
- "babel-types": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-for-of": {
- "version": "6.23.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz",
- "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-function-name": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz",
- "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=",
- "dev": true,
- "requires": {
- "babel-helper-function-name": "6.24.1",
- "babel-runtime": "6.26.0",
- "babel-types": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-literals": {
- "version": "6.22.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz",
- "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-modules-amd": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz",
- "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=",
- "dev": true,
- "requires": {
- "babel-plugin-transform-es2015-modules-commonjs": "6.26.0",
- "babel-runtime": "6.26.0",
- "babel-template": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-modules-commonjs": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz",
- "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=",
- "dev": true,
- "requires": {
- "babel-plugin-transform-strict-mode": "6.24.1",
- "babel-runtime": "6.26.0",
- "babel-template": "6.26.0",
- "babel-types": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-modules-systemjs": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz",
- "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=",
- "dev": true,
- "requires": {
- "babel-helper-hoist-variables": "6.24.1",
- "babel-runtime": "6.26.0",
- "babel-template": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-modules-umd": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz",
- "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=",
- "dev": true,
- "requires": {
- "babel-plugin-transform-es2015-modules-amd": "6.24.1",
- "babel-runtime": "6.26.0",
- "babel-template": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-object-super": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz",
- "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=",
- "dev": true,
- "requires": {
- "babel-helper-replace-supers": "6.24.1",
- "babel-runtime": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-parameters": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz",
- "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=",
- "dev": true,
- "requires": {
- "babel-helper-call-delegate": "6.24.1",
- "babel-helper-get-function-arity": "6.24.1",
- "babel-runtime": "6.26.0",
- "babel-template": "6.26.0",
- "babel-traverse": "6.26.0",
- "babel-types": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-shorthand-properties": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz",
- "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0",
- "babel-types": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-spread": {
- "version": "6.22.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz",
- "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-sticky-regex": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz",
- "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=",
- "dev": true,
- "requires": {
- "babel-helper-regex": "6.26.0",
- "babel-runtime": "6.26.0",
- "babel-types": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-template-literals": {
- "version": "6.22.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz",
- "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-typeof-symbol": {
- "version": "6.23.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz",
- "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0"
- }
- },
- "babel-plugin-transform-es2015-unicode-regex": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz",
- "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=",
- "dev": true,
- "requires": {
- "babel-helper-regex": "6.26.0",
- "babel-runtime": "6.26.0",
- "regexpu-core": "2.0.0"
- }
- },
- "babel-plugin-transform-regenerator": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz",
- "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=",
- "dev": true,
- "requires": {
- "regenerator-transform": "0.10.1"
- }
- },
- "babel-plugin-transform-strict-mode": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz",
- "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0",
- "babel-types": "6.26.0"
- }
- },
- "babel-polyfill": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz",
- "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0",
- "core-js": "2.5.1",
- "regenerator-runtime": "0.10.5"
- },
- "dependencies": {
- "regenerator-runtime": {
- "version": "0.10.5",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
- "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=",
- "dev": true
- }
- }
- },
- "babel-preset-es2015": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz",
- "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=",
- "dev": true,
- "requires": {
- "babel-plugin-check-es2015-constants": "6.22.0",
- "babel-plugin-transform-es2015-arrow-functions": "6.22.0",
- "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0",
- "babel-plugin-transform-es2015-block-scoping": "6.26.0",
- "babel-plugin-transform-es2015-classes": "6.24.1",
- "babel-plugin-transform-es2015-computed-properties": "6.24.1",
- "babel-plugin-transform-es2015-destructuring": "6.23.0",
- "babel-plugin-transform-es2015-duplicate-keys": "6.24.1",
- "babel-plugin-transform-es2015-for-of": "6.23.0",
- "babel-plugin-transform-es2015-function-name": "6.24.1",
- "babel-plugin-transform-es2015-literals": "6.22.0",
- "babel-plugin-transform-es2015-modules-amd": "6.24.1",
- "babel-plugin-transform-es2015-modules-commonjs": "6.26.0",
- "babel-plugin-transform-es2015-modules-systemjs": "6.24.1",
- "babel-plugin-transform-es2015-modules-umd": "6.24.1",
- "babel-plugin-transform-es2015-object-super": "6.24.1",
- "babel-plugin-transform-es2015-parameters": "6.24.1",
- "babel-plugin-transform-es2015-shorthand-properties": "6.24.1",
- "babel-plugin-transform-es2015-spread": "6.22.0",
- "babel-plugin-transform-es2015-sticky-regex": "6.24.1",
- "babel-plugin-transform-es2015-template-literals": "6.22.0",
- "babel-plugin-transform-es2015-typeof-symbol": "6.23.0",
- "babel-plugin-transform-es2015-unicode-regex": "6.24.1",
- "babel-plugin-transform-regenerator": "6.26.0"
- }
- },
- "babel-register": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
- "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=",
- "dev": true,
- "requires": {
- "babel-core": "6.26.0",
- "babel-runtime": "6.26.0",
- "core-js": "2.5.1",
- "home-or-tmp": "2.0.0",
- "lodash": "4.17.4",
- "mkdirp": "0.5.1",
- "source-map-support": "0.4.18"
- }
- },
- "babel-runtime": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
- "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
- "dev": true,
- "requires": {
- "core-js": "2.5.1",
- "regenerator-runtime": "0.11.0"
- }
- },
- "babel-template": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
- "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0",
- "babel-traverse": "6.26.0",
- "babel-types": "6.26.0",
- "babylon": "6.18.0",
- "lodash": "4.17.4"
- }
- },
- "babel-traverse": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
- "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
- "dev": true,
- "requires": {
- "babel-code-frame": "6.26.0",
- "babel-messages": "6.23.0",
- "babel-runtime": "6.26.0",
- "babel-types": "6.26.0",
- "babylon": "6.18.0",
- "debug": "2.6.9",
- "globals": "9.18.0",
- "invariant": "2.2.2",
- "lodash": "4.17.4"
- }
- },
- "babel-types": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
- "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0",
- "esutils": "2.0.2",
- "lodash": "4.17.4",
- "to-fast-properties": "1.0.3"
- }
- },
- "babylon": {
- "version": "6.18.0",
- "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
- "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
- "dev": true
- },
- "balanced-match": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
- "dev": true
- },
- "base64-js": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz",
- "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==",
- "dev": true
- },
- "big.js": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz",
- "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==",
- "dev": true
- },
- "binary-extensions": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.10.0.tgz",
- "integrity": "sha1-muuabF6IY4qtFx4Wf1kAq+JINdA=",
- "dev": true
- },
- "brace-expansion": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
- "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
- "dev": true,
- "requires": {
- "balanced-match": "1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "braces": {
- "version": "1.8.5",
- "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
- "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
- "dev": true,
- "requires": {
- "expand-range": "1.8.2",
- "preserve": "0.2.0",
- "repeat-element": "1.1.2"
- }
- },
- "browserify-aes": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-0.4.0.tgz",
- "integrity": "sha1-BnFJtmjfMcS1hTPgLQHoBthgjiw=",
- "dev": true,
- "requires": {
- "inherits": "2.0.3"
- }
- },
- "browserify-zlib": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz",
- "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=",
- "dev": true,
- "requires": {
- "pako": "0.2.9"
- }
- },
- "browserslist": {
- "version": "1.7.7",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
- "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
- "dev": true,
- "requires": {
- "caniuse-db": "1.0.30000746",
- "electron-to-chromium": "1.3.26"
- }
- },
- "buffer": {
- "version": "4.9.1",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
- "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
- "dev": true,
- "requires": {
- "base64-js": "1.2.1",
- "ieee754": "1.1.8",
- "isarray": "1.0.0"
- }
- },
- "builtin-status-codes": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
- "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
- "dev": true
- },
- "caller-path": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
- "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
- "dev": true,
- "requires": {
- "callsites": "0.2.0"
- }
- },
- "callsites": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
- "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
- "dev": true
- },
- "camelcase": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
- "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
- "dev": true
- },
- "caniuse-api": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz",
- "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=",
- "dev": true,
- "requires": {
- "browserslist": "1.7.7",
- "caniuse-db": "1.0.30000746",
- "lodash.memoize": "4.1.2",
- "lodash.uniq": "4.5.0"
- }
- },
- "caniuse-db": {
- "version": "1.0.30000746",
- "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000746.tgz",
- "integrity": "sha1-UBCYxm9fu/Y0wC8lUIsF6ICZEPQ=",
- "dev": true
- },
- "center-align": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
- "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
- "dev": true,
- "requires": {
- "align-text": "0.1.4",
- "lazy-cache": "1.0.4"
- }
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true,
- "requires": {
- "ansi-styles": "2.2.1",
- "escape-string-regexp": "1.0.5",
- "has-ansi": "2.0.0",
- "strip-ansi": "3.0.1",
- "supports-color": "2.0.0"
- }
- },
- "chokidar": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
- "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
- "dev": true,
- "requires": {
- "anymatch": "1.3.2",
- "async-each": "1.0.1",
- "fsevents": "1.1.2",
- "glob-parent": "2.0.0",
- "inherits": "2.0.3",
- "is-binary-path": "1.0.1",
- "is-glob": "2.0.1",
- "path-is-absolute": "1.0.1",
- "readdirp": "2.1.0"
- }
- },
- "circular-json": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
- "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==",
- "dev": true
- },
- "clap": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz",
- "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==",
- "dev": true,
- "requires": {
- "chalk": "1.1.3"
- }
- },
- "cli-cursor": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz",
- "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=",
- "dev": true,
- "requires": {
- "restore-cursor": "1.0.1"
- }
- },
- "cli-width": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
- "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
- "dev": true
- },
- "cliui": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
- "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
- "dev": true,
- "requires": {
- "center-align": "0.1.3",
- "right-align": "0.1.3",
- "wordwrap": "0.0.2"
- },
- "dependencies": {
- "wordwrap": {
- "version": "0.0.2",
- "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
- "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
- "dev": true
- }
- }
- },
- "clone": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz",
- "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=",
- "dev": true
- },
- "co": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
- "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
- "dev": true
- },
- "coa": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz",
- "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=",
- "dev": true,
- "requires": {
- "q": "1.5.0"
- }
- },
- "code-point-at": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
- "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
- "dev": true
- },
- "color": {
- "version": "0.11.4",
- "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz",
- "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=",
- "dev": true,
- "requires": {
- "clone": "1.0.2",
- "color-convert": "1.9.0",
- "color-string": "0.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz",
- "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=",
- "dev": true,
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
- "dev": true
- },
- "color-string": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz",
- "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=",
- "dev": true,
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "colormin": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz",
- "integrity": "sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=",
- "dev": true,
- "requires": {
- "color": "0.11.4",
- "css-color-names": "0.0.4",
- "has": "1.0.1"
- }
- },
- "colors": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
- "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
- "dev": true
- },
- "commondir": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
- "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
- "dev": true
- },
- "concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
- "dev": true
- },
- "concat-stream": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz",
- "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=",
- "dev": true,
- "requires": {
- "inherits": "2.0.3",
- "readable-stream": "2.3.3",
- "typedarray": "0.0.6"
- }
- },
- "console-browserify": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
- "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
- "dev": true,
- "requires": {
- "date-now": "0.1.4"
- }
- },
- "constants-browserify": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
- "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
- "dev": true
- },
- "convert-source-map": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz",
- "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=",
- "dev": true
- },
- "core-js": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz",
- "integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=",
- "dev": true
- },
- "core-util-is": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
- "dev": true
- },
- "crypto-browserify": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.3.0.tgz",
- "integrity": "sha1-ufx1u0oO1h3PHNXa6W6zDJw+UGw=",
- "dev": true,
- "requires": {
- "browserify-aes": "0.4.0",
- "pbkdf2-compat": "2.0.1",
- "ripemd160": "0.2.0",
- "sha.js": "2.2.6"
- }
- },
- "css-color-names": {
- "version": "0.0.4",
- "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
- "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=",
- "dev": true
- },
- "css-loader": {
- "version": "0.26.4",
- "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.26.4.tgz",
- "integrity": "sha1-th6eMNuUMD5v/IkvEOzQmtAlof0=",
- "dev": true,
- "requires": {
- "babel-code-frame": "6.26.0",
- "css-selector-tokenizer": "0.7.0",
- "cssnano": "3.10.0",
- "loader-utils": "1.1.0",
- "lodash.camelcase": "4.3.0",
- "object-assign": "4.1.1",
- "postcss": "5.2.18",
- "postcss-modules-extract-imports": "1.1.0",
- "postcss-modules-local-by-default": "1.2.0",
- "postcss-modules-scope": "1.1.0",
- "postcss-modules-values": "1.3.0",
- "source-list-map": "0.1.8"
- },
- "dependencies": {
- "loader-utils": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz",
- "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=",
- "dev": true,
- "requires": {
- "big.js": "3.2.0",
- "emojis-list": "2.1.0",
- "json5": "0.5.1"
- }
- }
- }
- },
- "css-selector-tokenizer": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz",
- "integrity": "sha1-5piEdK6MlTR3v15+/s/OzNnPTIY=",
- "dev": true,
- "requires": {
- "cssesc": "0.1.0",
- "fastparse": "1.1.1",
- "regexpu-core": "1.0.0"
- },
- "dependencies": {
- "regexpu-core": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz",
- "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=",
- "dev": true,
- "requires": {
- "regenerate": "1.3.3",
- "regjsgen": "0.2.0",
- "regjsparser": "0.1.5"
- }
- }
- }
- },
- "cssesc": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz",
- "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=",
- "dev": true
- },
- "cssnano": {
- "version": "3.10.0",
- "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz",
- "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=",
- "dev": true,
- "requires": {
- "autoprefixer": "6.7.7",
- "decamelize": "1.2.0",
- "defined": "1.0.0",
- "has": "1.0.1",
- "object-assign": "4.1.1",
- "postcss": "5.2.18",
- "postcss-calc": "5.3.1",
- "postcss-colormin": "2.2.2",
- "postcss-convert-values": "2.6.1",
- "postcss-discard-comments": "2.0.4",
- "postcss-discard-duplicates": "2.1.0",
- "postcss-discard-empty": "2.1.0",
- "postcss-discard-overridden": "0.1.1",
- "postcss-discard-unused": "2.2.3",
- "postcss-filter-plugins": "2.0.2",
- "postcss-merge-idents": "2.1.7",
- "postcss-merge-longhand": "2.0.2",
- "postcss-merge-rules": "2.1.2",
- "postcss-minify-font-values": "1.0.5",
- "postcss-minify-gradients": "1.0.5",
- "postcss-minify-params": "1.2.2",
- "postcss-minify-selectors": "2.1.1",
- "postcss-normalize-charset": "1.1.1",
- "postcss-normalize-url": "3.0.8",
- "postcss-ordered-values": "2.2.3",
- "postcss-reduce-idents": "2.4.0",
- "postcss-reduce-initial": "1.0.1",
- "postcss-reduce-transforms": "1.0.4",
- "postcss-svgo": "2.1.6",
- "postcss-unique-selectors": "2.0.2",
- "postcss-value-parser": "3.3.0",
- "postcss-zindex": "2.2.0"
- }
- },
- "csso": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz",
- "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=",
- "dev": true,
- "requires": {
- "clap": "1.2.3",
- "source-map": "0.5.7"
- }
- },
- "d": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
- "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
- "dev": true,
- "requires": {
- "es5-ext": "0.10.31"
- }
- },
- "date-now": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
- "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=",
- "dev": true
- },
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "requires": {
- "ms": "2.0.0"
- }
- },
- "decamelize": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
- "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
- "dev": true
- },
- "deep-is": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
- "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
- "dev": true
- },
- "defined": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
- "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
- "dev": true
- },
- "del": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
- "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
- "dev": true,
- "requires": {
- "globby": "5.0.0",
- "is-path-cwd": "1.0.0",
- "is-path-in-cwd": "1.0.0",
- "object-assign": "4.1.1",
- "pify": "2.3.0",
- "pinkie-promise": "2.0.1",
- "rimraf": "2.6.2"
- }
- },
- "detect-indent": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
- "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=",
- "dev": true,
- "requires": {
- "repeating": "2.0.1"
- }
- },
- "doctrine": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz",
- "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=",
- "dev": true,
- "requires": {
- "esutils": "2.0.2",
- "isarray": "1.0.0"
- }
- },
- "domain-browser": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz",
- "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw=",
- "dev": true
- },
- "electron-to-chromium": {
- "version": "1.3.26",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.26.tgz",
- "integrity": "sha1-mWQnKUhhp02cfIK5Jg6jAejALWY=",
- "dev": true
- },
- "emojis-list": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
- "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
- "dev": true
- },
- "enhanced-resolve": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz",
- "integrity": "sha1-TW5omzcl+GCQknzMhs2fFjW4ni4=",
- "dev": true,
- "requires": {
- "graceful-fs": "4.1.11",
- "memory-fs": "0.2.0",
- "tapable": "0.1.10"
- },
- "dependencies": {
- "memory-fs": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz",
- "integrity": "sha1-8rslNovBIeORwlIN6Slpyu4KApA=",
- "dev": true
- }
- }
- },
- "errno": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz",
- "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=",
- "dev": true,
- "requires": {
- "prr": "0.0.0"
- }
- },
- "es5-ext": {
- "version": "0.10.31",
- "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.31.tgz",
- "integrity": "sha1-e7k4yVp/G59ygJLcCcQe3MOY7v4=",
- "dev": true,
- "requires": {
- "es6-iterator": "2.0.1",
- "es6-symbol": "3.1.1"
- }
- },
- "es6-iterator": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz",
- "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=",
- "dev": true,
- "requires": {
- "d": "1.0.0",
- "es5-ext": "0.10.31",
- "es6-symbol": "3.1.1"
- }
- },
- "es6-map": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz",
- "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=",
- "dev": true,
- "requires": {
- "d": "1.0.0",
- "es5-ext": "0.10.31",
- "es6-iterator": "2.0.1",
- "es6-set": "0.1.5",
- "es6-symbol": "3.1.1",
- "event-emitter": "0.3.5"
- }
- },
- "es6-set": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz",
- "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=",
- "dev": true,
- "requires": {
- "d": "1.0.0",
- "es5-ext": "0.10.31",
- "es6-iterator": "2.0.1",
- "es6-symbol": "3.1.1",
- "event-emitter": "0.3.5"
- }
- },
- "es6-symbol": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
- "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
- "dev": true,
- "requires": {
- "d": "1.0.0",
- "es5-ext": "0.10.31"
- }
- },
- "es6-weak-map": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz",
- "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",
- "dev": true,
- "requires": {
- "d": "1.0.0",
- "es5-ext": "0.10.31",
- "es6-iterator": "2.0.1",
- "es6-symbol": "3.1.1"
- }
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
- "dev": true
- },
- "escope": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz",
- "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=",
- "dev": true,
- "requires": {
- "es6-map": "0.1.5",
- "es6-weak-map": "2.0.2",
- "esrecurse": "4.2.0",
- "estraverse": "4.2.0"
- }
- },
- "eslint": {
- "version": "3.19.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz",
- "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=",
- "dev": true,
- "requires": {
- "babel-code-frame": "6.26.0",
- "chalk": "1.1.3",
- "concat-stream": "1.6.0",
- "debug": "2.6.9",
- "doctrine": "2.0.0",
- "escope": "3.6.0",
- "espree": "3.5.1",
- "esquery": "1.0.0",
- "estraverse": "4.2.0",
- "esutils": "2.0.2",
- "file-entry-cache": "2.0.0",
- "glob": "7.1.2",
- "globals": "9.18.0",
- "ignore": "3.3.5",
- "imurmurhash": "0.1.4",
- "inquirer": "0.12.0",
- "is-my-json-valid": "2.16.1",
- "is-resolvable": "1.0.0",
- "js-yaml": "3.7.0",
- "json-stable-stringify": "1.0.1",
- "levn": "0.3.0",
- "lodash": "4.17.4",
- "mkdirp": "0.5.1",
- "natural-compare": "1.4.0",
- "optionator": "0.8.2",
- "path-is-inside": "1.0.2",
- "pluralize": "1.2.1",
- "progress": "1.1.8",
- "require-uncached": "1.0.3",
- "shelljs": "0.7.8",
- "strip-bom": "3.0.0",
- "strip-json-comments": "2.0.1",
- "table": "3.8.3",
- "text-table": "0.2.0",
- "user-home": "2.0.0"
- }
- },
- "eslint-loader": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-1.9.0.tgz",
- "integrity": "sha512-40aN976qSNPyb9ejTqjEthZITpls1SVKtwguahmH1dzGCwQU/vySE+xX33VZmD8csU0ahVNCtFlsPgKqRBiqgg==",
- "dev": true,
- "requires": {
- "loader-fs-cache": "1.0.1",
- "loader-utils": "1.1.0",
- "object-assign": "4.1.1",
- "object-hash": "1.2.0",
- "rimraf": "2.6.2"
- },
- "dependencies": {
- "loader-utils": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz",
- "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=",
- "dev": true,
- "requires": {
- "big.js": "3.2.0",
- "emojis-list": "2.1.0",
- "json5": "0.5.1"
- }
- }
- }
- },
- "espree": {
- "version": "3.5.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.1.tgz",
- "integrity": "sha1-DJiLirRttTEAoZVK5LqZXd0n2H4=",
- "dev": true,
- "requires": {
- "acorn": "5.1.2",
- "acorn-jsx": "3.0.1"
- }
- },
- "esprima": {
- "version": "2.7.3",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
- "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=",
- "dev": true
- },
- "esquery": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz",
- "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=",
- "dev": true,
- "requires": {
- "estraverse": "4.2.0"
- }
- },
- "esrecurse": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz",
- "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=",
- "dev": true,
- "requires": {
- "estraverse": "4.2.0",
- "object-assign": "4.1.1"
- }
- },
- "estraverse": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
- "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
- "dev": true
- },
- "esutils": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
- "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
- "dev": true
- },
- "event-emitter": {
- "version": "0.3.5",
- "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
- "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
- "dev": true,
- "requires": {
- "d": "1.0.0",
- "es5-ext": "0.10.31"
- }
- },
- "events": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
- "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=",
- "dev": true
- },
- "exit-hook": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz",
- "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=",
- "dev": true
- },
- "expand-brackets": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
- "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
- "dev": true,
- "requires": {
- "is-posix-bracket": "0.1.1"
- }
- },
- "expand-range": {
- "version": "1.8.2",
- "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
- "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
- "dev": true,
- "requires": {
- "fill-range": "2.2.3"
- }
- },
- "extglob": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
- "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
- "dev": true,
- "requires": {
- "is-extglob": "1.0.0"
- }
- },
- "extract-text-webpack-plugin": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-1.0.1.tgz",
- "integrity": "sha1-yVvzy6rEnclvHcbgclSfu2VMzSw=",
- "dev": true,
- "requires": {
- "async": "1.5.2",
- "loader-utils": "0.2.17",
- "webpack-sources": "0.1.5"
- }
- },
- "fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
- "dev": true
- },
- "fastparse": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz",
- "integrity": "sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg=",
- "dev": true
- },
- "figures": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
- "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
- "dev": true,
- "requires": {
- "escape-string-regexp": "1.0.5",
- "object-assign": "4.1.1"
- }
- },
- "file-entry-cache": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
- "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
- "dev": true,
- "requires": {
- "flat-cache": "1.3.0",
- "object-assign": "4.1.1"
- }
- },
- "filename-regex": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
- "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
- "dev": true
- },
- "fill-range": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz",
- "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=",
- "dev": true,
- "requires": {
- "is-number": "2.1.0",
- "isobject": "2.1.0",
- "randomatic": "1.1.7",
- "repeat-element": "1.1.2",
- "repeat-string": "1.6.1"
- }
- },
- "find-cache-dir": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz",
- "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=",
- "dev": true,
- "requires": {
- "commondir": "1.0.1",
- "mkdirp": "0.5.1",
- "pkg-dir": "1.0.0"
- }
- },
- "find-up": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
- "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
- "dev": true,
- "requires": {
- "path-exists": "2.1.0",
- "pinkie-promise": "2.0.1"
- }
- },
- "flat-cache": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz",
- "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=",
- "dev": true,
- "requires": {
- "circular-json": "0.3.3",
- "del": "2.2.2",
- "graceful-fs": "4.1.11",
- "write": "0.2.1"
- }
- },
- "flatten": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz",
- "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=",
- "dev": true
- },
- "for-in": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
- "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
- "dev": true
- },
- "for-own": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
- "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
- "dev": true,
- "requires": {
- "for-in": "1.0.2"
- }
- },
- "fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
- "dev": true
- },
- "fsevents": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz",
- "integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==",
- "dev": true,
- "optional": true,
- "requires": {
- "nan": "2.7.0",
- "node-pre-gyp": "0.6.36"
- },
- "dependencies": {
- "abbrev": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "ajv": {
- "version": "4.11.8",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "co": "4.6.0",
- "json-stable-stringify": "1.0.1"
- }
- },
- "ansi-regex": {
- "version": "2.1.1",
- "bundled": true,
- "dev": true
- },
- "aproba": {
- "version": "1.1.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "are-we-there-yet": {
- "version": "1.1.4",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "delegates": "1.0.0",
- "readable-stream": "2.2.9"
- }
- },
- "asn1": {
- "version": "0.2.3",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "assert-plus": {
- "version": "0.2.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "asynckit": {
- "version": "0.4.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "aws-sign2": {
- "version": "0.6.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "aws4": {
- "version": "1.6.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "balanced-match": {
- "version": "0.4.2",
- "bundled": true,
- "dev": true
- },
- "bcrypt-pbkdf": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "tweetnacl": "0.14.5"
- }
- },
- "block-stream": {
- "version": "0.0.9",
- "bundled": true,
- "dev": true,
- "requires": {
- "inherits": "2.0.3"
- }
- },
- "boom": {
- "version": "2.10.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "hoek": "2.16.3"
- }
- },
- "brace-expansion": {
- "version": "1.1.7",
- "bundled": true,
- "dev": true,
- "requires": {
- "balanced-match": "0.4.2",
- "concat-map": "0.0.1"
- }
- },
- "buffer-shims": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "caseless": {
- "version": "0.12.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "co": {
- "version": "4.6.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "code-point-at": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true
- },
- "combined-stream": {
- "version": "1.0.5",
- "bundled": true,
- "dev": true,
- "requires": {
- "delayed-stream": "1.0.0"
- }
- },
- "concat-map": {
- "version": "0.0.1",
- "bundled": true,
- "dev": true
- },
- "console-control-strings": {
- "version": "1.1.0",
- "bundled": true,
- "dev": true
- },
- "core-util-is": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- },
- "cryptiles": {
- "version": "2.0.5",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "boom": "2.10.1"
- }
- },
- "dashdash": {
- "version": "1.14.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "assert-plus": "1.0.0"
- },
- "dependencies": {
- "assert-plus": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true,
- "optional": true
- }
- }
- },
- "debug": {
- "version": "2.6.8",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "ms": "2.0.0"
- }
- },
- "deep-extend": {
- "version": "0.4.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "delayed-stream": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "delegates": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "ecc-jsbn": {
- "version": "0.1.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "jsbn": "0.1.1"
- }
- },
- "extend": {
- "version": "3.0.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "extsprintf": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- },
- "forever-agent": {
- "version": "0.6.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "form-data": {
- "version": "2.1.4",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "asynckit": "0.4.0",
- "combined-stream": "1.0.5",
- "mime-types": "2.1.15"
- }
- },
- "fs.realpath": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "fstream": {
- "version": "1.0.11",
- "bundled": true,
- "dev": true,
- "requires": {
- "graceful-fs": "4.1.11",
- "inherits": "2.0.3",
- "mkdirp": "0.5.1",
- "rimraf": "2.6.1"
- }
- },
- "fstream-ignore": {
- "version": "1.0.5",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "fstream": "1.0.11",
- "inherits": "2.0.3",
- "minimatch": "3.0.4"
- }
- },
- "gauge": {
- "version": "2.7.4",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "aproba": "1.1.1",
- "console-control-strings": "1.1.0",
- "has-unicode": "2.0.1",
- "object-assign": "4.1.1",
- "signal-exit": "3.0.2",
- "string-width": "1.0.2",
- "strip-ansi": "3.0.1",
- "wide-align": "1.1.2"
- }
- },
- "getpass": {
- "version": "0.1.7",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "assert-plus": "1.0.0"
- },
- "dependencies": {
- "assert-plus": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true,
- "optional": true
- }
- }
- },
- "glob": {
- "version": "7.1.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "fs.realpath": "1.0.0",
- "inflight": "1.0.6",
- "inherits": "2.0.3",
- "minimatch": "3.0.4",
- "once": "1.4.0",
- "path-is-absolute": "1.0.1"
- }
- },
- "graceful-fs": {
- "version": "4.1.11",
- "bundled": true,
- "dev": true
- },
- "har-schema": {
- "version": "1.0.5",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "har-validator": {
- "version": "4.2.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "ajv": "4.11.8",
- "har-schema": "1.0.5"
- }
- },
- "has-unicode": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "hawk": {
- "version": "3.1.3",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "boom": "2.10.1",
- "cryptiles": "2.0.5",
- "hoek": "2.16.3",
- "sntp": "1.0.9"
- }
- },
- "hoek": {
- "version": "2.16.3",
- "bundled": true,
- "dev": true
- },
- "http-signature": {
- "version": "1.1.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "assert-plus": "0.2.0",
- "jsprim": "1.4.0",
- "sshpk": "1.13.0"
- }
- },
- "inflight": {
- "version": "1.0.6",
- "bundled": true,
- "dev": true,
- "requires": {
- "once": "1.4.0",
- "wrappy": "1.0.2"
- }
- },
- "inherits": {
- "version": "2.0.3",
- "bundled": true,
- "dev": true
- },
- "ini": {
- "version": "1.3.4",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "is-fullwidth-code-point": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "number-is-nan": "1.0.1"
- }
- },
- "is-typedarray": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "isarray": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true
- },
- "isstream": {
- "version": "0.1.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "jodid25519": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "jsbn": "0.1.1"
- }
- },
- "jsbn": {
- "version": "0.1.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "json-schema": {
- "version": "0.2.3",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "json-stable-stringify": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "jsonify": "0.0.0"
- }
- },
- "json-stringify-safe": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "jsonify": {
- "version": "0.0.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "jsprim": {
- "version": "1.4.0",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "assert-plus": "1.0.0",
- "extsprintf": "1.0.2",
- "json-schema": "0.2.3",
- "verror": "1.3.6"
- },
- "dependencies": {
- "assert-plus": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true,
- "optional": true
- }
- }
- },
- "mime-db": {
- "version": "1.27.0",
- "bundled": true,
- "dev": true
- },
- "mime-types": {
- "version": "2.1.15",
- "bundled": true,
- "dev": true,
- "requires": {
- "mime-db": "1.27.0"
- }
- },
- "minimatch": {
- "version": "3.0.4",
- "bundled": true,
- "dev": true,
- "requires": {
- "brace-expansion": "1.1.7"
- }
- },
- "minimist": {
- "version": "0.0.8",
- "bundled": true,
- "dev": true
- },
- "mkdirp": {
- "version": "0.5.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "minimist": "0.0.8"
- }
- },
- "ms": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "node-pre-gyp": {
- "version": "0.6.36",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "mkdirp": "0.5.1",
- "nopt": "4.0.1",
- "npmlog": "4.1.0",
- "rc": "1.2.1",
- "request": "2.81.0",
- "rimraf": "2.6.1",
- "semver": "5.3.0",
- "tar": "2.2.1",
- "tar-pack": "3.4.0"
- }
- },
- "nopt": {
- "version": "4.0.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "abbrev": "1.1.0",
- "osenv": "0.1.4"
- }
- },
- "npmlog": {
- "version": "4.1.0",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "are-we-there-yet": "1.1.4",
- "console-control-strings": "1.1.0",
- "gauge": "2.7.4",
- "set-blocking": "2.0.0"
- }
- },
- "number-is-nan": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "oauth-sign": {
- "version": "0.8.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "object-assign": {
- "version": "4.1.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "once": {
- "version": "1.4.0",
- "bundled": true,
- "dev": true,
- "requires": {
- "wrappy": "1.0.2"
- }
- },
- "os-homedir": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "os-tmpdir": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "osenv": {
- "version": "0.1.4",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "os-homedir": "1.0.2",
- "os-tmpdir": "1.0.2"
- }
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
- "performance-now": {
- "version": "0.2.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "process-nextick-args": {
- "version": "1.0.7",
- "bundled": true,
- "dev": true
- },
- "punycode": {
- "version": "1.4.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "qs": {
- "version": "6.4.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "rc": {
- "version": "1.2.1",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "deep-extend": "0.4.2",
- "ini": "1.3.4",
- "minimist": "1.2.0",
- "strip-json-comments": "2.0.1"
- },
- "dependencies": {
- "minimist": {
- "version": "1.2.0",
- "bundled": true,
- "dev": true,
- "optional": true
- }
- }
- },
- "readable-stream": {
- "version": "2.2.9",
- "bundled": true,
- "dev": true,
- "requires": {
- "buffer-shims": "1.0.0",
- "core-util-is": "1.0.2",
- "inherits": "2.0.3",
- "isarray": "1.0.0",
- "process-nextick-args": "1.0.7",
- "string_decoder": "1.0.1",
- "util-deprecate": "1.0.2"
- }
- },
- "request": {
- "version": "2.81.0",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "aws-sign2": "0.6.0",
- "aws4": "1.6.0",
- "caseless": "0.12.0",
- "combined-stream": "1.0.5",
- "extend": "3.0.1",
- "forever-agent": "0.6.1",
- "form-data": "2.1.4",
- "har-validator": "4.2.1",
- "hawk": "3.1.3",
- "http-signature": "1.1.1",
- "is-typedarray": "1.0.0",
- "isstream": "0.1.2",
- "json-stringify-safe": "5.0.1",
- "mime-types": "2.1.15",
- "oauth-sign": "0.8.2",
- "performance-now": "0.2.0",
- "qs": "6.4.0",
- "safe-buffer": "5.0.1",
- "stringstream": "0.0.5",
- "tough-cookie": "2.3.2",
- "tunnel-agent": "0.6.0",
- "uuid": "3.0.1"
- }
- },
- "rimraf": {
- "version": "2.6.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "glob": "7.1.2"
- }
- },
- "safe-buffer": {
- "version": "5.0.1",
- "bundled": true,
- "dev": true
- },
- "semver": {
- "version": "5.3.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "set-blocking": {
- "version": "2.0.0",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "signal-exit": {
- "version": "3.0.2",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "sntp": {
- "version": "1.0.9",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "hoek": "2.16.3"
- }
- },
- "sshpk": {
- "version": "1.13.0",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "asn1": "0.2.3",
- "assert-plus": "1.0.0",
- "bcrypt-pbkdf": "1.0.1",
- "dashdash": "1.14.1",
- "ecc-jsbn": "0.1.1",
- "getpass": "0.1.7",
- "jodid25519": "1.0.2",
- "jsbn": "0.1.1",
- "tweetnacl": "0.14.5"
- },
- "dependencies": {
- "assert-plus": {
- "version": "1.0.0",
- "bundled": true,
- "dev": true,
- "optional": true
- }
- }
- },
- "string-width": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true,
- "requires": {
- "code-point-at": "1.1.0",
- "is-fullwidth-code-point": "1.0.0",
- "strip-ansi": "3.0.1"
- }
- },
- "string_decoder": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "safe-buffer": "5.0.1"
- }
- },
- "stringstream": {
- "version": "0.0.5",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "strip-ansi": {
- "version": "3.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "ansi-regex": "2.1.1"
- }
- },
- "strip-json-comments": {
- "version": "2.0.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "tar": {
- "version": "2.2.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "block-stream": "0.0.9",
- "fstream": "1.0.11",
- "inherits": "2.0.3"
- }
- },
- "tar-pack": {
- "version": "3.4.0",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "debug": "2.6.8",
- "fstream": "1.0.11",
- "fstream-ignore": "1.0.5",
- "once": "1.4.0",
- "readable-stream": "2.2.9",
- "rimraf": "2.6.1",
- "tar": "2.2.1",
- "uid-number": "0.0.6"
- }
- },
- "tough-cookie": {
- "version": "2.3.2",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "punycode": "1.4.1"
- }
- },
- "tunnel-agent": {
- "version": "0.6.0",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "safe-buffer": "5.0.1"
- }
- },
- "tweetnacl": {
- "version": "0.14.5",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "uid-number": {
- "version": "0.0.6",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "util-deprecate": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- },
- "uuid": {
- "version": "3.0.1",
- "bundled": true,
- "dev": true,
- "optional": true
- },
- "verror": {
- "version": "1.3.6",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "extsprintf": "1.0.2"
- }
- },
- "wide-align": {
- "version": "1.1.2",
- "bundled": true,
- "dev": true,
- "optional": true,
- "requires": {
- "string-width": "1.0.2"
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "bundled": true,
- "dev": true
- }
- }
- },
- "function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
- "dev": true
- },
- "generate-function": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
- "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=",
- "dev": true
- },
- "generate-object-property": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
- "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=",
- "dev": true,
- "requires": {
- "is-property": "1.0.2"
- }
- },
- "glob": {
- "version": "7.1.2",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
- "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
- "dev": true,
- "requires": {
- "fs.realpath": "1.0.0",
- "inflight": "1.0.6",
- "inherits": "2.0.3",
- "minimatch": "3.0.4",
- "once": "1.4.0",
- "path-is-absolute": "1.0.1"
- }
- },
- "glob-base": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
- "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
- "dev": true,
- "requires": {
- "glob-parent": "2.0.0",
- "is-glob": "2.0.1"
- }
- },
- "glob-parent": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
- "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
- "dev": true,
- "requires": {
- "is-glob": "2.0.1"
- }
- },
- "globals": {
- "version": "9.18.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
- "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
- "dev": true
- },
- "globby": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
- "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
- "dev": true,
- "requires": {
- "array-union": "1.0.2",
- "arrify": "1.0.1",
- "glob": "7.1.2",
- "object-assign": "4.1.1",
- "pify": "2.3.0",
- "pinkie-promise": "2.0.1"
- }
- },
- "graceful-fs": {
- "version": "4.1.11",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
- "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
- "dev": true
- },
- "has": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz",
- "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=",
- "dev": true,
- "requires": {
- "function-bind": "1.1.1"
- }
- },
- "has-ansi": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
- "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
- "dev": true,
- "requires": {
- "ansi-regex": "2.1.1"
- }
- },
- "has-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
- "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
- "dev": true
- },
- "home-or-tmp": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
- "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=",
- "dev": true,
- "requires": {
- "os-homedir": "1.0.2",
- "os-tmpdir": "1.0.2"
- }
- },
- "html-comment-regex": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.1.tgz",
- "integrity": "sha1-ZouTd26q5V696POtRkswekljYl4=",
- "dev": true
- },
- "html-janitor": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/html-janitor/-/html-janitor-2.0.2.tgz",
- "integrity": "sha1-P0VR0j0b6FVOJz+eraK2F8Kzq3A=",
- "dev": true
- },
- "https-browserify": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz",
- "integrity": "sha1-P5E2XKvmC3ftDruiS0VOPgnZWoI=",
- "dev": true
- },
- "icss-replace-symbols": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz",
- "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=",
- "dev": true
- },
- "ieee754": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz",
- "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=",
- "dev": true
- },
- "ignore": {
- "version": "3.3.5",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.5.tgz",
- "integrity": "sha512-JLH93mL8amZQhh/p6mfQgVBH3M6epNq3DfsXsTSuSrInVjwyYlFE1nv2AgfRCC8PoOhM0jwQ5v8s9LgbK7yGDw==",
- "dev": true
- },
- "imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
- "dev": true
- },
- "indexes-of": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
- "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=",
- "dev": true
- },
- "indexof": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
- "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
- "dev": true
- },
- "inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
- "dev": true,
- "requires": {
- "once": "1.4.0",
- "wrappy": "1.0.2"
- }
- },
- "inherits": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
- "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
- "dev": true
- },
- "inquirer": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz",
- "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=",
- "dev": true,
- "requires": {
- "ansi-escapes": "1.4.0",
- "ansi-regex": "2.1.1",
- "chalk": "1.1.3",
- "cli-cursor": "1.0.2",
- "cli-width": "2.2.0",
- "figures": "1.7.0",
- "lodash": "4.17.4",
- "readline2": "1.0.1",
- "run-async": "0.1.0",
- "rx-lite": "3.1.2",
- "string-width": "1.0.2",
- "strip-ansi": "3.0.1",
- "through": "2.3.8"
- }
- },
- "interpret": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.4.tgz",
- "integrity": "sha1-ggzdWIuGj/sZGoCVBtbJyPISsbA=",
- "dev": true
- },
- "invariant": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz",
- "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=",
- "dev": true,
- "requires": {
- "loose-envify": "1.3.1"
- }
- },
- "is-absolute-url": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz",
- "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=",
- "dev": true
- },
- "is-binary-path": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
- "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
- "dev": true,
- "requires": {
- "binary-extensions": "1.10.0"
- }
- },
- "is-buffer": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz",
- "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=",
- "dev": true
- },
- "is-dotfile": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
- "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
- "dev": true
- },
- "is-equal-shallow": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
- "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
- "dev": true,
- "requires": {
- "is-primitive": "2.0.0"
- }
- },
- "is-extendable": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
- "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
- "dev": true
- },
- "is-extglob": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
- "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
- "dev": true
- },
- "is-finite": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
- "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
- "dev": true,
- "requires": {
- "number-is-nan": "1.0.1"
- }
- },
- "is-fullwidth-code-point": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
- "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
- "dev": true,
- "requires": {
- "number-is-nan": "1.0.1"
- }
- },
- "is-glob": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
- "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
- "dev": true,
- "requires": {
- "is-extglob": "1.0.0"
- }
- },
- "is-my-json-valid": {
- "version": "2.16.1",
- "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz",
- "integrity": "sha512-ochPsqWS1WXj8ZnMIV0vnNXooaMhp7cyL4FMSIPKTtnV0Ha/T19G2b9kkhcNsabV9bxYkze7/aLZJb/bYuFduQ==",
- "dev": true,
- "requires": {
- "generate-function": "2.0.0",
- "generate-object-property": "1.2.0",
- "jsonpointer": "4.0.1",
- "xtend": "4.0.1"
- }
- },
- "is-number": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
- "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
- "dev": true,
- "requires": {
- "kind-of": "3.2.2"
- }
- },
- "is-path-cwd": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
- "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=",
- "dev": true
- },
- "is-path-in-cwd": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz",
- "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=",
- "dev": true,
- "requires": {
- "is-path-inside": "1.0.0"
- }
- },
- "is-path-inside": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz",
- "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=",
- "dev": true,
- "requires": {
- "path-is-inside": "1.0.2"
- }
- },
- "is-plain-obj": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
- "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
- "dev": true
- },
- "is-posix-bracket": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
- "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
- "dev": true
- },
- "is-primitive": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
- "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
- "dev": true
- },
- "is-property": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
- "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=",
- "dev": true
- },
- "is-resolvable": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz",
- "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=",
- "dev": true,
- "requires": {
- "tryit": "1.0.3"
- }
- },
- "is-svg": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz",
- "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=",
- "dev": true,
- "requires": {
- "html-comment-regex": "1.1.1"
- }
- },
- "isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
- },
- "isobject": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
- "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
- "dev": true,
- "requires": {
- "isarray": "1.0.0"
- }
- },
- "js-base64": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.3.2.tgz",
- "integrity": "sha512-Y2/+DnfJJXT1/FCwUebUhLWb3QihxiSC42+ctHLGogmW2jPY6LCapMdFZXRvVP2z6qyKW7s6qncE/9gSqZiArw==",
- "dev": true
- },
- "js-tokens": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
- "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
- "dev": true
- },
- "js-yaml": {
- "version": "3.7.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz",
- "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=",
- "dev": true,
- "requires": {
- "argparse": "1.0.9",
- "esprima": "2.7.3"
- }
- },
- "jsesc": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
- "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=",
- "dev": true
- },
- "json-stable-stringify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
- "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
- "dev": true,
- "requires": {
- "jsonify": "0.0.0"
- }
- },
- "json5": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
- "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
- "dev": true
- },
- "jsonify": {
- "version": "0.0.0",
- "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
- "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
- "dev": true
- },
- "jsonpointer": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz",
- "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=",
- "dev": true
- },
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "dev": true,
- "requires": {
- "is-buffer": "1.1.5"
- }
- },
- "lazy-cache": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
- "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
- "dev": true
- },
- "levn": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
- "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
- "dev": true,
- "requires": {
- "prelude-ls": "1.1.2",
- "type-check": "0.3.2"
- }
- },
- "loader-fs-cache": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.1.tgz",
- "integrity": "sha1-VuC/CL2XCLJqdltoUJhAyN7J/bw=",
- "dev": true,
- "requires": {
- "find-cache-dir": "0.1.1",
- "mkdirp": "0.5.1"
- }
- },
- "loader-utils": {
- "version": "0.2.17",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz",
- "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=",
- "dev": true,
- "requires": {
- "big.js": "3.2.0",
- "emojis-list": "2.1.0",
- "json5": "0.5.1",
- "object-assign": "4.1.1"
- }
- },
- "lodash": {
- "version": "4.17.4",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
- "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
- "dev": true
- },
- "lodash.camelcase": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
- "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=",
- "dev": true
- },
- "lodash.memoize": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
- "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
- "dev": true
- },
- "lodash.uniq": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
- "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=",
- "dev": true
- },
- "longest": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
- "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
- "dev": true
- },
- "loose-envify": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz",
- "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=",
- "dev": true,
- "requires": {
- "js-tokens": "3.0.2"
- }
- },
- "macaddress": {
- "version": "0.2.8",
- "resolved": "https://registry.npmjs.org/macaddress/-/macaddress-0.2.8.tgz",
- "integrity": "sha1-WQTcU3w57G2+/q6QIycTX6hRHxI=",
- "dev": true
- },
- "math-expression-evaluator": {
- "version": "1.2.17",
- "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz",
- "integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw=",
- "dev": true
- },
- "memory-fs": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.3.0.tgz",
- "integrity": "sha1-e8xrYp46Q+hx1+Kaymrop/FcuyA=",
- "dev": true,
- "requires": {
- "errno": "0.1.4",
- "readable-stream": "2.3.3"
- }
- },
- "micromatch": {
- "version": "2.3.11",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
- "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
- "dev": true,
- "requires": {
- "arr-diff": "2.0.0",
- "array-unique": "0.2.1",
- "braces": "1.8.5",
- "expand-brackets": "0.1.5",
- "extglob": "0.3.2",
- "filename-regex": "2.0.1",
- "is-extglob": "1.0.0",
- "is-glob": "2.0.1",
- "kind-of": "3.2.2",
- "normalize-path": "2.1.1",
- "object.omit": "2.0.1",
- "parse-glob": "3.0.4",
- "regex-cache": "0.4.4"
- }
- },
- "minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
- "dev": true,
- "requires": {
- "brace-expansion": "1.1.8"
- }
- },
- "minimist": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
- "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
- "dev": true
- },
- "mkdirp": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
- "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
- "dev": true,
- "requires": {
- "minimist": "0.0.8"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
- "dev": true
- },
- "mute-stream": {
- "version": "0.0.5",
- "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz",
- "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=",
- "dev": true
- },
- "nan": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz",
- "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=",
- "dev": true,
- "optional": true
- },
- "natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
- "dev": true
- },
- "node-libs-browser": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-0.7.0.tgz",
- "integrity": "sha1-PicsCBnjCJNeJmdECNevDhSRuDs=",
- "dev": true,
- "requires": {
- "assert": "1.4.1",
- "browserify-zlib": "0.1.4",
- "buffer": "4.9.1",
- "console-browserify": "1.1.0",
- "constants-browserify": "1.0.0",
- "crypto-browserify": "3.3.0",
- "domain-browser": "1.1.7",
- "events": "1.1.1",
- "https-browserify": "0.0.1",
- "os-browserify": "0.2.1",
- "path-browserify": "0.0.0",
- "process": "0.11.10",
- "punycode": "1.4.1",
- "querystring-es3": "0.2.1",
- "readable-stream": "2.3.3",
- "stream-browserify": "2.0.1",
- "stream-http": "2.7.2",
- "string_decoder": "0.10.31",
- "timers-browserify": "2.0.4",
- "tty-browserify": "0.0.0",
- "url": "0.11.0",
- "util": "0.10.3",
- "vm-browserify": "0.0.4"
- },
- "dependencies": {
- "string_decoder": {
- "version": "0.10.31",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
- "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
- "dev": true
- }
- }
- },
- "normalize-path": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
- "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
- "dev": true,
- "requires": {
- "remove-trailing-separator": "1.1.0"
- }
- },
- "normalize-range": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
- "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
- "dev": true
- },
- "normalize-url": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
- "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=",
- "dev": true,
- "requires": {
- "object-assign": "4.1.1",
- "prepend-http": "1.0.4",
- "query-string": "4.3.4",
- "sort-keys": "1.1.2"
- }
- },
- "num2fraction": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
- "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=",
- "dev": true
- },
- "number-is-nan": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
- "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
- "dev": true
- },
- "object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "dev": true
- },
- "object-hash": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.2.0.tgz",
- "integrity": "sha512-smRWXzkvxw72VquyZ0wggySl7PFUtoDhvhpdwgESXxUrH7vVhhp9asfup1+rVLrhsl7L45Ee1Q/l5R2Ul4MwUg==",
- "dev": true
- },
- "object.omit": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
- "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
- "dev": true,
- "requires": {
- "for-own": "0.1.5",
- "is-extendable": "0.1.1"
- }
- },
- "once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "dev": true,
- "requires": {
- "wrappy": "1.0.2"
- }
- },
- "onetime": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
- "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=",
- "dev": true
- },
- "optimist": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
- "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
- "dev": true,
- "requires": {
- "minimist": "0.0.8",
- "wordwrap": "0.0.3"
- },
- "dependencies": {
- "wordwrap": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
- "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
- "dev": true
- }
- }
- },
- "optionator": {
- "version": "0.8.2",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
- "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
- "dev": true,
- "requires": {
- "deep-is": "0.1.3",
- "fast-levenshtein": "2.0.6",
- "levn": "0.3.0",
- "prelude-ls": "1.1.2",
- "type-check": "0.3.2",
- "wordwrap": "1.0.0"
- }
- },
- "os-browserify": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.2.1.tgz",
- "integrity": "sha1-Y/xMzuXS13Y9Jrv4YBB45sLgBE8=",
- "dev": true
- },
- "os-homedir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
- "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
- "dev": true
- },
- "os-tmpdir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
- "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
- "dev": true
- },
- "pako": {
- "version": "0.2.9",
- "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
- "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=",
- "dev": true
- },
- "parse-glob": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
- "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
- "dev": true,
- "requires": {
- "glob-base": "0.3.0",
- "is-dotfile": "1.0.3",
- "is-extglob": "1.0.0",
- "is-glob": "2.0.1"
- }
- },
- "path": {
- "version": "0.12.7",
- "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz",
- "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=",
- "dev": true,
- "requires": {
- "process": "0.11.10",
- "util": "0.10.3"
- }
- },
- "path-browserify": {
- "version": "0.0.0",
- "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz",
- "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=",
- "dev": true
- },
- "path-exists": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
- "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
- "dev": true,
- "requires": {
- "pinkie-promise": "2.0.1"
- }
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
- "dev": true
- },
- "path-is-inside": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
- "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
- "dev": true
- },
- "path-parse": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
- "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=",
- "dev": true
- },
- "pbkdf2-compat": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz",
- "integrity": "sha1-tuDI+plJTZTgURV1gCpZpcFC8og=",
- "dev": true
- },
- "pify": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
- "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
- "dev": true
- },
- "pinkie": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
- "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
- "dev": true
- },
- "pinkie-promise": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
- "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
- "dev": true,
- "requires": {
- "pinkie": "2.0.4"
- }
- },
- "pkg-dir": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz",
- "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=",
- "dev": true,
- "requires": {
- "find-up": "1.1.2"
- }
- },
- "pluralize": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz",
- "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=",
- "dev": true
- },
- "postcss": {
- "version": "5.2.18",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
- "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
- "dev": true,
- "requires": {
- "chalk": "1.1.3",
- "js-base64": "2.3.2",
- "source-map": "0.5.7",
- "supports-color": "3.2.3"
- },
- "dependencies": {
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "1.0.0"
- }
- }
- }
- },
- "postcss-calc": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz",
- "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=",
- "dev": true,
- "requires": {
- "postcss": "5.2.18",
- "postcss-message-helpers": "2.0.0",
- "reduce-css-calc": "1.3.0"
- }
- },
- "postcss-colormin": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.2.tgz",
- "integrity": "sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=",
- "dev": true,
- "requires": {
- "colormin": "1.1.2",
- "postcss": "5.2.18",
- "postcss-value-parser": "3.3.0"
- }
- },
- "postcss-convert-values": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz",
- "integrity": "sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=",
- "dev": true,
- "requires": {
- "postcss": "5.2.18",
- "postcss-value-parser": "3.3.0"
- }
- },
- "postcss-discard-comments": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz",
- "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=",
- "dev": true,
- "requires": {
- "postcss": "5.2.18"
- }
- },
- "postcss-discard-duplicates": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz",
- "integrity": "sha1-uavye4isGIFYpesSq8riAmO5GTI=",
- "dev": true,
- "requires": {
- "postcss": "5.2.18"
- }
- },
- "postcss-discard-empty": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz",
- "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=",
- "dev": true,
- "requires": {
- "postcss": "5.2.18"
- }
- },
- "postcss-discard-overridden": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz",
- "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=",
- "dev": true,
- "requires": {
- "postcss": "5.2.18"
- }
- },
- "postcss-discard-unused": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz",
- "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=",
- "dev": true,
- "requires": {
- "postcss": "5.2.18",
- "uniqs": "2.0.0"
- }
- },
- "postcss-filter-plugins": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz",
- "integrity": "sha1-bYWGJTTXNaxCDkqFgG4fXUKG2Ew=",
- "dev": true,
- "requires": {
- "postcss": "5.2.18",
- "uniqid": "4.1.1"
- }
- },
- "postcss-merge-idents": {
- "version": "2.1.7",
- "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz",
- "integrity": "sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=",
- "dev": true,
- "requires": {
- "has": "1.0.1",
- "postcss": "5.2.18",
- "postcss-value-parser": "3.3.0"
- }
- },
- "postcss-merge-longhand": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz",
- "integrity": "sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=",
- "dev": true,
- "requires": {
- "postcss": "5.2.18"
- }
- },
- "postcss-merge-rules": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz",
- "integrity": "sha1-0d9d+qexrMO+VT8OnhDofGG19yE=",
- "dev": true,
- "requires": {
- "browserslist": "1.7.7",
- "caniuse-api": "1.6.1",
- "postcss": "5.2.18",
- "postcss-selector-parser": "2.2.3",
- "vendors": "1.0.1"
- }
- },
- "postcss-message-helpers": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz",
- "integrity": "sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4=",
- "dev": true
- },
- "postcss-minify-font-values": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz",
- "integrity": "sha1-S1jttWZB66fIR0qzUmyv17vey2k=",
- "dev": true,
- "requires": {
- "object-assign": "4.1.1",
- "postcss": "5.2.18",
- "postcss-value-parser": "3.3.0"
- }
- },
- "postcss-minify-gradients": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz",
- "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=",
- "dev": true,
- "requires": {
- "postcss": "5.2.18",
- "postcss-value-parser": "3.3.0"
- }
- },
- "postcss-minify-params": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz",
- "integrity": "sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=",
- "dev": true,
- "requires": {
- "alphanum-sort": "1.0.2",
- "postcss": "5.2.18",
- "postcss-value-parser": "3.3.0",
- "uniqs": "2.0.0"
- }
- },
- "postcss-minify-selectors": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz",
- "integrity": "sha1-ssapjAByz5G5MtGkllCBFDEXNb8=",
- "dev": true,
- "requires": {
- "alphanum-sort": "1.0.2",
- "has": "1.0.1",
- "postcss": "5.2.18",
- "postcss-selector-parser": "2.2.3"
- }
- },
- "postcss-modules-extract-imports": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz",
- "integrity": "sha1-thTJcgvmgW6u41+zpfqh26agXds=",
- "dev": true,
- "requires": {
- "postcss": "6.0.13"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
- "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
- "dev": true,
- "requires": {
- "color-convert": "1.9.0"
- }
- },
- "chalk": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz",
- "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "3.2.0",
- "escape-string-regexp": "1.0.5",
- "supports-color": "4.4.0"
- }
- },
- "has-flag": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
- "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
- "dev": true
- },
- "postcss": {
- "version": "6.0.13",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz",
- "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==",
- "dev": true,
- "requires": {
- "chalk": "2.1.0",
- "source-map": "0.6.1",
- "supports-color": "4.4.0"
- }
- },
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true
- },
- "supports-color": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
- "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
- "dev": true,
- "requires": {
- "has-flag": "2.0.0"
- }
- }
- }
- },
- "postcss-modules-local-by-default": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz",
- "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=",
- "dev": true,
- "requires": {
- "css-selector-tokenizer": "0.7.0",
- "postcss": "6.0.13"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
- "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
- "dev": true,
- "requires": {
- "color-convert": "1.9.0"
- }
- },
- "chalk": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz",
- "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "3.2.0",
- "escape-string-regexp": "1.0.5",
- "supports-color": "4.4.0"
- }
- },
- "has-flag": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
- "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
- "dev": true
- },
- "postcss": {
- "version": "6.0.13",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz",
- "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==",
- "dev": true,
- "requires": {
- "chalk": "2.1.0",
- "source-map": "0.6.1",
- "supports-color": "4.4.0"
- }
- },
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true
- },
- "supports-color": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
- "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
- "dev": true,
- "requires": {
- "has-flag": "2.0.0"
- }
- }
- }
- },
- "postcss-modules-scope": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz",
- "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=",
- "dev": true,
- "requires": {
- "css-selector-tokenizer": "0.7.0",
- "postcss": "6.0.13"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
- "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
- "dev": true,
- "requires": {
- "color-convert": "1.9.0"
- }
- },
- "chalk": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz",
- "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "3.2.0",
- "escape-string-regexp": "1.0.5",
- "supports-color": "4.4.0"
- }
- },
- "has-flag": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
- "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
- "dev": true
- },
- "postcss": {
- "version": "6.0.13",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz",
- "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==",
- "dev": true,
- "requires": {
- "chalk": "2.1.0",
- "source-map": "0.6.1",
- "supports-color": "4.4.0"
- }
- },
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true
- },
- "supports-color": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
- "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
- "dev": true,
- "requires": {
- "has-flag": "2.0.0"
- }
- }
- }
- },
- "postcss-modules-values": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz",
- "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=",
- "dev": true,
- "requires": {
- "icss-replace-symbols": "1.1.0",
- "postcss": "6.0.13"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
- "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
- "dev": true,
- "requires": {
- "color-convert": "1.9.0"
- }
- },
- "chalk": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz",
- "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "3.2.0",
- "escape-string-regexp": "1.0.5",
- "supports-color": "4.4.0"
- }
- },
- "has-flag": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
- "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
- "dev": true
- },
- "postcss": {
- "version": "6.0.13",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz",
- "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==",
- "dev": true,
- "requires": {
- "chalk": "2.1.0",
- "source-map": "0.6.1",
- "supports-color": "4.4.0"
- }
- },
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true
- },
- "supports-color": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
- "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
- "dev": true,
- "requires": {
- "has-flag": "2.0.0"
- }
- }
- }
- },
- "postcss-normalize-charset": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz",
- "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=",
- "dev": true,
- "requires": {
- "postcss": "5.2.18"
- }
- },
- "postcss-normalize-url": {
- "version": "3.0.8",
- "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz",
- "integrity": "sha1-EI90s/L82viRov+j6kWSJ5/HgiI=",
- "dev": true,
- "requires": {
- "is-absolute-url": "2.1.0",
- "normalize-url": "1.9.1",
- "postcss": "5.2.18",
- "postcss-value-parser": "3.3.0"
- }
- },
- "postcss-ordered-values": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz",
- "integrity": "sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=",
- "dev": true,
- "requires": {
- "postcss": "5.2.18",
- "postcss-value-parser": "3.3.0"
- }
- },
- "postcss-reduce-idents": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz",
- "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=",
- "dev": true,
- "requires": {
- "postcss": "5.2.18",
- "postcss-value-parser": "3.3.0"
- }
- },
- "postcss-reduce-initial": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz",
- "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=",
- "dev": true,
- "requires": {
- "postcss": "5.2.18"
- }
- },
- "postcss-reduce-transforms": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz",
- "integrity": "sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=",
- "dev": true,
- "requires": {
- "has": "1.0.1",
- "postcss": "5.2.18",
- "postcss-value-parser": "3.3.0"
- }
- },
- "postcss-selector-parser": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz",
- "integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=",
- "dev": true,
- "requires": {
- "flatten": "1.0.2",
- "indexes-of": "1.0.1",
- "uniq": "1.0.1"
- }
- },
- "postcss-svgo": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz",
- "integrity": "sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=",
- "dev": true,
- "requires": {
- "is-svg": "2.1.0",
- "postcss": "5.2.18",
- "postcss-value-parser": "3.3.0",
- "svgo": "0.7.2"
- }
- },
- "postcss-unique-selectors": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz",
- "integrity": "sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=",
- "dev": true,
- "requires": {
- "alphanum-sort": "1.0.2",
- "postcss": "5.2.18",
- "uniqs": "2.0.0"
- }
- },
- "postcss-value-parser": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz",
- "integrity": "sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU=",
- "dev": true
- },
- "postcss-zindex": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz",
- "integrity": "sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=",
- "dev": true,
- "requires": {
- "has": "1.0.1",
- "postcss": "5.2.18",
- "uniqs": "2.0.0"
- }
- },
- "prelude-ls": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
- "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
- "dev": true
- },
- "prepend-http": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
- "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
- "dev": true
- },
- "preserve": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
- "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
- "dev": true
- },
- "private": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/private/-/private-0.1.7.tgz",
- "integrity": "sha1-aM5eih7woju1cMwoU3tTMqumPvE=",
- "dev": true
- },
- "process": {
- "version": "0.11.10",
- "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
- "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
- "dev": true
- },
- "process-nextick-args": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
- "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
- "dev": true
- },
- "progress": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz",
- "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=",
- "dev": true
- },
- "prr": {
- "version": "0.0.0",
- "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz",
- "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=",
- "dev": true
- },
- "punycode": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
- "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
- "dev": true
- },
- "q": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/q/-/q-1.5.0.tgz",
- "integrity": "sha1-3QG6ydBtMObyGa7LglPunr3DCPE=",
- "dev": true
- },
- "query-string": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
- "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
- "dev": true,
- "requires": {
- "object-assign": "4.1.1",
- "strict-uri-encode": "1.1.0"
- }
- },
- "querystring": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
- "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
- "dev": true
- },
- "querystring-es3": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
- "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
- "dev": true
- },
- "randomatic": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
- "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==",
- "dev": true,
- "requires": {
- "is-number": "3.0.0",
- "kind-of": "4.0.0"
- },
- "dependencies": {
- "is-number": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
- "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
- "dev": true,
- "requires": {
- "kind-of": "3.2.2"
- },
- "dependencies": {
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "dev": true,
- "requires": {
- "is-buffer": "1.1.5"
- }
- }
- }
- },
- "kind-of": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
- "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
- "dev": true,
- "requires": {
- "is-buffer": "1.1.5"
- }
- }
- }
- },
- "readable-stream": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
- "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
- "dev": true,
- "requires": {
- "core-util-is": "1.0.2",
- "inherits": "2.0.3",
- "isarray": "1.0.0",
- "process-nextick-args": "1.0.7",
- "safe-buffer": "5.1.1",
- "string_decoder": "1.0.3",
- "util-deprecate": "1.0.2"
- }
- },
- "readdirp": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
- "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=",
- "dev": true,
- "requires": {
- "graceful-fs": "4.1.11",
- "minimatch": "3.0.4",
- "readable-stream": "2.3.3",
- "set-immediate-shim": "1.0.1"
- }
- },
- "readline2": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz",
- "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=",
- "dev": true,
- "requires": {
- "code-point-at": "1.1.0",
- "is-fullwidth-code-point": "1.0.0",
- "mute-stream": "0.0.5"
- }
- },
- "rechoir": {
- "version": "0.6.2",
- "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
- "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
- "dev": true,
- "requires": {
- "resolve": "1.4.0"
- }
- },
- "reduce-css-calc": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz",
- "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=",
- "dev": true,
- "requires": {
- "balanced-match": "0.4.2",
- "math-expression-evaluator": "1.2.17",
- "reduce-function-call": "1.0.2"
- },
- "dependencies": {
- "balanced-match": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
- "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=",
- "dev": true
- }
- }
- },
- "reduce-function-call": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.2.tgz",
- "integrity": "sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=",
- "dev": true,
- "requires": {
- "balanced-match": "0.4.2"
- },
- "dependencies": {
- "balanced-match": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
- "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=",
- "dev": true
- }
- }
- },
- "regenerate": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz",
- "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==",
- "dev": true
- },
- "regenerator-runtime": {
- "version": "0.11.0",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz",
- "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==",
- "dev": true
- },
- "regenerator-transform": {
- "version": "0.10.1",
- "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz",
- "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==",
- "dev": true,
- "requires": {
- "babel-runtime": "6.26.0",
- "babel-types": "6.26.0",
- "private": "0.1.7"
- }
- },
- "regex-cache": {
- "version": "0.4.4",
- "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
- "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
- "dev": true,
- "requires": {
- "is-equal-shallow": "0.1.3"
- }
- },
- "regexpu-core": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz",
- "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=",
- "dev": true,
- "requires": {
- "regenerate": "1.3.3",
- "regjsgen": "0.2.0",
- "regjsparser": "0.1.5"
- }
- },
- "regjsgen": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
- "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=",
- "dev": true
- },
- "regjsparser": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
- "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=",
- "dev": true,
- "requires": {
- "jsesc": "0.5.0"
- },
- "dependencies": {
- "jsesc": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
- "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
- "dev": true
- }
- }
- },
- "remove-trailing-separator": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
- "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
- "dev": true
- },
- "repeat-element": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
- "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=",
- "dev": true
- },
- "repeat-string": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
- "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
- "dev": true
- },
- "repeating": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
- "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
- "dev": true,
- "requires": {
- "is-finite": "1.0.2"
- }
- },
- "require-uncached": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
- "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
- "dev": true,
- "requires": {
- "caller-path": "0.1.0",
- "resolve-from": "1.0.1"
- }
- },
- "resolve": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz",
- "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==",
- "dev": true,
- "requires": {
- "path-parse": "1.0.5"
- }
- },
- "resolve-from": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
- "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=",
- "dev": true
- },
- "restore-cursor": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz",
- "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=",
- "dev": true,
- "requires": {
- "exit-hook": "1.1.1",
- "onetime": "1.1.0"
- }
- },
- "right-align": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
- "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
- "dev": true,
- "requires": {
- "align-text": "0.1.4"
- }
- },
- "rimraf": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
- "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
- "dev": true,
- "requires": {
- "glob": "7.1.2"
- }
- },
- "ripemd160": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-0.2.0.tgz",
- "integrity": "sha1-K/GYveFnys+lHAqSjoS2i74XH84=",
- "dev": true
- },
- "run-async": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz",
- "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=",
- "dev": true,
- "requires": {
- "once": "1.4.0"
- }
- },
- "rx-lite": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz",
- "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=",
- "dev": true
- },
- "safe-buffer": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
- "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
- "dev": true
- },
- "sax": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
- "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
- "dev": true
- },
- "set-immediate-shim": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
- "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=",
- "dev": true
- },
- "setimmediate": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
- "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
- "dev": true
- },
- "sha.js": {
- "version": "2.2.6",
- "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.2.6.tgz",
- "integrity": "sha1-F93t3F9yL7ZlAWWIlUYZd4ZzFbo=",
- "dev": true
- },
- "shelljs": {
- "version": "0.7.8",
- "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz",
- "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=",
- "dev": true,
- "requires": {
- "glob": "7.1.2",
- "interpret": "1.0.4",
- "rechoir": "0.6.2"
- }
- },
- "slash": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
- "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
- "dev": true
- },
- "slice-ansi": {
- "version": "0.0.4",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz",
- "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=",
- "dev": true
- },
- "sort-keys": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
- "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
- "dev": true,
- "requires": {
- "is-plain-obj": "1.1.0"
- }
- },
- "source-list-map": {
- "version": "0.1.8",
- "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-0.1.8.tgz",
- "integrity": "sha1-xVCyq1Qn9rPyH1r+rYjE9Vh7IQY=",
- "dev": true
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "source-map-support": {
- "version": "0.4.18",
- "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
- "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
- "dev": true,
- "requires": {
- "source-map": "0.5.7"
- }
- },
- "sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
- "dev": true
- },
- "stream-browserify": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
- "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=",
- "dev": true,
- "requires": {
- "inherits": "2.0.3",
- "readable-stream": "2.3.3"
- }
- },
- "stream-http": {
- "version": "2.7.2",
- "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz",
- "integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==",
- "dev": true,
- "requires": {
- "builtin-status-codes": "3.0.0",
- "inherits": "2.0.3",
- "readable-stream": "2.3.3",
- "to-arraybuffer": "1.0.1",
- "xtend": "4.0.1"
- }
- },
- "strict-uri-encode": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
- "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
- "dev": true
- },
- "string-width": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
- "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
- "dev": true,
- "requires": {
- "code-point-at": "1.1.0",
- "is-fullwidth-code-point": "1.0.0",
- "strip-ansi": "3.0.1"
- }
- },
- "string_decoder": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
- "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
- "dev": true,
- "requires": {
- "safe-buffer": "5.1.1"
- }
- },
- "strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
- "dev": true,
- "requires": {
- "ansi-regex": "2.1.1"
- }
- },
- "strip-bom": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
- "dev": true
- },
- "strip-json-comments": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
- "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
- "dev": true
- },
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
- },
- "svgo": {
- "version": "0.7.2",
- "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz",
- "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=",
- "dev": true,
- "requires": {
- "coa": "1.0.4",
- "colors": "1.1.2",
- "csso": "2.3.2",
- "js-yaml": "3.7.0",
- "mkdirp": "0.5.1",
- "sax": "1.2.4",
- "whet.extend": "0.9.9"
- }
- },
- "table": {
- "version": "3.8.3",
- "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz",
- "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=",
- "dev": true,
- "requires": {
- "ajv": "4.11.8",
- "ajv-keywords": "1.5.1",
- "chalk": "1.1.3",
- "lodash": "4.17.4",
- "slice-ansi": "0.0.4",
- "string-width": "2.1.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
- "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
- "dev": true
- },
- "string-width": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
- "dev": true,
- "requires": {
- "is-fullwidth-code-point": "2.0.0",
- "strip-ansi": "4.0.0"
- }
- },
- "strip-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
- "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
- "dev": true,
- "requires": {
- "ansi-regex": "3.0.0"
- }
- }
- }
- },
- "tapable": {
- "version": "0.1.10",
- "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.1.10.tgz",
- "integrity": "sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q=",
- "dev": true
- },
- "text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
- "dev": true
- },
- "through": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
- "dev": true
- },
- "timers-browserify": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.4.tgz",
- "integrity": "sha512-uZYhyU3EX8O7HQP+J9fTVYwsq90Vr68xPEFo7yrVImIxYvHgukBEgOB/SgGoorWVTzGM/3Z+wUNnboA4M8jWrg==",
- "dev": true,
- "requires": {
- "setimmediate": "1.0.5"
- }
- },
- "to-arraybuffer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
- "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
- "dev": true
- },
- "to-fast-properties": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
- "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=",
- "dev": true
- },
- "trim-right": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
- "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
- "dev": true
- },
- "tryit": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz",
- "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=",
- "dev": true
- },
- "tty-browserify": {
- "version": "0.0.0",
- "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
- "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
- "dev": true
- },
- "type-check": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
- "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
- "dev": true,
- "requires": {
- "prelude-ls": "1.1.2"
- }
- },
- "typedarray": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
- "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
- "dev": true
- },
- "uglify-js": {
- "version": "2.7.5",
- "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.5.tgz",
- "integrity": "sha1-RhLAx7qu4rp8SH3kkErhIgefLKg=",
- "dev": true,
- "requires": {
- "async": "0.2.10",
- "source-map": "0.5.7",
- "uglify-to-browserify": "1.0.2",
- "yargs": "3.10.0"
- },
- "dependencies": {
- "async": {
- "version": "0.2.10",
- "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
- "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=",
- "dev": true
- }
- }
- },
- "uglify-to-browserify": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
- "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
- "dev": true
- },
- "uniq": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
- "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
- "dev": true
- },
- "uniqid": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/uniqid/-/uniqid-4.1.1.tgz",
- "integrity": "sha1-iSIN32t1GuUrX3JISGNShZa7hME=",
- "dev": true,
- "requires": {
- "macaddress": "0.2.8"
- }
- },
- "uniqs": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz",
- "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=",
- "dev": true
- },
- "url": {
- "version": "0.11.0",
- "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
- "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
- "dev": true,
- "requires": {
- "punycode": "1.3.2",
- "querystring": "0.2.0"
- },
- "dependencies": {
- "punycode": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
- "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
- "dev": true
- }
- }
- },
- "user-home": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz",
- "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=",
- "dev": true,
- "requires": {
- "os-homedir": "1.0.2"
- }
- },
- "util": {
- "version": "0.10.3",
- "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
- "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
- "dev": true,
- "requires": {
- "inherits": "2.0.1"
- },
- "dependencies": {
- "inherits": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
- "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=",
- "dev": true
- }
- }
- },
- "util-deprecate": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
- "dev": true
- },
- "vendors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.1.tgz",
- "integrity": "sha1-N61zyO5Bf7PVgOeFMSMH0nSEfyI=",
- "dev": true
- },
- "vm-browserify": {
- "version": "0.0.4",
- "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz",
- "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=",
- "dev": true,
- "requires": {
- "indexof": "0.0.1"
- }
- },
- "watchpack": {
- "version": "0.2.9",
- "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-0.2.9.tgz",
- "integrity": "sha1-Yuqkq15bo1/fwBgnVibjwPXj+ws=",
- "dev": true,
- "requires": {
- "async": "0.9.2",
- "chokidar": "1.7.0",
- "graceful-fs": "4.1.11"
- },
- "dependencies": {
- "async": {
- "version": "0.9.2",
- "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
- "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=",
- "dev": true
- }
- }
- },
- "webpack": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/webpack/-/webpack-1.15.0.tgz",
- "integrity": "sha1-T/MfU9sDM55VFkqdRo7gMklo/pg=",
- "dev": true,
- "requires": {
- "acorn": "3.3.0",
- "async": "1.5.2",
- "clone": "1.0.2",
- "enhanced-resolve": "0.9.1",
- "interpret": "0.6.6",
- "loader-utils": "0.2.17",
- "memory-fs": "0.3.0",
- "mkdirp": "0.5.1",
- "node-libs-browser": "0.7.0",
- "optimist": "0.6.1",
- "supports-color": "3.2.3",
- "tapable": "0.1.10",
- "uglify-js": "2.7.5",
- "watchpack": "0.2.9",
- "webpack-core": "0.6.9"
- },
- "dependencies": {
- "acorn": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
- "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=",
- "dev": true
- },
- "interpret": {
- "version": "0.6.6",
- "resolved": "https://registry.npmjs.org/interpret/-/interpret-0.6.6.tgz",
- "integrity": "sha1-/s16GOfOXKar+5U+H4YhOknxYls=",
- "dev": true
- },
- "supports-color": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
- "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
- "dev": true,
- "requires": {
- "has-flag": "1.0.0"
- }
- }
- }
- },
- "webpack-core": {
- "version": "0.6.9",
- "resolved": "https://registry.npmjs.org/webpack-core/-/webpack-core-0.6.9.tgz",
- "integrity": "sha1-/FcViMhVjad76e+23r3Fo7FyvcI=",
- "dev": true,
- "requires": {
- "source-list-map": "0.1.8",
- "source-map": "0.4.4"
- },
- "dependencies": {
- "source-map": {
- "version": "0.4.4",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
- "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
- "dev": true,
- "requires": {
- "amdefine": "1.0.1"
- }
- }
- }
- },
- "webpack-sources": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-0.1.5.tgz",
- "integrity": "sha1-qh86vw8NdNtxEcQOUAuE+WZkB1A=",
- "dev": true,
- "requires": {
- "source-list-map": "0.1.8",
- "source-map": "0.5.7"
- }
- },
- "whet.extend": {
- "version": "0.9.9",
- "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz",
- "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=",
- "dev": true
- },
- "window-size": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
- "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
- "dev": true
- },
- "wordwrap": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
- "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
- "dev": true
- },
- "wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
- "dev": true
- },
- "write": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
- "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
- "dev": true,
- "requires": {
- "mkdirp": "0.5.1"
- }
- },
- "xtend": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
- "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
- "dev": true
- },
- "yargs": {
- "version": "3.10.0",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
- "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
- "dev": true,
- "requires": {
- "camelcase": "1.2.1",
- "cliui": "2.1.0",
- "decamelize": "1.2.0",
- "window-size": "0.1.0"
- }
- }
- }
-}
diff --git a/package.json b/package.json
index 4ea7ebf44..829207af0 100644
--- a/package.json
+++ b/package.json
@@ -1,25 +1,59 @@
{
"name": "codex.editor",
- "version": "1.7.9",
+ "version": "2.0.0",
"description": "Codex Editor. Native JS, based on API and Open Source",
- "main": "index.js",
+ "main": "build/codex-editor.js",
"scripts": {
- "build": "webpack"
+ "build": "rimraf dist && yarn svg && yarn build:dev",
+ "svg": "svg-sprite-generate -d src/assets/ -o build/sprite.svg",
+ "build:dev": "webpack --mode development --progress --display-error-details --display-entrypoints"
},
- "author": "Codex Team",
+ "author": "CodeX",
"license": "ISC",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/codex-team/codex.editor.git"
+ },
"devDependencies": {
- "babel-core": "^6.21.0",
- "babel-loader": "^6.2.10",
- "babel-polyfill": "^6.20.0",
- "babel-preset-es2015": "^6.22.0",
- "babel-runtime": "^6.20.0",
- "css-loader": "^0.26.1",
- "eslint": "^3.12.2",
- "eslint-loader": "^1.6.1",
- "extract-text-webpack-plugin": "^1.0.1",
+ "@codexteam/shortcuts": "^1.0.0",
+ "babel-core": "^6.26.3",
+ "babel-loader": "^7.1.5",
+ "babel-plugin-add-module-exports": "^0.2.1",
+ "babel-plugin-class-display-name": "^2.1.0",
+ "babel-polyfill": "^6.26.0",
+ "babel-preset-env": "^1.7.0",
+ "babel-preset-stage-0": "^6.24.1",
+ "babel-runtime": "^6.26.0",
+ "css-loader": "^0.28.11",
+ "eslint": "^4.19.1",
+ "eslint-loader": "^2.1.0",
+ "extract-text-webpack-plugin": "^3.0.2",
"html-janitor": "^2.0.2",
"path": "^0.12.7",
- "webpack": "^1.14.0"
+ "postcss-apply": "^0.10.0",
+ "postcss-color-hex-alpha": "^3.0.0",
+ "postcss-color-mod-function": "^2.4.3",
+ "postcss-cssnext": "^3.1.0",
+ "postcss-custom-media": "^6.0.0",
+ "postcss-custom-properties": "^7.0.0",
+ "postcss-custom-selectors": "^4.0.1",
+ "postcss-font-family-system-ui": "^3.0.0",
+ "postcss-font-variant": "^3.0.0",
+ "postcss-loader": "^2.1.6",
+ "postcss-media-minmax": "^3.0.0",
+ "postcss-nested": "^3.0.0",
+ "postcss-nested-ancestors": "^2.0.0",
+ "postcss-nesting": "^6.0.0",
+ "postcss-smart-import": "^0.7.6",
+ "raw-loader": "^0.5.1",
+ "rimraf": "^2.6.2",
+ "stylelint": "^9.3.0",
+ "svg-sprite-generator": "0.0.7",
+ "ts-loader": "^4.4.2",
+ "tslint": "^5.11.0",
+ "tslint-loader": "^3.6.0",
+ "typescript": "^2.9.2",
+ "webpack": "^4.16.2",
+ "webpack-cli": "^3.1.0"
}
}
diff --git a/plugins/attaches/attaches.css b/plugins/attaches/attaches.css
deleted file mode 100644
index 8082a356a..000000000
--- a/plugins/attaches/attaches.css
+++ /dev/null
@@ -1,130 +0,0 @@
-.cdx-attaches__default-wrapper {
- margin: 15px 0;
- padding: 15px;
- background: #fff;
- border: 1px solid #ebecec;
- box-shadow: 0 1px 2px 0 rgba(34, 36, 44, 0.03);
- border-radius: 3px;
- text-align: center;
-}
-
-.cdx-attaches__default-button {
- color: #8990aa;
- cursor: pointer;
-}
-
-.cdx-attaches__default-button:hover {
- color: #393f52;
-}
-
-.cdx-attaches__wrapper {
- display: -ms-flexbox;
- display: flex;
- -ms-flex-flow: row nowrap;
- flex-flow: row nowrap;
- -ms-flex-pack: start;
- justify-content: flex-start;
- -ms-flex-align: center;
- align-items: center;
- margin: 10px 0;
- padding: 15px 20px;
- background: #fff;
- border: 1px solid #ebecec;
- box-shadow: 0 1px 2px 0 rgba(34, 36, 44, 0.03);
- border-radius: 3px;
- font-size: 15px;
-}
-
-.cdx-attaches__file-name {
- -ms-flex-positive: 8;
- flex-grow: 8;
- width: 100%;
- outline: none;
- border: 0;
- font-size: inherit;
-}
-
-.cdx-attaches__file-name--collapsed {
- width: 30%;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.cdx-attaches__extension,
-.cdx-attaches__size {
- color: #8f9298;
- white-space: nowrap;
-}
-
-.cdx-attaches__extension::after {
- content: ',';
- margin-right: 0.2em;
-}
-
-.cdx-attaches__size::after {
- content: 'KB';
- margin-left: 0.2em;
-}
-
-.cdx-attaches__icon {
- display: inline-block;
- width: 16px;
- height: 32px;
- background: url(file-icon-black.svg) no-repeat center center;
- background-size: contain;
-}
-
-li:hover .cdx-attaches__icon,
-.selected .cdx-attaches__icon {
- background: url(file-icon-white.svg) no-repeat center center;
- background-size: contain;
-}
-
-.cdx-attaches__icon--inline {
- height: 16px;
- vertical-align: text-bottom;
-}
-
-.cdx-attaches__loader {
- background-color: transparent;
- background-image: repeating-linear-gradient(-45deg, transparent, transparent 4px, #f5f9ff 4px, #eaedef 8px) !important;
- background-size: 56px 56px;
- animation: loading-bar 5s infinite linear;
-}
-
-@keyframes loading-bar {
- 100% { background-position: -56% 0; }
-}
-
-.cdx-attaches__progress-bar {
- width: 100%;
- height: 3px;
- margin: 0 15px;
- background: #e1e3eb;
- border: 0;
- border-radius: 5px;
-}
-
-.cdx-attaches__progress-bar::-webkit-progress-bar {
- background: #e0e1e3;
- border-radius: 5px;
-}
-
-.cdx-attaches__progress-bar::-webkit-progress-value {
- background: #414957;
- border-radius: 5px;
- transition: all 100ms ease-in;
-}
-
-progress::-moz-progress-bar {
- background: #414957;
- border-radius: 5px;
-}
-
-.cdx-attaches__cross-button {
- width: 18px;
- height: 18px;
- background: url(cross.svg) no-repeat center center;
- background-size: contain;
- cursor: pointer;
-}
diff --git a/plugins/attaches/attaches.js b/plugins/attaches/attaches.js
deleted file mode 100644
index 52268411f..000000000
--- a/plugins/attaches/attaches.js
+++ /dev/null
@@ -1,430 +0,0 @@
-/**
- * Attache-file Plugin for CodeX Editor
- *
- * @param {String} config.fetchUrl - Route for file uploding
- * @param {Nubmer} config.maxSize - Maximum allowed file size in KB
- * @param {String} config.accept - Accepted MIME-types. By default, accepts all
- *
- * Backend should return response with
- * 'url' - Full path to the uploaded file
- * 'title' - File title,
- * 'name' - File name without extension,
- * 'extension' - File extension,
- * 'size' - File size
- *
- * @author @gohabereg
- * @version 1.0.0
- */
-var cdxAttaches = function () {
-
- /**
- * Private methods and props
- */
-
- var KBYTE = 1024,
- fileWrapper = null;
-
- /**
- * Default config
- * Can be redefined with prepare method
- *
- * @var sting config.fetchUrl -- url to your fetch script
- * @var int config.maxSize -- max size of file in kilobytes
- * @var accept config.accept -- valid MIME-types. By default, accepts all
- *
- */
- var config = {
-
- fetchUrl: '',
- maxSize: 2,
- accept: ''
-
- };
-
- var elementsClasses = {
-
- defaultFormWrapper : 'cdx-attaches__default-wrapper',
- defaultFormButton : 'cdx-attaches__default-button',
-
- progressBar : 'cdx-attaches__progress-bar',
- wrapper : 'cdx-attaches__wrapper',
- loader : 'cdx-attaches__loader',
- crossButton : 'cdx-attaches__cross-button',
-
- file: {
- title : 'cdx-attaches__file-name',
- collapsedName : 'cdx-attaches__file-name--collapsed',
- extension : 'cdx-attaches__extension',
- size : 'cdx-attaches__size'
- }
-
- };
-
- var ui = {
-
- defaultForm: function () {
-
- var wrapper = codex.editor.draw.node('div', elementsClasses.defaultFormWrapper),
- button = codex.editor.draw.node('div', elementsClasses.defaultFormButton);
-
- button.addEventListener('click', upload.fire);
- button.innerHTML = ' Загрузить файл';
-
- wrapper.appendChild(button);
-
- return wrapper;
-
- },
-
- uploadedFile: function (data) {
-
- var wrapper = codex.editor.draw.node('div', elementsClasses.wrapper),
- name = codex.editor.draw.node('input', elementsClasses.file.title),
- extension = codex.editor.draw.node('span', elementsClasses.file.extension),
- size = codex.editor.draw.node('span', elementsClasses.file.size);
-
- wrapper.dataset.url = data.url;
- wrapper.dataset.name = data.name;
- name.value = data.title || '';
- extension.textContent = data.extension.toUpperCase();
- size.textContent = data.size;
-
- wrapper.appendChild(name);
- wrapper.appendChild(extension);
- wrapper.appendChild(size);
-
- return wrapper;
-
- },
-
- progressBar: {
-
- bar: null,
-
- draw: function () {
-
- var wrapper = codex.editor.draw.node('div', elementsClasses.wrapper),
- progress = codex.editor.draw.node('progress', elementsClasses.progressBar),
- name = codex.editor.draw.node('span', elementsClasses.file.title),
- crossButton = codex.editor.draw.node('span', elementsClasses.crossButton);
-
- progress.max = 100;
- progress.value = 0;
-
- name.textContent = codex.editor.transport.input.files[0].name;
- name.classList.add(elementsClasses.file.collapsedName);
-
- crossButton.addEventListener('click', upload.abort);
-
- ui.progressBar.bar = progress;
-
- wrapper.appendChild(name);
- wrapper.appendChild(progress);
- wrapper.appendChild(crossButton);
-
- return wrapper;
-
- },
-
- change: function (value) {
-
- console.assert( !isNaN(value), 'CodeX Editor Attaches: passed value is not a Number');
-
- ui.progressBar.bar.value = value;
-
- }
-
- }
-
- };
-
- /**
- * Notify about upload errors via codex.editor.notifications
- *
- * @param Object error can have `message` property with error message
- */
- var notifyError = function (error) {
-
- error = error || {};
-
- codex.editor.notifications.notification({
- type: 'error',
- message: 'Ошибка во время загрузки файла' + ( error.message ? ': ' + error.message : '' )
- });
-
- };
-
- /**
- * Contains validation methods
- *
- * TODO: MIME-type validation
- *
- */
- var validation = {
-
- size: function () {
-
- var file = codex.editor.transport.input.files[0];
-
- return Math.ceil(file.size / KBYTE) <= config.maxSize;
-
- },
-
- };
-
- var upload = {
-
- current: null,
-
- aborted: false,
-
- /**
- * Fired codex.editor.transport selectAndUpload methods
- */
- fire: function () {
-
- codex.editor.transport.selectAndUpload({
- url: config.fetchUrl,
- success: upload.success,
- beforeSend: upload.start,
- progress: upload.progress,
- error: upload.error,
- accept: config.accept
- });
-
- },
-
- /**
- * Will be called before upload
- * Draws load animation and progress bar
- */
- start: function () {
-
- if (!validation.size()) {
-
- notifyError({message: 'Файл слишком большой'});
- return false;
-
- }
-
- if (upload.current) {
-
- notifyError({message: 'Дождитесь окончания предыдущей загрузки'});
- return;
-
- }
-
- var progress = ui.progressBar.draw();
-
- upload.current = progress;
-
- codex.editor.content.switchBlock(fileWrapper, progress, 'attaches');
-
- },
-
- /**
- * Handler for XmlHttpRequest.upload.onprogress event
- * Changes progress bar status
- *
- * @param event
- */
- progress: function (event) {
-
- /** Prevents isNaN value assignment */
- if (!event.total) {
- return;
- }
-
- var value = parseInt(event.loaded / event.total * 100);
-
- ui.progressBar.change(value);
-
- },
-
- /**
- * Will be called after success upload
- * Try to decode JSON response and draws ui or fires error handler
- *
- * @param response
- */
- success: function (response) {
-
- var data,
- uploadedFile;
-
- try {
-
- response = JSON.parse(response);
-
- if (response.success) {
-
- data = response.data;
- data.size = Math.ceil(data.size / KBYTE) || 1;
-
- uploadedFile = ui.uploadedFile(data);
- codex.editor.content.switchBlock(upload.current, uploadedFile, 'attaches');
-
- uploadedFile.querySelector('input').focus();
-
- } else {
-
- upload.error(response);
-
- }
-
- } catch (e) {
-
- upload.error();
-
- }
-
- upload.current = null;
-
- },
-
- /**
- * Upload errors handler
- *
- * @param error
- */
- error: function (error) {
-
- var defaultFrom = ui.defaultForm();
-
- codex.editor.content.switchBlock(upload.current, defaultFrom, 'attaches');
-
- if (!upload.aborted) {
-
- notifyError(error);
-
- }
-
- upload.aborted = false;
-
- upload.current = null;
-
- },
-
- abort: function () {
-
- codex.editor.transport.abort();
-
- upload.aborted = true;
-
- upload.current = null;
-
- }
-
- };
-
-
-
- /*
- * Public methods
- * @param {String} _config.fetchUrl Required
- */
- var prepare = function (_config) {
-
- return new Promise(function(resolve, reject){
-
- if ( !_config.fetchUrl ){
-
- reject(Error('fetchUrl is missed'));
- return;
-
- }
-
- config.fetchUrl = _config.fetchUrl;
- config.accept = _config.accept || config.accept;
-
- if ( !isNaN(_config.maxSize)){
- config.maxSize = _config.maxSize;
- }
-
- resolve();
-
- });
-
- };
-
- var render = function (data) {
-
- if (!data) {
-
- fileWrapper = ui.defaultForm();
- return fileWrapper;
-
- }
-
- return ui.uploadedFile(data);
-
- };
-
- var save = function (block) {
-
- var data = {
-
- url: block.dataset.url,
- name: block.dataset.name,
- title: block.querySelector('.' + elementsClasses.file.title).value,
- extension: block.querySelector('.' + elementsClasses.file.extension).textContent,
- size: block.querySelector('.' + elementsClasses.file.size).textContent,
-
- };
-
- return data;
-
- };
-
- var validate = function (data) {
-
- if (!data.url || !data.url.trim()) {
-
- return false;
-
- }
-
- if (!data.title || !data.title.trim()) {
-
- return false;
-
- }
-
- if (!data.extension || !data.extension.trim()) {
-
- return false;
-
- }
-
- if (!data.size || !data.size.trim()) {
-
- return false;
-
- }
-
- return true;
-
- };
-
- var destroy = function () {
-
- cdxAttaches = null;
-
- };
-
- var appendCallback = function () {
-
- upload.fire();
-
- };
-
- return {
- prepare: prepare,
- render: render,
- save: save,
- validate: validate,
- destroy: destroy,
- appendCallback: appendCallback
- };
-
-}();
\ No newline at end of file
diff --git a/plugins/attaches/cross.svg b/plugins/attaches/cross.svg
deleted file mode 100644
index 1cbdeac83..000000000
--- a/plugins/attaches/cross.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
\ No newline at end of file
diff --git a/plugins/attaches/file-icon-black.svg b/plugins/attaches/file-icon-black.svg
deleted file mode 100644
index 0a559b7e7..000000000
--- a/plugins/attaches/file-icon-black.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/plugins/attaches/file-icon-white.svg b/plugins/attaches/file-icon-white.svg
deleted file mode 100644
index 87a6039ef..000000000
--- a/plugins/attaches/file-icon-white.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/plugins/code/code.css b/plugins/code/code.css
deleted file mode 100644
index 8221b6156..000000000
--- a/plugins/code/code.css
+++ /dev/null
@@ -1,30 +0,0 @@
-.ce-code {
- display: block;
- width: 100%;
- min-height: 100px;
- border: 1px solid #ebeef3;
- border-radius: 3px;
- background: #fdfdff !important;
-
- margin: 1em 0 !important;
- padding: .5em .8em;
- box-sizing: border-box;
- white-space: pre-wrap;
-
- font-family: 'monospace', 'monaco', 'consolas', 'courier';
- line-height: 1.5em;
- color: #325179;
- font-size: .8em;
-
- resize: vertical;
- outline: none;
-}
-
-
-/**
-* CodeX Editor styles overlay
-* @todo change for ce-tool-wrapper__code
-*/
-.ce_block[data-type="code"]{
- padding: 1em 0 !important;
-}
diff --git a/plugins/code/code.js b/plugins/code/code.js
deleted file mode 100644
index aaeb72b38..000000000
--- a/plugins/code/code.js
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * Code Plugin\
- * Creates code tag and adds content to this tag
- */
-
-var code = (function(code_plugin) {
-
- var baseClass = "ce-code";
-
- /**
- * Make initial header block
- * @param {object} JSON with block data
- * @return {Element} element to append
- */
- var make_ = function (data) {
-
- var tag = codex.editor.draw.node('TEXTAREA', [baseClass], {});
-
- if (data && data.text) {
- tag.value = data.text;
- }
-
- return tag;
- };
-
- /**
- * Escapes HTML chars
- *
- * @param {string} input
- * @return {string} — escaped string
- */
- var escapeHTML_ = function (input) {
-
- var div = document.createElement('DIV'),
- text = document.createTextNode(input);
-
- div.appendChild(text);
-
- return div.innerHTML;
-
- };
-
- /**
- * Method to render HTML block from JSON
- */
- code_plugin.render = function (data) {
-
- return make_(data);
- };
-
- /**
- * Method to extract JSON data from HTML block
- */
- code_plugin.save = function (blockContent) {
-
- var escaped = escapeHTML_(blockContent.value),
- data = {
- text : escaped
- };
-
-
- return data;
-
- };
-
- code_plugin.validate = function (data) {
-
- if (data.text.trim() == '')
- return;
-
- return true;
- };
-
- code_plugin.destroy = function () {
-
- code = null;
-
- };
-
- return code_plugin;
-
-})({});
diff --git a/plugins/embed/embed.css b/plugins/embed/embed.css
deleted file mode 100644
index c11a8b38d..000000000
--- a/plugins/embed/embed.css
+++ /dev/null
@@ -1,17 +0,0 @@
-.ce-redactor .embed {
- max-width: 600px;
- margin: 15px 0;
- background: #fff;
-}
-
-.ce-redactor .embed iframe {
- width: 100% !important;
- border: 0 !important;
-}
-
-.embed__loader {
- background-image: url("loading.gif") !important;
- background-repeat: no-repeat;
- background-position: center center;
- opacity: 0.5;
-}
diff --git a/plugins/embed/embed.js b/plugins/embed/embed.js
deleted file mode 100644
index 744ec85c8..000000000
--- a/plugins/embed/embed.js
+++ /dev/null
@@ -1,211 +0,0 @@
-/**
- * Embed plugin by gohabereg
- * @version 1.0.0
- */
-var embed = function(embed_plugin){
-
- var methods = {
-
- addInternal: function (content) {
- codex.editor.content.switchBlock(codex.editor.content.currentNode, content);
-
- var blockContent = codex.editor.content.currentNode.childNodes[0];
- blockContent.classList.add('embed__loader');
-
- setTimeout(function(){
- blockContent.classList.remove('embed__loader');
- }, 1000);
-
- },
-
- getHtmlWithEmbedId: function (type, id) {
- return services[type].html.replace(/<\%\= remote\_id \%\>/g, id);
- },
-
- makeElementFromHtml: function(html) {
- var wrapper = document.createElement('DIV');
-
- wrapper.innerHTML = html;
-
- return wrapper;
- },
-
- getRemoteId: function(source, execArray) {
-
- switch(source) {
- case 'yandex-music-track':
- id = execArray[2]+'/'+execArray[1];
- break;
- case 'yandex-music-playlist':
- id = execArray[1]+'/'+execArray[2];
- break;
- default:
- id = execArray[1];
- }
-
- return id;
- }
- };
-
- var services = {
- youtube: {
- regex: /^.*(?:(?:youtu\.be\/)|(?:youtube\.com)\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*)(?:[\?\&]t\=(\d*)|)/,
- html: "",
- height: 320,
- width: 580
- }
- };
-
-
- embed_plugin.make = function(data, isInternal) {
-
- if (!data.remote_id)
- return;
-
- var html = methods.getHtmlWithEmbedId(data.source, data.remote_id),
- block = methods.makeElementFromHtml(html);
-
- block.dataset.remoteId = data.remote_id;
- block.dataset.source = data.source;
- block.dataset.thumbnailUrl = data.thumbnailUrl;
-
- block.classList.add('embed');
-
- // var sidePadding = (600 - services[data.source].width) / 2 + 'px';
-
- // block.style.padding = '30px ' + sidePadding;
-
- if (isInternal) {
- methods.addInternal(block);
- }
-
- return block;
-
- };
-
- /**
- * Saving JSON output.
- * Upload data via ajax
- */
- embed_plugin.save = function(blockContent) {
-
- if (!blockContent)
- return;
-
- var data,
- source = blockContent.dataset.source;
-
- data = {
- source: source,
- remote_id: blockContent.dataset.remoteId,
- thumbnailUrl: blockContent.dataset.thumbnailUrl,
- height: services[source].height,
- width: services[source].width
- };
-
- return data;
-
- };
-
- /**
- * Render data
- */
- embed_plugin.render = function(data) {
- return embed_plugin.make(data);
- };
-
- embed_plugin.urlPastedCallback = function(url, pattern) {
-
- var execArray = pattern.regex.exec(url),
- id = methods.getRemoteId(pattern.type, execArray);
-
- var data = {
- source: pattern.type,
- remote_id: id,
- thumbnailUrl: url
- };
-
- embed_plugin.make(data, true);
- };
-
- embed_plugin.validate = function(savedData) {
-
- var source = savedData.source,
- execArray = services[source].regex.exec(savedData.thumbnailUrl),
- remoteId = methods.getRemoteId(source, execArray);
-
- return remoteId == savedData.remote_id;
-
- };
-
- embed_plugin.pastePatterns = [
- {
- type: 'vk',
- regex: /https?:\/\/vk\.com\/.*(?:video)([-0-9]+_[0-9]+)/, ///https?.+vk?.com\/feed\?w=wall\d+_\d+/,
- callback: embed_plugin.urlPastedCallback
- },
- {
- type: 'youtube',
- regex: /(?:https?:\/{2})?(?:w{3}\.)?youtu(?:be)?\.(?:com|be)(?:\/watch\?v=|\/)([^\s&]+)/,
- callback: embed_plugin.urlPastedCallback
- },
- {
- type: 'vimeo',
- regex: /(?:http[s]?:\/\/)?(?:www.)?vimeo\.co(?:.+\/([^\/]\d+)(?:#t=[\d]+)?s?$)/,
- callback: embed_plugin.urlPastedCallback
- },
- {
- type: 'coub',
- regex: /https?:\/\/coub\.com\/view\/([^\/\?\&]+)/,
- callback: embed_plugin.urlPastedCallback
- },
- {
- type: 'vine',
- regex: /https?:\/\/vine\.co\/v\/([^\/\?\&]+)/,
- callback: embed_plugin.urlPastedCallback
- },
- {
- type: 'imgur',
- regex: /https?:\/\/(?:i\.)?imgur\.com.*\/([a-zA-Z0-9]+)(?:\.gifv)?/,
- callback: embed_plugin.urlPastedCallback
- },
- {
- type: 'gfycat',
- regex: /https?:\/\/gfycat\.com(?:\/detail)?\/([a-zA-Z]+)/,
- callback: embed_plugin.urlPastedCallback
- },
- {
- type: 'twitch-channel',
- regex: /https?:\/\/www.twitch.tv\/([^\/\?\&]*)/,
- callback: embed_plugin.urlPastedCallback
- },
- {
- type: 'twitch-video',
- regex: /https?:\/\/www.twitch.tv\/(?:[^\/\?\&]*\/v|videos)\/([0-9]*)/,
- callback: embed_plugin.urlPastedCallback
- },
- {
- type: 'yandex-music-album',
- regex: /https?:\/\/music.yandex.ru\/album\/([0-9]*)/,
- callback: embed_plugin.urlPastedCallback
- },
- {
- type: 'yandex-music-track',
- regex: /https?:\/\/music.yandex.ru\/album\/([0-9]*)\/track\/([0-9]*)/,
- callback: embed_plugin.urlPastedCallback
- },
- {
- type: 'yandex-music-playlist',
- regex: /https?:\/\/music.yandex.ru\/users\/([^\/\?\&]*)\/playlists\/([0-9]*)/,
- callback: embed_plugin.urlPastedCallback
- } ];
-
- embed_plugin.destroy = function () {
-
- embed = null;
-
- };
-
- return embed_plugin;
-
-}({});
\ No newline at end of file
diff --git a/plugins/embed/loading.gif b/plugins/embed/loading.gif
deleted file mode 100644
index 4e3904d54..000000000
Binary files a/plugins/embed/loading.gif and /dev/null differ
diff --git a/plugins/header/header.css b/plugins/header/header.css
deleted file mode 100644
index 42a1c0ceb..000000000
--- a/plugins/header/header.css
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
-* Plugin styles
-*/
-.ce-header {
- padding: .7em 0;
- margin: 0;
- line-height: 1.4em;
-}
-.ce-header p,
-.ce-header div{
- padding: 0 !important;
- margin: 0 !important;
-}
-
-/** H e a d e r - settings */
-.ce_plugin_header--select_button{
- display: block;
- color: #306ac7;
- cursor: pointer;
- line-height: 1.3em;
-}
- .ce_plugin_header--select_button:not(:last-of-type){
- margin-bottom: 1.5em;
- }
- .ce_plugin_header--select_button:hover{
- color: #a1b4ec;
- }
-
-
-/**
-* Empty header placeholder
-*/
-.ce-header:empty::before{
- content : attr(data-placeholder);
- color: #818BA1;
- opacity: .7;
- transition: opacity 200ms ease;
-}
-.ce-header:focus::before{
- opacity: .1;
-}
diff --git a/plugins/header/header.js b/plugins/header/header.js
deleted file mode 100644
index 6e73ee881..000000000
--- a/plugins/header/header.js
+++ /dev/null
@@ -1,169 +0,0 @@
-/**
-* Example of making plugin
-* H e a d e r
-*/
-
-var header = (function(header_plugin) {
-
- /**
- * @private
- */
- var methods_ = {
-
- /**
- * Binds click event to passed button
- */
- addSelectTypeClickListener : function (el, type) {
-
- el.addEventListener('click', function () {
-
- methods_.selectTypeClicked(type);
-
- }, false);
- },
-
- /**
- * Replaces old header with new type
- * @params {string} type - new header tagName: H1—H6
- */
- selectTypeClicked : function (type) {
-
- var old_header, new_header;
-
- /** Now current header stored as a currentNode */
- old_header = codex.editor.content.currentNode.querySelector('[contentEditable]');
-
- /** Making new header */
- new_header = codex.editor.draw.node(type, ['ce-header'], { innerHTML : old_header.innerHTML });
- new_header.contentEditable = true;
- new_header.setAttribute('data-placeholder', 'Заголовок');
- new_header.dataset.headerData = type;
-
- codex.editor.content.switchBlock(old_header, new_header, 'header');
-
- /** Close settings after replacing */
- codex.editor.toolbar.settings.close();
- }
-
- };
-
- /**
- * @private
- *
- * Make initial header block
- * @param {object} JSON with block data
- * @return {Element} element to append
- */
- var make_ = function (data) {
-
- var availableTypes = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
- tag,
- headerType = 'h2';
-
-
- if ( data && data['heading-styles'] && availableTypes.includes(data['heading-styles']) ) {
-
- headerType = data['heading-styles'];
-
- }
-
- tag = document.createElement(headerType);
-
- /**
- * Save header type in data-attr.
- * We need it in save method to extract type from HTML to JSON
- */
- tag.dataset.headerData = headerType;
-
-
- if (data && data.text) {
- tag.textContent = data.text;
- }
-
- if (!tag.dataset.headerData) {
- tag.dataset.headerData = 'h2';
- }
-
- tag.classList.add('ce-header');
- tag.setAttribute('data-placeholder', 'Заголовок');
- tag.contentEditable = true;
-
- return tag;
-
- };
-
- header_plugin.prepareDataForSave = function(data) {
-
- };
-
- /**
- * Method to render HTML block from JSON
- */
- header_plugin.render = function (data) {
-
- return make_(data);
-
- };
-
- /**
- * Method to extract JSON data from HTML block
- */
- header_plugin.save = function (blockContent) {
-
- var data = {
- "heading-styles": blockContent.dataset.headerData,
- "format": "html",
- "text": blockContent.textContent || ''
- };
-
- return data;
- };
-
- /**
- * Settings panel content
- * - - - - - - - - - - - - -
- * | настройки H1 H2 H3 |
- * - - - - - - - - - - - - -
- * @return {Element} element contains all settings
- */
- header_plugin.makeSettings = function () {
-
- var holder = codex.editor.draw.node('DIV', ['cdx-plugin-settings--horisontal'], {} ),
- types = {
- h2: 'H2',
- h3: 'H3',
- h4: 'H4'
- },
- selectTypeButton;
-
- /** Now add type selectors */
- for (var type in types){
-
- selectTypeButton = codex.editor.draw.node('SPAN', ['cdx-plugin-settings__item'], { textContent : types[type] });
- methods_.addSelectTypeClickListener(selectTypeButton, type);
- holder.appendChild(selectTypeButton);
-
- }
-
- return holder;
- };
-
- header_plugin.validate = function(data) {
-
- if (data.text.trim() === '' || data['heading-styles'].trim() === ''){
- return false;
- }
-
- return true;
- };
-
- header_plugin.destroy = function () {
-
- header = null;
-
- }
-
- return header_plugin;
-
-})({});
-
diff --git a/plugins/image/image.css b/plugins/image/image.css
deleted file mode 100644
index 8534065e9..000000000
--- a/plugins/image/image.css
+++ /dev/null
@@ -1,180 +0,0 @@
-/**
-* Image plugin for codex-editor
-* @author CodeX Team
-*
-* @version 0.0.1
-*/
-
-.ce-image__wrapper img {
- transition: all 500ms ease-in;
- will-change: opacity, filter;
-}
-
-.ce-image__preview img {
- opacity: .5;
- filter: blur(1.7px) grayscale(1);
-}
-
-/** upload image form */
-.ce-plugin-image__holder{
- position: relative;
- background: #FEFEFE;
- border: 2px solid #edeff5;
- text-align: center;
- margin: 30px 0;
- padding: 15px;
-}
- .ce-plugin-image__holder input{
- border: 0;
- background: transparent;
- outline: none;
- -webkit-appearance: none;
- font-size: 1.2em;
- color: #A5ABBC;
- }
- /* Placeholder color for Chrome */
- .ce-plugin-image__holder input::-webkit-input-placeholder {
- color: #A5ABBC;
- }
- /* Placeholder color for IE 10+ */
- .ce-plugin-image__holder input:-ms-input-placeholder {
- color: #A5ABBC;
- }
- /* Placeholder color for Firefox 19+ */
- .ce-plugin-image__holder input::-moz-placeholder {
- color: #A5ABBC;
- opacity: 1;
- }
-
-.ce-plugin-image__loader {
- background-color: transparent;
- background-image: repeating-linear-gradient(-45deg, transparent, transparent 4px, #f5f9ff 4px, #eaedef 8px) !important;
- background-size: 56px 56px;
- animation: loading-bar 5s infinite linear;
-}
-@keyframes loading-bar {
- 100% { background-position: -56% 0 }
-}
-
-
-
-.ce-plugin-image__button{
- cursor: pointer;
- font-size: 1;
- color: #8990AA;
-}
- .ce-plugin-image__button:hover{
- color: #393F52;
- }
-
-
-
-/** Uploaded image */
-.ce-plugin-image__wrapper {
- padding: 1em 0;
-}
-
-.ce-image__wrapper--bordered {
- border: 1px solid #eee;
- box-sizing: border-box;
-}
-
-.ce-plugin-image__uploaded--centered {
- display: block;
- max-width: 600px;
- margin: 0 auto;
-}
-
-.ce-plugin-image__uploaded--stretched {
- width: 100%;
-}
- .ce-plugin-image__firstlevel--stretch {
- margin: 0 !important;
- max-width: none !important;
- padding: 0 !important;
- }
-
-.ce-plugin-image__caption {
- max-width: 600px;
- margin: .5em auto 0;
- padding: .5em;
- text-align: center;
- color: #898a8c;
- background: #fff;
- border: 1px solid #ebeef3;
- border-radius: 3px;
- box-sizing: border-box;
-}
-
- .ce-plugin-image__caption:empty::before {
- content: 'Введите подпись';
- text-align: center;
- font-weight: normal;
- color: #a1a5b3;;
- opacity: .9;
- transition: opacity 200ms ease;
- }
-
- .ce-plugin-image__caption:focus::before {
- opacity: .1;
- text-align: center;
- }
-
-/** Settings */
-.ce_plugin_image--select_button{
- display: block;
- color: #306ac7;
- cursor: pointer;
- line-height: 1.3em;
-}
- .ce_plugin_image--select_button:not(:last-of-type){
- margin-bottom: 1.5em;
- }
- .ce_plugin_image--select_button:hover{
- color: #a1b4ec;
- }
-
-.ce-image-settings {
- padding: 7px 0
-}
-.ce-image-settings__item {
- padding: 7px 15px;
- cursor: pointer;
-}
-
-.ce-settings-checkbox {
- display: inline-block;
- width: 17px;
- background: #494361;
- line-height: 0px;
- border-radius: 14px;
- padding: 2px;
- vertical-align: text-top;
- margin-right: 16px;
- transition: background-color 200ms ease-out;
- will-change: background-color;
-}
-
-.ce-settings-checkbox__toggler {
- display: inline-block;
- width: 12px;
- height: 12px;
- border-radius: 50%;
- background: #fff;
- transition: margin 200ms ease-out;
-}
-
-/**
- * Setting is active
- */
-.ce-image-settings__item--toggled {
- color: #1FAA7E;
-}
-
-.ce-image-settings__item--toggled .ce-settings-checkbox {
- background-color: #14DC9E;
-}
-
-.ce-image-settings__item--toggled .ce-settings-checkbox__toggler {
- margin-left: 6px;
-}
\ No newline at end of file
diff --git a/plugins/image/image.js b/plugins/image/image.js
deleted file mode 100644
index b0b837464..000000000
--- a/plugins/image/image.js
+++ /dev/null
@@ -1,701 +0,0 @@
-/**
- * Image plugin for codex-editor
- * @author CodeX Team
- *
- * @version 1.3.0
- */
-var image = (function(image_plugin) {
-
- /**
- * @private
- *
- * CSS classNames
- */
- var elementClasses_ = {
-
- ce_image : 'ce-image',
- loading : 'ce-plugin-image__loader',
- blockStretched: 'ce-block--stretched',
- uploadedImage : {
- centered : 'ce-plugin-image__uploaded--centered',
- stretched : 'ce-plugin-image__uploaded--stretched'
- },
- imageCaption : 'ce-plugin-image__caption',
- imageWrapper : 'ce-plugin-image__wrapper',
- formHolder : 'ce-plugin-image__holder',
- uploadButton : 'ce-plugin-image__button',
- imagePreview : 'ce-image__preview',
- selectorHolder: 'ce-settings-checkbox',
- selectorButton: 'ce-settings-checkbox__toggler',
- settingsItem: 'ce-image-settings__item',
- imageWrapperBordered : 'ce-image__wrapper--bordered',
- toggled : 'ce-image-settings__item--toggled'
-
- };
-
- /**
- *
- * @private
- *
- * UI methods
- */
- var ui_ = {
-
- holder : function(){
-
- var element = document.createElement('DIV');
-
- element.classList.add(elementClasses_.formHolder);
- element.classList.add(elementClasses_.ce_image);
-
- return element;
- },
-
- uploadButton : function(){
-
- var button = document.createElement('SPAN');
-
- button.classList.add(elementClasses_.uploadButton);
-
- button.innerHTML = ' ';
- button.innerHTML += 'Загрузить фотографию';
-
- return button;
-
- },
-
- /**
- * @param {object} file - file path
- * @param {string} style - css class
- * @return {object} image - document IMG tag
- */
- image : function(file, styles) {
-
- var image = document.createElement('IMG');
-
- styles.map(function(item) {
- image.classList.add(item);
- });
-
- image.src = file.url;
- image.dataset.bigUrl = file.bigUrl;
-
- return image;
- },
-
- wrapper : function() {
-
- var div = document.createElement('div');
-
- div.classList.add(elementClasses_.imageWrapper);
-
- return div;
- },
-
- caption : function() {
-
- var div = document.createElement('div');
-
- div.classList.add(elementClasses_.imageCaption);
- div.contentEditable = true;
-
- return div;
- },
- /**
- * Draws form for image upload
- */
- makeForm : function() {
-
- var holder = ui_.holder(),
- uploadButton = ui_.uploadButton();
-
- holder.appendChild(uploadButton);
-
- uploadButton.addEventListener('click', uploadButtonClicked_, false );
-
- image.holder = holder;
-
- return holder;
- },
-
-
- /**
- * wraps image and caption
- * @param {object} data - image information
- * @param {string} imageTypeClass - plugin's style
- * @param {boolean} stretched - stretched or not
- * @return wrapped block with image and caption
- */
- makeImage : function(data, imageTypeClasses, stretched, bordered) {
-
- var file = data,
- text = data.caption,
- type = data.type,
- image = ui_.image(file, imageTypeClasses),
- caption = ui_.caption(),
- wrapper = ui_.wrapper();
-
- caption.innerHTML = text || '';
-
- wrapper.dataset.stretched = stretched;
- wrapper.dataset.bordered = bordered;
-
- /** Appeding to the wrapper */
- wrapper.appendChild(image);
- wrapper.appendChild(caption);
-
- return wrapper;
- },
-
- /**
- * @param {HTML} data - Rendered block with image
- */
- getImage : function(data) {
-
- var image = data.querySelector('.' + elementClasses_.uploadedImage.centered) ||
- data.querySelector('.' + elementClasses_.uploadedImage.stretched);
-
- return image;
- },
-
- /**
- * wraps image and caption
- * @deprecated
- * @param {object} data - image information
- * @return wrapped block with image and caption
- */
- centeredImage : function(data) {
-
- var file = data.file,
- text = data.caption,
- type = data.type,
- image = ui_.image(file, elementClasses_.uploadedImage.centered),
- caption = ui_.caption(),
- wrapper = ui_.wrapper();
-
- caption.textContent = text;
-
- wrapper.dataset.stretched = 'false';
-
- /** Appeding to the wrapper */
- wrapper.appendChild(image);
- wrapper.appendChild(caption);
-
- return wrapper;
- },
-
- /**
- * wraps image and caption
- * @deprecated
- * @param {object} data - image information
- * @return stretched image
- */
- stretchedImage : function(data) {
-
- var file = data.file,
- text = data.caption,
- type = data.type,
- image = ui_.image(file, elementClasses_.uploadedImage.stretched),
- caption = ui_.caption(),
- wrapper = ui_.wrapper();
-
- caption.textContent = text;
-
- wrapper.dataset.stretched = 'true';
-
- /** Appeding to the wrapper */
- wrapper.appendChild(image);
- wrapper.appendChild(caption);
-
- return wrapper;
-
- }
-
- };
-
- /**
- * @private
- *
- * After render callback
- */
- var uploadButtonClicked_ = function(event) {
-
- var url = image_plugin.config.uploadImage,
- beforeSend = uploadingCallbacks_.ByClick.beforeSend,
- success = uploadingCallbacks_.ByClick.success,
- error = uploadingCallbacks_.ByClick.error;
-
- /** Define callbacks */
- codex.editor.transport.selectAndUpload({
- url : url,
- multiple : false,
- accept : 'image/*',
- beforeSend : beforeSend,
- success : success,
- error : error
- });
- };
-
- var methods_ = {
-
- addSelectTypeClickListener : function(el, type) {
-
- el.addEventListener('click', function() {
-
- // el - settings element
-
- switch (type) {
- case 'bordered':
- methods_.toggleBordered(type, this); break;
- case 'stretched':
- methods_.toggleStretched(type, this); break;
- }
-
-
- }, false);
-
- },
-
- toggleBordered : function(type, clickedSettingsItem ) {
-
- var current = codex.editor.content.currentNode,
- blockContent = current.childNodes[0],
- img = ui_.getImage(current),
- wrapper = current.querySelector('.' + elementClasses_.imageWrapper);
-
- if (!img) {
- return;
- }
-
- /**
- * Add classes to the IMG tag and to the Settings element
- */
- img.classList.toggle(elementClasses_.imageWrapperBordered);
- clickedSettingsItem.classList.toggle(elementClasses_.toggled);
-
- /**
- * Save settings in dataset
- */
- wrapper.dataset.bordered = img.classList.contains(elementClasses_.imageWrapperBordered);
-
- setTimeout(function() {
- codex.editor.toolbar.settings.close();
- }, 200);
-
- },
-
- toggleStretched : function( type, clickedSettingsItem ) {
-
- var current = codex.editor.content.currentNode,
- blockContent = current.childNodes[0],
- img = ui_.getImage(current),
- wrapper = current.querySelector('.' + elementClasses_.imageWrapper);
-
- if (!img) {
- return;
- }
-
- /** Clear classList */
- blockContent.classList.add(elementClasses_.blockStretched);
- img.classList.toggle(elementClasses_.uploadedImage.stretched);
- img.classList.toggle(elementClasses_.uploadedImage.centered);
-
- clickedSettingsItem.classList.toggle(elementClasses_.toggled);
-
- wrapper.dataset.stretched = img.classList.contains(elementClasses_.uploadedImage.stretched);
-
- setTimeout(function() {
- codex.editor.toolbar.settings.close();
- }, 1000);
-
- }
- };
-
- /**
- * @private
- * Callbacks
- */
- var uploadingCallbacks_ = {
-
- ByClick : {
-
- /**
- * Before sending ajax request
- */
- beforeSend : function() {
-
- var input = codex.editor.transport.input,
- files = input.files;
-
- var validFileExtensions = ["jpg", "jpeg", "bmp", "gif", "png"];
-
- var type = files[0].type.split('/');
-
- var result = validFileExtensions.some(function(ext) {
- return ext == type[1];
- });
-
- if (!result) {
- return;
- }
-
- var reader = new FileReader();
- reader.readAsDataURL(files[0]);
-
- reader.onload = function(e) {
-
- var data = {
- background : false,
- border : false,
- isstretch : false,
- url : e.target.result,
- bigUrl : null,
- width : null,
- height : null,
- additionalData : null,
- caption : '',
- cover : null
- };
-
- var newImage = make_(data);
-
- codex.editor.content.switchBlock(image.holder, newImage, 'image');
- newImage.classList.add(elementClasses_.imagePreview);
-
- /**
- * Change holder to image
- */
- image.holder = newImage;
- };
-
- },
-
- /** Photo was uploaded successfully */
- success : function(result) {
-
- var parsed = JSON.parse(result),
- data,
- currentBlock = codex.editor.content.currentNode;
-
- /**
- * Preparing {Object} data to draw an image
- * @uses ceImage.make method
- */
- data = parsed.data;
-
- image.holder.classList.remove(elementClasses_.imagePreview);
-
- /**
- * Change src of image
- */
- var newImage = image.holder.getElementsByTagName('IMG')[0];
-
- newImage.src = parsed.data.url;
- newImage.dataset.bigUrl = parsed.data.bigUrl;
- newImage.dataset.width = parsed.data.width;
- newImage.dataset.height = parsed.data.height;
- newImage.dataset.additionalData = parsed.data.additionalData;
-
- },
-
- /** Error callback. Sends notification to user that something happend or plugin doesn't supports method */
- error : function(result) {
-
- var oldHolder = image.holder;
- var form = ui_.makeForm();
-
- codex.editor.content.switchBlock(oldHolder, form, 'image');
-
- }
- },
-
- ByPaste : {
-
- /**
- * Direct upload
- * Any URL that contains image extension
- * @param url
- */
- uploadImageFromUrl : function(path) {
-
- var image,
- current = codex.editor.content.currentNode,
- beforeSend,
- success_callback;
-
- /** When image is uploaded to redactors folder */
- success_callback = function(data) {
-
- var imageInfo = JSON.parse(data);
-
- var newImage = image.getElementsByTagName('IMG')[0];
-
- newImage.dataset.stretched = false;
- newImage.dataset.src = imageInfo.url;
- newImage.dataset.bigUrl = imageInfo.bigUrl;
- newImage.dataset.width = imageInfo.width;
- newImage.dataset.height = imageInfo.height;
- newImage.dataset.additionalData = imageInfo.additionalData;
-
- image.classList.remove(elementClasses_.imagePreview);
-
- };
-
- /** Before sending XMLHTTP request */
- beforeSend = function() {
-
- var content = current.querySelector('.ce-block__content');
-
- var data = {
- background: false,
- border: false,
- isStretch: false,
- file: {
- url: path,
- bigUrl: null,
- width: null,
- height: null,
- additionalData: null
- },
- caption: '',
- cover: null
- };
-
- image = codex.editor.tools.image_extended.render(data);
-
- image.classList.add(elementClasses_.imagePreview);
-
- var img = image.querySelector('img');
-
- codex.editor.content.switchBlock(codex.editor.content.currentNode, image, 'image');
-
- };
-
- /** Preparing data for XMLHTTP */
- var data = {
- url: image_plugin.config.uploadFromUrl,
- type: "POST",
- data : {
- url: path
- },
- beforeSend : beforeSend,
- success : success_callback
- };
-
- codex.editor.core.ajax(data);
- }
-
- }
- };
-
- /**
- * Image path
- * @type {null}
- */
- image_plugin.path = null;
-
- /**
- * Plugin configuration
- */
- image_plugin.config = null;
-
- /**
- *
- * @private
- *
- * @param data
- * @return {*}
- *
- */
- var make_ = function ( data ) {
-
- var holder,
- classes = [];
-
- if (data) {
-
- if (data.border) {
- classes.push(elementClasses_.imageWrapperBordered);
- }
-
- if ( data.isstretch || data.isstretch === 'true') {
-
- classes.push(elementClasses_.uploadedImage.stretched);
- holder = ui_.makeImage(data, classes, 'true', data.border);
-
- } else {
-
- classes.push(elementClasses_.uploadedImage.centered);
- holder = ui_.makeImage(data, classes, 'false', data.border);
-
- }
-
- return holder;
-
- } else {
-
- holder = ui_.makeForm();
-
- return holder;
- }
- };
-
- /**
- * @private
- *
- * Prepare clear data before save
- *
- * @param data
- */
- var prepareDataForSave_ = function(data) {
-
- };
-
- /**
- * @public
- * @param config
- */
- image_plugin.prepare = function(config) {
-
- image_plugin.config = config;
-
- return Promise.resolve();
- };
-
- /**
- * @public
- *
- * this tool works when tool is clicked in toolbox
- */
- image_plugin.appendCallback = function(event) {
-
- /** Upload image and call success callback*/
- uploadButtonClicked_(event);
-
- };
-
- /**
- * @public
- *
- * @param data
- * @return {*}
- */
- image_plugin.render = function( data ) {
-
- return make_(data);
- };
-
- /**
- * @public
- *
- * @param block
- * @return {{background: boolean, border: boolean, isstretch: boolean, file: {url: (*|string|Object), bigUrl: (null|*), width: *, height: *, additionalData: null}, caption: (string|*|string), cover: null}}
- */
- image_plugin.save = function ( block ) {
-
- var content = block,
- image = ui_.getImage(content),
- caption = content.querySelector('.' + elementClasses_.imageCaption);
-
- var data = {
- background : false,
- border : content.dataset.bordered === 'true' ? true : false,
- isstretch : content.dataset.stretched === 'true' ? true : false,
- // file : {
- url : image.dataset.src || image.src,
- bigUrl : image.dataset.bigUrl,
- width : image.width,
- height : image.height,
- additionalData :null,
- // },
- caption : caption.innerHTML || '',
- cover : null
- };
-
- return data;
- };
-
- /**
- * @public
- *
- * Settings panel content
- * @return {Element} element contains all settings
- */
- image_plugin.makeSettings = function () {
-
- var currentNode = codex.editor.content.currentNode,
- wrapper = currentNode.querySelector('.' + elementClasses_.imageWrapper),
- holder = document.createElement('DIV'),
- types = {
- stretched : "На всю ширину",
- bordered : "Добавить рамку"
- },
- currentImageWrapper = currentNode.querySelector('.' + elementClasses_.imageWrapper ),
- currentImageSettings = currentImageWrapper.dataset;
-
- /** Add holder classname */
- holder.className = 'ce-image-settings';
-
- /** Now add type selectors */
- for (var type in types){
-
- /**
- * Settings template
- */
- var settingsItem = document.createElement('DIV'),
- selectorsHolder = document.createElement('SPAN'),
- selectorsButton = document.createElement('SPAN');
-
- settingsItem.classList.add(elementClasses_.settingsItem);
- selectorsHolder.classList.add(elementClasses_.selectorHolder);
- selectorsButton.classList.add(elementClasses_.selectorButton);
-
- selectorsHolder.appendChild(selectorsButton);
- settingsItem.appendChild(selectorsHolder);
-
- selectTypeButton = document.createTextNode(types[type]);
- settingsItem.appendChild(selectTypeButton);
-
- /**
- * Activate previously selected settings
- */
- if ( currentImageSettings[type] == 'true' ){
- settingsItem.classList.add(elementClasses_.toggled);
- }
-
- methods_.addSelectTypeClickListener(settingsItem, type);
-
- holder.appendChild(settingsItem);
-
- }
-
- return holder;
-
- };
-
- /**
- * Share as API
- */
- image_plugin.uploadImageFromUri = uploadingCallbacks_.ByPaste.uploadImageFromUrl;
-
- image_plugin.pastePatterns = [
- {
- type: 'image',
- regex: /(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*\.(?:jpe?g|gif|png))(?:\?([^#]*))?(?:#(.*))?/i,
- callback: image_plugin.uploadImageFromUri
- },
- {
- type: 'uploadCare',
- regex: /^https:\/\/(uploadcare\.cmtt\.ru|ucarecdn\.com|static[0-9]+\.siliconrus\.cmtt\.ru|static[0-9]+\.cmtt\.ru)/i,
- callback: image_plugin.uploadImageFromUri
- } ];
-
- image_plugin.destroy = function () {
-
- image = null;
-
- };
-
- return image_plugin;
-
-})({});
\ No newline at end of file
diff --git a/plugins/instagram/instagram.css b/plugins/instagram/instagram.css
deleted file mode 100644
index 5d4f265f9..000000000
--- a/plugins/instagram/instagram.css
+++ /dev/null
@@ -1,10 +0,0 @@
-.ce-redactor .instagram {
- width: 100%;
- max-width: 650px;
- margin: 10px auto;
-}
-
-.instagram__loader {
- background: url("loading.gif") !important;
- opacity: 0.1;
-}
\ No newline at end of file
diff --git a/plugins/instagram/instagram.js b/plugins/instagram/instagram.js
deleted file mode 100644
index 9072ef2d0..000000000
--- a/plugins/instagram/instagram.js
+++ /dev/null
@@ -1,162 +0,0 @@
-/**
- * Instagram plugin
- * @version 1.0.0
- */
-var instagram = (function(instagram_plugin) {
-
- var methods = {
-
- render : function(content) {
-
- codex.editor.content.switchBlock(codex.editor.content.currentNode, content);
-
- setTimeout(function() {
- window.instgrm.Embeds.process();
- }, 200);
-
- },
-
- /**
- * Drawing html content.
- *
- * @param url
- * @returns {Element} blockquote - HTML template for Instagram Embed JS
- */
- instagramBlock : function(url) {
-
- var blockquote = codex.editor.draw.node('BLOCKQUOTE', 'instagram-media instagram', {}),
- div = codex.editor.draw.node('DIV', '', {}),
- paragraph = codex.editor.draw.node('P', 'ce-paste__instagram--p', {}),
- anchor = codex.editor.draw.node('A', '', { href : url });
-
- blockquote.dataset.instgrmVersion = 4;
-
- paragraph.appendChild(anchor);
- div.appendChild(paragraph);
- blockquote.appendChild(div);
-
- return blockquote;
-
- }
- };
-
- /**
- * Prepare before usage
- * Load important scripts to render embed
- */
- instagram_plugin.prepare = function() {
-
- return new Promise(function(resolve, reject){
-
- codex.editor.core.importScript("https://platform.instagram.com/en_US/embeds.js", 'instagram-api').then(function(){
- resolve();
- }).catch(function(){
- reject(Error('Instagram API was not loaded'));
- });
-
- });
- };
-
- /**
- * @private
- *
- * Make instagram embed via Widgets method
- */
- var make_ = function(data, isInternal) {
-
- if (!data.instagram_url)
- return;
-
- var block = methods.instagramBlock(data.instagram_url);
-
- if (isInternal) {
-
- setTimeout(function() {
-
- /** Render block */
- methods.render(block);
-
- }, 200);
- }
-
- if (!isInternal) {
- methods.render(block);
- }
-
- return block;
- };
-
- instagram_plugin.validate = function(data) {
- return true;
- };
-
- /**
- * Saving JSON output.
- * Upload data via ajax
- */
- instagram_plugin.save = function(blockContent) {
-
- var data;
-
- if (!blockContent)
- return;
-
- /** Example */
- data = {
- instagram_url: blockContent.src
- };
-
- return data;
-
- };
-
- instagram_plugin.validate = function(data) {
-
- var checkUrl = new RegExp("http?.+instagram.com\/p?.");
-
- if (!data.instagram_url || checkUrl.exec(data.instagram_url).length == 0)
- return;
-
- return true;
- };
-
- /**
- * Render data
- */
- instagram_plugin.render = function(data) {
- return make_(data);
- };
-
- /**
- * callback for instagram url's coming from pasteTool
- * Using instagram Embed Widgete to render
- * @param url
- */
- instagram_plugin.urlPastedCallback = function(url) {
- var data = {
- instagram_url: url
- };
-
- make_(data, true);
-
- };
-
- instagram_plugin.pastePatterns = [
- {
- type: 'instagram',
- regex: /http?.+instagram.com\/p\/([a-zA-Z0-9]*)\S*/,
- callback: instagram_plugin.urlPastedCallback
- }
- ];
-
- instagram_plugin.destroy = function () {
-
- instagram = null;
- delete window.instgrm
-
- };
-
- return instagram_plugin;
-
-})({});
-
diff --git a/plugins/instagram/loading.gif b/plugins/instagram/loading.gif
deleted file mode 100644
index 72ea7ccb5..000000000
Binary files a/plugins/instagram/loading.gif and /dev/null differ
diff --git a/plugins/link/link.css b/plugins/link/link.css
deleted file mode 100644
index 24f1c3b2d..000000000
--- a/plugins/link/link.css
+++ /dev/null
@@ -1,86 +0,0 @@
-.ce-link {
- padding: 0.7em 0 !important;
- border-radius: 3px;
-}
-
-.clearfix:after {
- visibility: hidden;
- display: block;
- font-size: 0;
- content: " ";
- clear: both;
- height: 0;
-}
-
-.ceditor-tool-link-input {
- outline: none;
- border: 0;
- width: 100%;
- background: transparent;
- font-size: 1em;
- padding: 8px 25px;
- transition: background 200ms;
- border-left: 3px solid #65d8b3;
-}
-
-.tool-link-panel {
- position: relative;
- margin: 5px 0;
- background: #f8f7ef;
- border: 1px solid transparent;
- padding: 25px 30px;
-}
-
-.tool-link-image {
- float:right;
- width: 75px;
- border-radius: 3px;
-}
-
-.tool-link-title {
- display: block;
- width: 340px;
- margin-bottom: 4px;
- line-height: 1.2em;
- font-size: 20px;
- font-weight: 700;
- color: #000;
-}
-
-.tool-link-description {
- display: block;
- margin-top: 10px;
- font-size: 14px;
- color: #000;
-}
-
-.tool-link-link {
- width: 360px;
- font-size: 10px;
- margin-bottom: 4px;
- letter-spacing: 1px;
- overflow: hidden;
- text-transform: uppercase;
- text-decoration: none;
- color: rgba(165,156,86,.8);
-}
-
-.tool-link-loader {
- background-color: transparent;
- background-image: repeating-linear-gradient(-45deg, transparent, transparent 4px, #f5f9ff 4px, #eaedef 8px) !important;
- background-size: 56px 56px;
- animation: loading-bar 5s infinite linear;
-}
-@keyframes loading-bar {
- 100% { background-position: -56% 0 }
-}
-
-
-
-.tool-link-error {
- background: rgb(255, 241, 241);
- color: #bf4747;
-}
-.tool-link-error .ceditor-tool-link-input {
- border-left-color: #d86b6b
-}
diff --git a/plugins/link/link.js b/plugins/link/link.js
deleted file mode 100644
index 2763015f9..000000000
--- a/plugins/link/link.js
+++ /dev/null
@@ -1,350 +0,0 @@
-/**
- * Created by nostr on 29.06.16.
- */
-
-/**
- * Link tool plugin
- */
-
-var link = (function(link_plugin) {
-
- var settings = {
- defaultText : 'Вставьте ссылку ...',
- ENTER_KEY : 13,
- currentBlock : null,
- currentInput : null,
- elementClasses : {
- link: "tool-link-link",
- image: "tool-link-image",
- title: "tool-link-title",
- description: "tool-link-description",
- loader: "tool-link-loader",
- error: "tool-link-error"
- }
- };
-
- var ui = {
-
- make : function (json) {
-
- var wrapper = ui.wrapper(),
- siteImage = ui.image(json.image, settings.elementClasses.image),
- siteTitle = ui.title(json.title),
- siteDescription = ui.description(json.description),
- siteLink = ui.link(json.url, json.url);
-
- wrapper.appendChild(siteImage);
- wrapper.appendChild(siteTitle);
- wrapper.appendChild(siteLink);
- wrapper.appendChild(siteDescription);
-
- siteTitle.contentEditable = true;
- siteDescription.contentEditable = true;
-
- return wrapper;
-
- },
-
- mainBlock : function () {
-
- var wrapper = document.createElement('div');
-
- wrapper.classList.add("ceditor-tool-link");
-
- return wrapper;
-
- },
-
- input : function () {
-
- var inputTag = document.createElement('input');
-
- inputTag.classList.add("ceditor-tool-link-input");
-
- inputTag.placeholder = settings.defaultText;
-
- inputTag.contentEditable = false;
-
- return inputTag;
-
- },
-
- wrapper : function () {
-
- var wrapper = document.createElement('div');
-
- wrapper.classList.add('tool-link-panel', 'clearfix');
-
- return wrapper;
-
- },
-
- image : function (imageSrc, imageClass) {
-
- var imageTag = document.createElement('img');
-
- imageTag.classList.add(imageClass);
-
- imageTag.setAttribute('src', imageSrc);
-
- return imageTag;
-
- },
-
- link : function (linkUrl, linkText) {
-
- var linkTag = document.createElement('a');
-
- linkTag.classList.add(settings.elementClasses.link);
-
- linkTag.href = linkUrl;
-
- linkTag.target = "_blank";
-
- linkTag.innerText = linkText;
-
- return linkTag;
-
- },
-
- title : function (titleText) {
-
- var titleTag = document.createElement('div');
-
- titleTag.classList.add("tool-link-content", settings.elementClasses.title);
-
- titleTag.innerHTML = titleText;
-
- return titleTag;
- },
-
- description : function (descriptionText) {
-
- var descriptionTag = document.createElement('div');
-
- descriptionTag.classList.add("tool-link-content", settings.elementClasses.description);
-
- descriptionTag.innerHTML = descriptionText;
-
- return descriptionTag;
- }
-
- };
-
- var methods = {
-
- blockPasteCallback : function (event) {
-
- var clipboardData = event.clipboardData || window.clipboardData,
- pastedData = clipboardData.getData('Text'),
- block = event.target.parentNode;
-
- methods.renderLink(pastedData, block);
-
- event.stopPropagation();
-
- },
-
- blockKeyDownCallback : function (event) {
-
- var inputTag = event.target,
- block = inputTag.parentNode,
- url;
-
- if ( block.classList.contains(settings.elementClasses.error) ) {
- block.classList.remove(settings.elementClasses.error);
- }
-
- if (event.keyCode == settings.ENTER_KEY) {
-
- url = inputTag.value;
-
- methods.renderLink(url, block);
-
- event.preventDefault();
- }
- },
-
- renderLink : function (url, block) {
-
- Promise.resolve()
-
- .then(function () {
- return methods.urlify(url);
- })
-
- .then(function (url) {
-
- /* Show loader gif **/
- block.classList.add(settings.elementClasses.loader);
-
- return fetch( link_plugin.config.fetchUrl + '?url=' + encodeURI(url) );
- })
-
- .then(function (response) {
-
- if (response.status == "200"){
-
- return response.json();
-
- } else {
-
- return Error("Invalid response status: %o", response);
-
- }
-
- })
-
- .then(function (json) {
- methods.composeLinkPreview(json, block);
- })
-
- .catch(function(error) {
-
- /* Hide loader gif **/
- block.classList.remove(settings.elementClasses.loader);
-
- block.classList.add(settings.elementClasses.error);
-
- codex.editor.core.log('Error while doing things with link paste: %o', 'error', error);
- });
-
- },
-
- urlify : function (text) {
-
- var urlRegex = /(https?:\/\/\S+)/g;
-
- var links = text.match(urlRegex);
-
- if (links) {
- return links[0];
- }
-
- return Promise.reject(Error("Url is not matched"));
-
- },
-
- composeLinkPreview : function (json, currentBlock) {
-
- if (json == {}) {
- return;
- }
-
- var previewBlock = ui.make(json);
-
- settings.currentInput.remove();
-
- currentBlock.appendChild(previewBlock);
-
- currentBlock.classList.remove(settings.elementClasses.loader);
-
- }
- };
-
- link_plugin.prepare = function (config) {
-
- link_plugin.config = config;
-
- return Promise.resolve();
-
- };
-
- /**
- * Make initial header block
- * @param {object} JSON with block data
- * @return {Element} element to append
- */
- link_plugin.makeNewBlock = function (data) {
-
- var wrapper = ui.mainBlock(),
- tag = ui.input();
-
- settings.currentInput = tag;
-
- wrapper.appendChild(tag);
-
- wrapper.classList.add('ce-link');
- /**
- * Bind callbacks
- **/
- tag.addEventListener('paste', methods.blockPasteCallback, false);
- tag.addEventListener('keydown', methods.blockKeyDownCallback, false);
-
- return wrapper;
-
- };
-
- /**
- * Method to render HTML block from JSON
- */
- link_plugin.render = function (json) {
-
- if ( json ) {
-
- var block = ui.mainBlock(),
- tag = ui.make(json);
-
- block.classList.add('ce-link');
- block.appendChild(tag);
-
- return block;
-
- } else {
-
- var wrapper = ui.mainBlock(),
- tag = ui.input();
-
- settings.currentInput = tag;
-
- wrapper.appendChild(tag);
-
- wrapper.classList.add('ce-link');
- /**
- * Bind callbacks
- **/
- tag.addEventListener('paste', methods.blockPasteCallback, false);
- tag.addEventListener('keydown', methods.blockKeyDownCallback, false);
-
- return wrapper;
- }
-
-
- };
-
- link_plugin.validate = function (data) {
-
- if (data.url.trim() == '' || data.title.trim() == '' || data.description.trim() == '')
- return;
-
- return true;
- };
-
- /**
- * Method to extract JSON data from HTML block
- */
- link_plugin.save = function (blockContent){
-
- var linkElement = settings.elementClasses.link;
-
- var data = {
- url : blockContent.querySelector("." + linkElement).href,
- shortLink : blockContent.querySelector("." + linkElement).textContent || '',
- image : blockContent.querySelector("." + settings.elementClasses.image).src || '',
- title : blockContent.querySelector("." + settings.elementClasses.title).textContent || '',
- description : blockContent.querySelector("." + settings.elementClasses.description).textContent || ''
- };
-
- return data;
-
- };
-
- link_plugin.destroy = function () {
-
- link = null;
-
- };
-
- return link_plugin;
-
-})({});
diff --git a/plugins/list/list.css b/plugins/list/list.css
deleted file mode 100644
index ce7142609..000000000
--- a/plugins/list/list.css
+++ /dev/null
@@ -1,45 +0,0 @@
-.cdx-plugin-list {
- margin: 0;
- padding: .5em 0;
- line-height: 1.7em;
-}
-
-ul.cdx-plugin-list {
- list-style-type: disc;
-}
-
-ol.cdx-plugin-list {
- list-style-type: decimal;
-}
-
-.cdx-plugin-list__li {
- display: list-item;
- background: #fff;
- border: 1px solid #ebeef3;
- border-radius: 3px;
- margin: .5em;
- padding: .5em;
- list-style-position: outside;
- list-style-type: inherit;
- margin-left: 1.1em;
-}
-
-.cdx-plugin-list p {
- margin: 0.6em 0;
-}
-
-.cdx-plugin-list p:first-of-type {
- margin-top: 0;
-}
-
-.cdx-plugin-list p:last-of-type {
- margin-bottom: 0;
-}
-
-/**
-* List style settigns icons
-*/
-.ce_plugin_list--select_button i{
- margin-right: 1.3em;
-}
-
diff --git a/plugins/list/list.js b/plugins/list/list.js
deleted file mode 100644
index 5cdef4354..000000000
--- a/plugins/list/list.js
+++ /dev/null
@@ -1,241 +0,0 @@
-/**
- * Code Plugin\
- * Creates code tag and adds content to this tag
- */
-var list = (function(list_plugin) {
-
- /**
- * CSS class names
- */
- var elementClasses_ = {
- pluginWrapper: 'cdx-plugin-list',
- li: 'cdx-plugin-list__li',
- settings: 'cdx-plugin-list__settings',
- settingsItem: 'cdx-plugin-settings__item'
- };
-
- var LIST_ITEM_TAG = 'LI';
-
- var ui = {
-
- make: function (blockType) {
-
- var wrapper = this.block(blockType || 'UL', elementClasses_.pluginWrapper);
-
- wrapper.dataset.type = blockType;
- wrapper.contentEditable = true;
-
- wrapper.addEventListener('keydown', methods_.keyDown);
-
- return wrapper;
-
- },
-
- block: function (blockType, blockClass) {
-
- var block = document.createElement(blockType);
-
- if (blockClass) block.classList.add(blockClass);
-
- return block;
-
- },
-
- button: function (buttonType) {
-
- var types = {
- unordered: 'Обычный',
- ordered: 'Нумерованный'
- },
- button = document.createElement('DIV');
-
- button.innerHTML = types[buttonType];
-
- button.classList.add(elementClasses_.settingsItem);
-
- return button;
- }
- };
-
- var methods_ = {
-
- /**
- * Changes block type => OL or UL
- * @param event
- * @param blockType
- */
- changeBlockStyle : function (event, blockType) {
-
- var currentBlock = codex.editor.content.currentNode,
- newEditable = ui.make(blockType),
- oldEditable = currentBlock.querySelector("[contenteditable]");
-
- newEditable.dataset.type = blockType;
- newEditable.innerHTML = oldEditable.innerHTML;
- newEditable.classList.add(elementClasses_.pluginWrapper);
-
- codex.editor.content.switchBlock(currentBlock, newEditable, 'list');
- },
- keyDown: function (e) {
-
- var controlKeyPressed = e.ctrlKey || e.metaKey,
- keyCodeForA = 65;
-
- /**
- * If CTRL+A (CMD+A) was pressed, we should select only one list item,
- * not all or
- */
- if (controlKeyPressed && e.keyCode == keyCodeForA) {
-
- e.preventDefault();
-
- /**
- * Select - content
- */
- methods_.selectListItem();
-
- }
-
- },
-
- /**
- * Select all content of
- with caret
- */
- selectListItem : function () {
-
- var selection = window.getSelection(),
- currentSelectedNode = selection.anchorNode.parentNode,
- range = new Range();
-
- /**
- * Search for
- element
- */
- while ( currentSelectedNode && currentSelectedNode.tagName != LIST_ITEM_TAG ) {
-
- currentSelectedNode = currentSelectedNode.parentNode;
-
- }
-
- range.selectNodeContents(currentSelectedNode);
-
- selection.removeAllRanges();
- selection.addRange(range);
-
- }
- };
-
- /**
- * Method to render HTML block from JSON
- */
- list_plugin.render = function (data) {
-
- var type = data && (data.type == 'ordered' || data.type == 'OL') ? 'OL' : 'UL',
- tag = ui.make(type),
- newLi;
-
- if (data && data.items) {
-
- data.items.forEach(function (element, index, array) {
-
- newLi = ui.block('li', elementClasses_.li);
-
- newLi.innerHTML = element || '';
-
- tag.appendChild(newLi);
-
- });
-
- } else {
-
- newLi = ui.block('li', elementClasses_.li);
-
- tag.appendChild(newLi);
-
- }
-
- return tag;
-
- };
-
- list_plugin.validate = function(data) {
-
- var isEmpty = data.items.every(function(item){
- return item.trim() === '';
- });
-
- if (isEmpty){
- return;
- }
-
- if (data.type != 'UL' && data.type != 'OL'){
- console.warn('CodeX Editor List-tool: wrong list type passed %o', data.type);
- return;
- }
-
- return true;
- };
-
- /**
- * Method to extract JSON data from HTML block
- */
- list_plugin.save = function (blockContent){
-
- var data = {
- type : null,
- items : []
- },
- litsItemContent = '',
- isEmptyItem = false;
-
- for (var index = 0; index < blockContent.childNodes.length; index++){
-
- litsItemContent = blockContent.childNodes[index].innerHTML;
- isEmptyItem = !blockContent.childNodes[index].textContent.trim();
-
- if (!isEmptyItem) {
- data.items.push(litsItemContent);
- }
- }
-
- data.type = blockContent.dataset.type;
-
- return data;
-
- };
-
- list_plugin.makeSettings = function () {
-
- var holder = document.createElement('DIV');
-
- /** Add holder classname */
- holder.className = elementClasses_.settings;
-
- var orderedButton = ui.button("ordered"),
- unorderedButton = ui.button("unordered");
-
- orderedButton.addEventListener('click', function (event) {
- methods_.changeBlockStyle(event, 'OL');
- codex.editor.toolbar.settings.close();
- });
-
- unorderedButton.addEventListener('click', function (event) {
- methods_.changeBlockStyle(event, 'UL');
- codex.editor.toolbar.settings.close();
- });
-
- holder.appendChild(orderedButton);
- holder.appendChild(unorderedButton);
-
- return holder;
-
- };
-
- list_plugin.destroy = function () {
-
- list = null;
-
- };
-
- return list_plugin;
-
-})({});
diff --git a/plugins/paragraph/paragraph.css b/plugins/paragraph/paragraph.css
deleted file mode 100644
index 7651db453..000000000
--- a/plugins/paragraph/paragraph.css
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
-* Empty paragraph placeholder
-*/
-
-.ce-paragraph {
- padding: 0.7em 0 !important;
- line-height: 1.7em;
-}
-
-.ce-paragraph:empty::before,
-.ce-paragraph p:empty::before{
- content : attr(data-placeholder);
- color: #818BA1;
- opacity: .7;
- transition: opacity 200ms ease;
-}
-.ce-paragraph:focus::before{
- opacity: .1;
-}
-
-.toolbar-opened .ce-paragraph::before {
- display: none;
-}
-
-
-.ce-paragraph p {
- margin: 1.2em 0;
-}
-.ce-paragraph p:first-of-type{
- margin-top: 0;
-}
-.ce-paragraph p:last-of-type{
- margin-bottom: 0;
-}
\ No newline at end of file
diff --git a/plugins/paragraph/paragraph.js b/plugins/paragraph/paragraph.js
deleted file mode 100644
index bbd5cd47a..000000000
--- a/plugins/paragraph/paragraph.js
+++ /dev/null
@@ -1,132 +0,0 @@
-/**
-* Paragraph Plugin
-* Creates DIV tag and adds content to this tag
-*/
-
-var paragraph = (function(paragraph_plugin) {
-
- /**
- * @private
- *
- * Make initial paragraph block
- * @param {object} JSON with block data
- * @return {Element} element to append
- */
-
- var make_ = function (data) {
-
- /** Create Empty DIV */
- var tag = codex.editor.draw.node('DIV', ['ce-paragraph'], {});
-
- if (data && data.text) {
- tag.innerHTML = data.text;
- }
-
- tag.contentEditable = true;
-
- return tag;
-
- };
-
- /**
- * @private
- *
- * Handles input data for save
- * @param data
- */
- var prepareDataForSave_ = function(data) {
-
- };
-
- /**
- * @public
- *
- * Plugins should have prepare method
- * @param config
- */
- paragraph_plugin.prepare = function(config) {
-
- };
-
- /*
- * @public
- *
- * Method to render HTML block from JSON
- */
- paragraph_plugin.render = function (data) {
-
- return make_(data);
-
- };
-
- /**
- * @public
- *
- * Check output data for validity.
- * Should be defined by developer
- */
- paragraph_plugin.validate = function(output) {
-
- let text = output.text;
-
- text = text.replace(' ', ' ');
- text = text.replace(/\s/g, ' ');
- text = text.trim();
-
- /**
- * Check for empty
:
- *
- */
- let div = document.createElement('div');
- div.innerHTML = text;
-
- text = div.textContent.trim();
-
- if (!text) {
- return false;
- }
-
-
- return output;
- };
-
- /**
- * @public
- *
- * Method to extract JSON data from HTML block
- */
- paragraph_plugin.save = function (blockContent){
-
- var wrappedText = codex.editor.content.wrapTextWithParagraphs(blockContent.innerHTML),
- sanitizerConfig = {
- tags : {
- p : {},
- a: {
- href: true,
- target: '_blank',
- rel: 'nofollow'
- },
- i: {},
- b: {},
- }
- };
-
- var data = {
- "text": codex.editor.sanitizer.clean(wrappedText, sanitizerConfig),
- "format": "html",
- "introText": '<>'
- };
-
- return data;
-
- };
-
- paragraph_plugin.destroy = function () {
-
- paragraph = null;
-
- };
-
- return paragraph_plugin;
-
-})({});
diff --git a/plugins/quote/img/codex.png b/plugins/quote/img/codex.png
deleted file mode 100644
index 68f532173..000000000
Binary files a/plugins/quote/img/codex.png and /dev/null differ
diff --git a/plugins/quote/img/upload.png b/plugins/quote/img/upload.png
deleted file mode 100644
index 7d28e986b..000000000
Binary files a/plugins/quote/img/upload.png and /dev/null differ
diff --git a/plugins/quote/quote.css b/plugins/quote/quote.css
deleted file mode 100644
index 3439e7970..000000000
--- a/plugins/quote/quote.css
+++ /dev/null
@@ -1,210 +0,0 @@
-.ce_plugin_quote--select_button{
- display: block;
- color: #306ac7;
- cursor: pointer;
- line-height: 1.3em;
-}
-.ce_plugin_quote--select_button:not(:last-of-type){
- margin-bottom: 1.5em;
-}
-.ce_plugin_quote--select_button:hover{
- color: #a1b4ec;
-}
-
-
-/** Quote Styles */
-
-.quoteStyle-withCaption--author:empty {
- direction: rtl;
-}
-.quoteStyle-withCaption--author {
- margin: 5px 0;
- background: #fff;
- border: 1px solid #ebeef3;
- padding: 7px;
- text-align: right;
- font-size: 1em;
- font-weight: bold;
- line-height: 1.5em;
-
-}
-.quoteStyle-simple--text,
-.quoteStyle-withCaption--blockquote,
-.quoteStyle-withPhoto--quote {
- /*font-size: 1.04em;
- line-height: 1.9em;*/
-}
-
-.quoteStyle-simple--text {
- padding: 1.2em 2.1em;
- margin: 2.5em 2em;
- background: #FBFBFB;
-}
-
-.quoteStyle-withCaption--blockquote {
- margin: 0;
- padding: 1.5em 2.0em !important;
- border: 1px solid #ebeef3;
- background: #fff;
-}
-
-.quoteStyle-withCaption--blockquote:focus,
-.quoteStyle-withCaption--author:focus {
- outline: none;
-}
-
-.quoteStyle-simple--text:empty::before,
-.quoteStyle-withCaption--blockquote:empty::before,
-.quoteStyle-withPhoto--quote:empty::before
-{
- content : 'Введите цитату';
- color: #818BA1;
- opacity: 0.7;
- transition: opacity 200ms ease;
-}
-
-.quoteStyle-withCaption--author:empty::before
-{
- content : 'Введите имя автора';
- font-weight: normal;
- color: #a1a5b3;;
- opacity: 1;
- transition: opacity 200ms ease;
-}
-.quoteStyle-withPhoto--author:empty::before {
- content : 'Введите имя автора';
- color: #000;
- opacity: .8;
- transition: opacity 200ms ease;
-}
-
-.quoteStyle-simple--text:focus::before,
-.quoteStyle-withCaption--blockquote:focus::before,
-.quoteStyle-withPhoto--quote:focus::before
-{
- opacity: .1;
-}
-
-.quoteStyle-withCaption--author:focus::before,
-.quoteStyle-withPhoto--author:focus::before
-{
- opacity: .1;
-}
-
-/** Quote with photo */
-.ce_redactor .quoteStyle-withPhoto--wrapper {
- margin: 0;
- padding: 4.5em 3.6em !important;
-}
-
-.quoteStyle-withPhoto--photo {
- width: 94px;
- height: 94px;
- overflow: hidden;
- text-align: center;
- line-height: 94px;
- border-radius: 3px;
- float: left;
- margin-right: 10px;
- border: 1px solid #ebeef3;
- box-sizing: border-box;
- background: #fff;
-}
-.quoteStyle-withPhoto--photo:hover {
- cursor: pointer;
- background: #F0F3F6;
-}
-
-.quoteStyle-withPhoto--photo:hover::after {
- display: block;
-}
-
-.authorsPhoto {
- height: 110%;
- vertical-align: top;
-}
-
-.authorsPhoto-wrapper {
- border: 0 !important;
- transition: all 20ms ease-in;
- will-change: opacity, filter;
-}
-
-.authorsPhotoWrapper_preview {
- opacity: .5;
- filter: blur(1.7px) grayscale(1);
-}
-
-.quoteStyle-withPhoto--photo .ce-icon-picture {
- font-family: "codex_editor";
- font-size: 1.5em;
- color: #d5dbea;
-}
-.quoteStyle-withPhoto--photo:hover{
- background: #fdfeff;
- border-color: #c1c4cc;
-}
-.quoteStyle-withPhoto--photo:hover .ce-icon-picture {
- color: #2b3142;
-}
-
-.quoteStyle-withPhoto--author {
- outline: none;
- overflow: hidden;
- margin-bottom: 10px;
- font-weight: bold;
- color: #000;
-}
-.quoteStyle-withPhoto--job {
- outline: none;
- overflow: hidden;
-}
-
-.quoteStyle-withPhoto--job:empty::before {
- content : 'Введите должность автора';
- color: #A5ABBC;
- opacity: 1;
- transition: opacity 200ms ease;
-}
-
-.quoteStyle-withPhoto--job:focus::before {
- opacity: .1;
-}
-
-.quoteStyle-withPhoto--quote {
- margin-bottom: 10px;
- line-height: 1.7em;
- outline: none;
- overflow: hidden;
-}
-
-/**
-* New styles
-*/
-.ce-quote{
- margin: 0 !important;
- padding: 15px 0;
-}
-.quoteStyle-withPhoto--author,
-.quoteStyle-withPhoto--job,
-.quoteStyle-withPhoto--quote{
- background: #fff;
- border: 1px solid #ebeef3;
- border-radius: 3px;
- padding: 10px 15px;
-}
-
-.quoteStyle-withPhoto--author,
-.quoteStyle-withPhoto--job {
- line-height: 20px;
-}
-.quoteStyle-withPhoto--quote{
- min-height: 200px;
-}
-
-/**
- * Current select-type button
- */
-.ce-quote-settings--selected{
- font-weight: bold;
-}
\ No newline at end of file
diff --git a/plugins/quote/quote.js b/plugins/quote/quote.js
deleted file mode 100644
index 45c7a8b62..000000000
--- a/plugins/quote/quote.js
+++ /dev/null
@@ -1,585 +0,0 @@
-/**
- *
- * Quote plugin
- */
-
-var quote = (function(quote_plugin) {
-
- /**
- * @private
- *
- * CSS styles
- */
- var elementClasses_ = {
-
- ce_quote : 'ce-quote',
- quoteText : 'ce_quote--text',
- quoteAuthor : 'ce_quote--author',
- authorsJob : 'ce_quote--job',
- authorsPhoto : 'authorsPhoto',
- authorsPhotoWrapper : 'authorsPhoto-wrapper',
- authorsPhotoWrapper_preview : 'authorsPhotoWrapper_preview',
-
- simple : {
- text : 'quoteStyle-simple--text'
- },
-
- withCaption : {
- blockquote : 'quoteStyle-withCaption--blockquote',
- author : 'quoteStyle-withCaption--author'
- },
-
- withPhoto : {
- photo : 'quoteStyle-withPhoto--photo',
- author : 'quoteStyle-withPhoto--author',
- job : 'quoteStyle-withPhoto--job',
- quote : 'quoteStyle-withPhoto--quote',
- wrapper : 'quoteStyle-withPhoto--wrapper',
- authorHolder : 'quoteStyle-withPhoto--authorWrapper'
- },
-
- settings : {
- holder : 'cdx-plugin-settings--horisontal',
- caption : 'ce_plugin_quote--caption',
- buttons : 'cdx-plugin-settings__item',
- selectedType : 'ce-quote-settings--selected'
- }
- };
-
- /**
- * @private
- *
- *
- */
- var methods_ = {
-
- changeStyleClicked : function() {
-
- var changeStyleButton = this,
- quote = codex.editor.content.currentNode.querySelector('.' + elementClasses_.ce_quote),
- newStyle = changeStyleButton.dataset.style,
- styleSelectors = this.parentNode.childNodes;
-
- quote.dataset.quoteStyle = newStyle;
-
- /**
- * Mark selected style button
- */
- for (var i = styleSelectors.length - 1; i >= 0; i--) {
- styleSelectors[i].classList.remove(elementClasses_.settings.selectedType);
- }
-
- this.classList.add(elementClasses_.settings.selectedType);
-
- },
-
- /**
- * @deprecated
- */
- selectTypeQuoteStyle : function(type) {
-
- var quoteStyleFunction;
-
- /**
- * Choose Quote style to replace
- */
- switch (type) {
- case 'simple':
- quoteStyleFunction = methods_.makeSimpleQuote;
- break;
- case 'withCaption':
- quoteStyleFunction = methods_.makeQuoteWithCaption;
- break;
- case 'withPhoto':
- quoteStyleFunction = methods_.makeQuoteWithPhoto;
- break;
- }
-
- return quoteStyleFunction;
-
- },
-
- /**
- * @deprecated
- */
- addSelectTypeClickListener : function(el, quoteStyle) {
-
- el.addEventListener('click', function () {
-
- /**
- * Parsing currentNode to JSON.
- */
- var parsedOldQuote = methods_.parseBlockQuote(),
- newStyledQuote = quoteStyle(parsedOldQuote);
-
- var wrapper = codex.editor.content.composeNewBlock(newStyledQuote, 'quote');
- wrapper.appendChild(newStyledQuote);
-
- codex.editor.content.switchBlock(codex.editor.content.currentNode, newStyledQuote, 'quote');
-
- /** Close settings after replacing */
- codex.editor.toolbar.settings.close();
-
- }, false);
-
- },
-
- /**
- * @deprecated
- */
- makeSimpleQuote : function(data) {
-
- var wrapper = ui_.makeBlock('BLOCKQUOTE', [elementClasses_.simple.text, elementClasses_.quoteText]);
-
- wrapper.innerHTML = data.text || '';
-
- wrapper.dataset.quoteStyle = 'simple';
- wrapper.classList.add(elementClasses_.ce_quote);
- wrapper.contentEditable = 'true';
-
- return wrapper;
- },
-
- /**
- * @deprecated
- */
- makeQuoteWithCaption : function(data) {
-
- var wrapper = ui_.blockquote(),
- text = ui_.makeBlock('DIV', [elementClasses_.withCaption.blockquote, elementClasses_.quoteText]),
- author = ui_.makeBlock('DIV', [elementClasses_.withCaption.author, elementClasses_.quoteAuthor]);
-
- /* make text block ontentEditable */
- text.contentEditable = 'true';
-
- text.innerHTML = data.text || '';
-
- /* make Author contentEditable */
- author.contentEditable = 'true';
-
- author.innerHTML = data.cite || '';
-
- /* Appending created components */
- wrapper.dataset.quoteStyle = 'withCaption';
- wrapper.classList.add(elementClasses_.ce_quote);
-
- wrapper.appendChild(text);
- wrapper.appendChild(author);
-
- return wrapper;
-
- },
-
- makeQuoteWithPhoto : function(data) {
-
- var wrapper = ui_.blockquote(),
- photo = ui_.makeBlock('DIV', [elementClasses_.withPhoto.photo]),
- author = ui_.makeBlock('DIV', [elementClasses_.withPhoto.author, elementClasses_.quoteAuthor]),
- job = ui_.makeBlock('DIV', [elementClasses_.withPhoto.job, elementClasses_.authorsJob]),
- quote = ui_.makeBlock('DIV', [elementClasses_.withPhoto.quote, elementClasses_.quoteText]);
-
- /* Default Image src */
- if (!data.image) {
-
- var icon = ui_.makeBlock('SPAN', ['ce-icon-picture']);
- photo.appendChild(icon);
-
- } else {
-
- var authorsPhoto = ui_.img(elementClasses_.authorsPhoto);
-
- authorsPhoto.src = data.image;
- authorsPhoto.dataset.bigUrl = data.image;
-
- photo.classList.add(elementClasses_.authorsPhotoWrapper);
- photo.appendChild(authorsPhoto);
- }
-
-
- photo.addEventListener('click', fileUploadClicked_, false);
-
- /* make author block contentEditable */
- author.contentEditable = 'true';
- author.innerHTML = data.cite || '';
-
- /* Author's position and job */
- job.contentEditable = 'true';
- job.innerHTML = data.caption || '';
-
- var authorsWrapper = ui_.makeBlock('DIV', [elementClasses_.withPhoto.authorHolder]);
- authorsWrapper.appendChild(author);
- authorsWrapper.appendChild(job);
-
- /* make quote text contentEditable */
- quote.contentEditable = 'true';
- quote.innerHTML = data.text || '';
-
- wrapper.classList.add(elementClasses_.ce_quote);
- wrapper.classList.add(elementClasses_.withPhoto.wrapper);
- wrapper.dataset.quoteStyle = 'withPhoto';
-
- wrapper.appendChild(quote);
- wrapper.appendChild(photo);
- wrapper.appendChild(authorsWrapper);
-
- return wrapper;
- },
-
- parseBlockQuote : function(block) {
-
- var currentNode = block || codex.editor.content.currentNode,
- photo = currentNode.getElementsByTagName('img')[0],
- author = currentNode.querySelector('.' + elementClasses_.quoteAuthor),
- job = currentNode.querySelector('.' + elementClasses_.authorsJob),
- quote ;
-
- /** Simple quote text placed in Blockquote tag*/
- if ( currentNode.dataset.quoteStyle == 'simple' ){
-
- quote = currentNode.innerHTML || '';
-
- } else {
-
- quote = currentNode.querySelector('.' + elementClasses_.quoteText).innerHTML;
-
- }
-
- if (job){
-
- job = job.innerHTML || '';
-
- }
-
- if (author){
-
- author = author.innerHTML || '';
-
- }
-
- if (photo){
-
- photo = photo.dataset.bigUrl;
-
- }
-
- var data = {
- style : currentNode.dataset.quoteStyle,
- text : quote,
- author : author,
- job : job,
- photo : photo
- };
-
- return data;
- }
- };
-
- /**
- * @private
- *
- * Author image Uploader
- */
- var fileUploadClicked_ = function() {
-
- var beforeSend = photoUploadingCallbacks_.beforeSend,
- success = photoUploadingCallbacks_.success,
- error = photoUploadingCallbacks_.error;
-
- codex.editor.transport.selectAndUpload({
- beforeSend: beforeSend,
- success: success,
- error: error
- });
-
- };
-
- /**
- * @private
- *
- */
- var ui_ = {
-
- wrapper : function($classList) {
-
- var el = document.createElement('DIV');
-
- el.classList.add($classList);
-
- return el;
-
- },
-
- blockquote : function() {
-
- var el = document.createElement('BLOCKQUOTE');
-
- return el;
-
- },
-
- img : function(attribute) {
-
- var imageTag = document.createElement('IMG');
- imageTag.classList.add(attribute);
-
- return imageTag;
- },
-
- makeBlock : function(tag, classList) {
-
- var el = document.createElement(tag);
-
- if ( classList ) {
-
- for( var i = 0; i < classList.length; i++)
- el.className += ' ' + classList[i];
-
- }
-
- return el;
-
- }
-
- };
-
-
-
- /**
- * @private
- *
- * Callbacks
- */
- var photoUploadingCallbacks_ = {
-
- preview_ : function(e) {
-
- var uploadImageWrapper = codex.editor.content.currentNode.querySelector('.' + elementClasses_.withPhoto.photo),
- authorsPhoto = ui_.img(elementClasses_.authorsPhoto);
-
- /** Appending uploaded image */
- uploadImageWrapper.classList.add(elementClasses_.authorsPhotoWrapper, elementClasses_.authorsPhotoWrapper_preview);
-
- authorsPhoto.src = e.target.result;
-
- /** Remove icon from image wrapper */
- uploadImageWrapper.innerHTML = '';
-
- uploadImageWrapper.appendChild(authorsPhoto);
- },
-
- beforeSend : function() {
-
- var input = codex.editor.transport.input,
- files = input.files,
- file = files[0],
- fileReader = new FileReader();
-
- fileReader.readAsDataURL(file);
-
- fileReader.onload = photoUploadingCallbacks_.preview_;
-
- },
-
- /**
- * Success callbacks for uploaded photo.
- * Replace upload icon with uploaded photo
- */
- success : function(result) {
-
- var parsed = JSON.parse(result),
- filename = parsed.filename,
- uploadImageWrapper = codex.editor.content.currentNode.querySelector('.' + elementClasses_.withPhoto.photo);
-
- var img = uploadImageWrapper.querySelector('IMG');
- img.src = parsed.data.file.bigUrl;
- img.dataset.bigUrl = parsed.data.file.bigUrl;
-
- uploadImageWrapper.classList.remove(elementClasses_.authorsPhotoWrapper_preview);
- },
-
- /** Error callback. Sends notification to user that something happend or plugin doesn't supports method */
- error : function(result) {
- console.log('Can\'t upload an image');
- }
-
- };
-
- /**
- * @private
- *
- * Make Quote from JSON datasets
- */
- var make_ = function(data) {
-
- var tag;
-
- if (data && data.size) {
-
- data.style = quote_plugin.config.defaultStyle;
-
- /**
- * Supported types
- */
- switch (data.style) {
-
- case 'simple':
- tag = methods_.makeSimpleQuote(data);
- break;
- case 'withCaption':
- tag = methods_.makeQuoteWithCaption(data);
- break;
- case 'withPhoto':
- tag = methods_.makeQuoteWithPhoto(data);
- break;
- }
-
- tag.dataset.quoteStyle = data.size;
-
- } else {
-
- var settings = {
- "text" : null,
- "format" : "html",
- "cite" : null,
- "caption": null,
- "size" : null,
- "image" : null
- };
-
- tag = methods_.makeQuoteWithPhoto(settings);
- }
-
- return tag;
- };
-
- var prepareDataForSave_ = function(data) {
-
- if (data.size == 'withPhoto') {
- data.size = 'small';
- }
-
- /** Make paragraphs */
- data.text = codex.editor.content.wrapTextWithParagraphs(data.text);
-
- return data;
- };
-
- /**
- * @public
- *
- * Renderer
- *
- * @param data
- */
- quote_plugin.render = function(data) {
- return make_(data);
- };
-
- quote_plugin.validate = function(output) {
-
- if (typeof output.text != "string") {
- return;
- }
-
- return output;
- };
-
- quote_plugin.save = function(blockContent) {
-
- /**
- * Extracts JSON quote data from HTML block
- * @param {Text} text, {Text} author, {Object} photo
- */
- var parsedblock = methods_.parseBlockQuote(blockContent);
-
- var outputData = {
- "text" : parsedblock.text,
- "format" : "html",
- "cite" : parsedblock.author || '',
- "caption": parsedblock.job || '',
- "size" : parsedblock.style,
- "image" : parsedblock.photo
- };
-
- return prepareDataForSave_(outputData);
- };
-
- /**
- * @public
- *
- * Draws settings
- */
- quote_plugin.makeSettings = function(data) {
-
- var holder = document.createElement('DIV'),
- types = {
- big : 'По центру',
- small : 'Врезка'
- },
- selectTypeButton;
-
- /** Add holder classname */
- holder.className = elementClasses_.settings.holder;
-
- /** Now add type selectors */
- for (var type in types){
-
- selectTypeButton = document.createElement('SPAN');
-
- selectTypeButton.textContent = types[type];
- selectTypeButton.className = elementClasses_.settings.buttons;
-
- selectTypeButton.dataset.style = type;
-
- if ( type == quote_plugin.config.defaultStyle ){
- selectTypeButton.classList.add(quoteTools.styles.settings.selectedType);
- }
-
- // var quoteStyle = quoteTools.selectTypeQuoteStyle(type);
-
- selectTypeButton.addEventListener('click', methods_.changeStyleClicked, false);
- // quoteTools.addSelectTypeClickListener(selectTypeButton, quoteStyle);
-
- holder.appendChild(selectTypeButton);
-
- }
-
- return holder;
-
- };
-
- /**
- * @public
- * Default path to redactors images
- * @type {null}
- */
- quote_plugin.path = null;
-
- /**
- * @public
- *
- * @type {null}
- */
- quote_plugin.config = null;
-
- /**
- * @public
- *
- * @param config
- */
- quote_plugin.prepare = function(config) {
-
- quote_plugin.config = config;
-
- return Promise.resolve();
- };
-
- quote_plugin.destroy = function () {
-
- quote = null;
-
- };
-
- return quote_plugin;
-
-})({});
\ No newline at end of file
diff --git a/plugins/raw/raw-icon-black.svg b/plugins/raw/raw-icon-black.svg
deleted file mode 100644
index b93884238..000000000
--- a/plugins/raw/raw-icon-black.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
\ No newline at end of file
diff --git a/plugins/raw/raw-icon-white.svg b/plugins/raw/raw-icon-white.svg
deleted file mode 100644
index afdf1d241..000000000
--- a/plugins/raw/raw-icon-white.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
\ No newline at end of file
diff --git a/plugins/raw/raw.css b/plugins/raw/raw.css
deleted file mode 100644
index 1af876585..000000000
--- a/plugins/raw/raw.css
+++ /dev/null
@@ -1,36 +0,0 @@
-.raw-plugin__input {
- display: block;
- width: 100%;
- min-height: 200px;
- border: 0;
- background: #fdfdfd;
- box-shadow: inset 0 2px 8px rgba(23, 32, 74, 0.06);
- border-radius: 3px;
- margin: 1em auto;
- padding: 1em;
- box-sizing: border-box;
- white-space: pre;
- outline: none;
- resize: vertical;
-
- font-family: 'monospace', 'monaco', 'consolas', 'courier';
- line-height: 1.7em;
- font-size: 12px;
- color: #152b48;
- overflow: auto;
- letter-spacing: 0.015em;
-}
-
-.raw-plugin-icon {
- display: inline-block;
- width: 16px;
- height: 32px;
- background: url(raw-icon-black.svg) no-repeat center center;
- background-size: contain;
-}
-
-li:hover .raw-plugin-icon,
-.selected .raw-plugin-icon{
- background: url(raw-icon-white.svg) no-repeat center center;
- background-size: contain;
-}
diff --git a/plugins/raw/raw.js b/plugins/raw/raw.js
deleted file mode 100644
index d63c29f1a..000000000
--- a/plugins/raw/raw.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
-* Plugin for CodeX.Editor
-* Implements RAW-data block
-*/
-var rawPlugin = function (plugin) {
-
- var editor = codex.editor;
-
- plugin.render = function (data) {
-
- var input = editor.draw.node('TEXTAREA', 'raw-plugin__input', {});
-
- input.placeholder = 'Вставьте HTML код';
-
- if (data && data.raw) {
- input.value = data.raw;
- }
-
- return input;
-
- };
-
- plugin.save = function (block) {
-
- return {
- raw: block.value
- };
-
- };
-
- plugin.validate = function (data) {
-
- if (data.raw.trim() === '') {
-
- return;
-
- }
-
- return true;
-
- };
-
- plugin.destroy = function () {
-
- rawPlugin = null;
-
- };
-
- return plugin;
-
-}({});
\ No newline at end of file
diff --git a/plugins/twitter/twitter.css b/plugins/twitter/twitter.css
deleted file mode 100644
index 34d4a89fd..000000000
--- a/plugins/twitter/twitter.css
+++ /dev/null
@@ -1,20 +0,0 @@
-.ce-redactor .twitter-tweet {
- margin: 15px auto !important;
- width: 100% !important;
-}
-
-.ce-twitter__caption {
- max-width: 520px;
- margin-bottom: 15px;
- background: #fff;
- border: 1px solid #ebeef3;
- border-radius: 3px;
- padding: .6em .8em;
- box-sizing: border-box;
-
-}
-
-.ce-twitter__caption:empty::before {
- content : 'Подпись';
- opacity: .5;
-}
\ No newline at end of file
diff --git a/plugins/twitter/twitter.js b/plugins/twitter/twitter.js
deleted file mode 100644
index 762fe6e9e..000000000
--- a/plugins/twitter/twitter.js
+++ /dev/null
@@ -1,281 +0,0 @@
-/**
- * Twitter plugin
- * @version 1.0.0
- */
-
-var twitter = (function(twitter_plugin) {
-
- /**
- * User's configuration object
- */
- var config_ = {};
-
- /**
- * CSS classes
- */
- var css_ = {
- pluginWrapper : 'cdx-tweet'
- };
-
- var methods = {
-
- /**
- * Twitter render method appends content after block
- * @param tweetId
- */
- twitter : function(data, twitterBlock) {
-
- var tweet = methods.drawTwitterHolder(),
- twittersCaption = methods.drawTwittersCaptionBlock();
-
- if (data.caption) {
- twittersCaption.innerHTML = data.caption;
- }
-
- /**
- * add created tweet to holder
- */
- tweet.appendChild(twitterBlock);
-
- // setTimeout(function() {
- window.twttr.widgets.createTweet(data.id_str, twitterBlock).then(tweetInsertedCallback_);
- // }, 1000);
-
- tweet.classList.add('ce-redactor__loader');
-
- if (codex.editor.content.currentNode) {
- tweet.dataset.statusUrl = data.status_url;
- codex.editor.content.switchBlock(codex.editor.content.currentNode, tweet, 'tweet');
- }
-
- /**
- * in case if we need extra data
- */
- if ( !data.user ) {
-
- codex.editor.core.ajax({
- url : config_.fetchUrl + '?tweetId=' + data.id_str,
- type: "GET",
- success: function(result) {
- methods.saveTwitterData(result, tweet);
- }
- });
-
- } else {
-
- tweet.dataset.profileImageUrl = data.user.profile_image_url;
- tweet.dataset.profileImageUrlHttps = data.user.profile_image_url_https;
- tweet.dataset.screenName = data.user.screen_name;
- tweet.dataset.name = data.user.name;
- tweet.dataset.id = +data.id;
- tweet.dataset.idStr = data.id_str;
- tweet.dataset.text = data.text;
- tweet.dataset.createdAt = data.created_at;
- tweet.dataset.statusUrl = data.status_url;
- tweet.dataset.media = data.media;
-
- tweet.classList.remove('ce-redactor__loader');
- }
-
- /**
- * add caption to tweet
- */
- setTimeout(function() {
- tweet.appendChild(twittersCaption);
- }, 1000);
-
- return tweet;
-
- },
-
- drawTwitterHolder : function() {
-
- var block = document.createElement('DIV');
-
- block.classList.add(css_.pluginWrapper);
-
- return block;
-
- },
-
- drawTwitterBlock : function() {
- var block = codex.editor.draw.node('DIV', '', { height: "20px" });
- return block;
- },
-
- drawTwittersCaptionBlock : function() {
- var block = codex.editor.draw.node('DIV', ['ce-twitter__caption'], { contentEditable : true });
- return block;
- },
-
- saveTwitterData : function(result, tweet) {
-
- var data = JSON.parse(result),
- twitterContent = tweet;
-
- setTimeout(function() {
-
- /**
- * Save twitter data via data-attributes
- */
- twitterContent.dataset.profileImageUrl = data.user.profile_image_url;
- twitterContent.dataset.profileImageUrlHttps = data.user.profile_image_url_https;
- twitterContent.dataset.screenName = data.user.screen_name;
- twitterContent.dataset.name = data.user.name;
- twitterContent.dataset.id = +data.id;
- twitterContent.dataset.idStr = data.id_str;
- twitterContent.dataset.text = data.text;
- twitterContent.dataset.createdAt = data.created_at;
- twitterContent.dataset.media = data.entities.urls.length > 0 ? "false" : "true";
-
- }, 50);
-
- }
- };
-
- /**
- * @private
- * Fires after tweet widget rendered
- */
- function tweetInsertedCallback_(widget) {
-
- var pluginWrapper = findParent_( widget , css_.pluginWrapper );
-
- pluginWrapper.classList.remove('ce-redactor__loader');
-
- }
-
- /**
- * @private
- * Find closiest parent Element with CSS class
- */
- function findParent_ (el, cls) {
- while ((el = el.parentElement) && !el.classList.contains(cls));
- return el;
- }
-
- /**
- * Prepare twitter scripts
- * @param {object} config
- */
- twitter_plugin.prepare = function(config) {
-
- /**
- * Save configs
- */
- config_ = config;
-
- return new Promise(function(resolve, reject){
-
- codex.editor.core.importScript("https://platform.twitter.com/widgets.js", 'twitter-api').then(function(){
- resolve();
- }).catch(function(){
- reject(Error('Twitter API was not loaded'));
- });
-
- });
-
- };
-
- /**
- * @private
- *
- * @param data
- * @returns {*}
- */
- make_ = function(data) {
-
- if (!data.id || !data.status_url)
- return;
-
- if (!data.id_str) {
- data.id_str = data.status_url.match(/[^\/]+$/)[0];
- }
-
- var twitterBlock = methods.drawTwitterBlock();
-
- var tweet = methods.twitter(data, twitterBlock);
-
- return tweet;
- };
-
- twitter_plugin.validate = function(data) {
- return true;
- };
-
- twitter_plugin.save = function(blockContent) {
-
- var data,
- caption = blockContent.querySelector('.ce-twitter__caption');
-
- data = {
- media:blockContent.dataset.media,
- conversation:false,
- user:{
- profile_image_url: blockContent.dataset.profileImageUrl,
- profile_image_url_https: blockContent.dataset.profileImageUrlHttps,
- screen_name: blockContent.dataset.screenName,
- name: blockContent.dataset.name
- },
- id: blockContent.dataset.id || blockContent.dataset.tweetId,
- id_str : blockContent.dataset.idStr,
- text: blockContent.dataset.text,
- created_at: blockContent.dataset.createdAt,
- status_url: blockContent.dataset.statusUrl,
- caption: caption.innerHTML || ''
- };
-
- return data;
- };
-
- twitter_plugin.render = function(data) {
- return make_(data);
- };
-
- twitter_plugin.urlPastedCallback = function(url) {
-
- var tweetId,
- arr,
- data;
-
- arr = url.split('/');
- tweetId = arr.pop();
-
- /** Example */
- data = {
- "media" : true,
- "conversation" : false,
- "user" : null,
- "id" : +tweetId,
- "text" : null,
- "created_at" : null,
- "status_url" : url,
- "caption" : null
- };
-
- make_(data);
- };
-
- twitter_plugin.pastePatterns = [
- {
- type: 'twitter',
- regex: /http?.+twitter.com?.+\//,
- callback: twitter_plugin.urlPastedCallback
- }
- ];
-
- twitter_plugin.destroy = function () {
-
- twitter = null;
- delete window.twttr;
-
- };
-
- return twitter_plugin;
-
-})({});
-
-
-
-
-
diff --git a/server/index.php b/server/index.php
deleted file mode 100644
index e6286c87c..000000000
--- a/server/index.php
+++ /dev/null
@@ -1,95 +0,0 @@
-loadHTML($html);
- $nodes = $doc->getElementsByTagName('title');
-
- $title = $nodes->item(0)->nodeValue;
- $description = "";
- $keywords = "";
- $image = "";
-
- $metas = $doc->getElementsByTagName('meta');
-
- for ($i = 0; $i < $metas->length; $i++)
- {
- $meta = $metas->item($i);
- if($meta->getAttribute('name') == 'description')
- $description = $meta->getAttribute('content');
- if($meta->getAttribute('name') == 'keywords')
- $keywords = $meta->getAttribute('content');
- if($meta->getAttribute('property')=='og:image'){
- $image = $meta->getAttribute('content');
- }
- }
-
- return [
- 'image' => $image,
- 'title' => $title,
- 'description' => $description
- ];
-}
-
-$url = get_url();
-
-$url_params = parse_url($url);
-
-if (!$url)
-{
- exit(0);
-}
-
-$html = file_get_contents_curl($url);
-
-$result = get_meta_from_html($html);
-
-$result = array_merge(
-
- get_meta_from_html($html),
-
- array(
- 'linkUrl' => $url,
- 'linkText' => $url_params["host"] . isset($url_params["path"])?$url_params["path"]:"",
- )
-
-);
-
-echo json_encode($result);
-
-?>
diff --git a/src/assets/arrow-down.svg b/src/assets/arrow-down.svg
new file mode 100644
index 000000000..2ce78b4e8
--- /dev/null
+++ b/src/assets/arrow-down.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/arrow-up.svg b/src/assets/arrow-up.svg
new file mode 100644
index 000000000..4bc8ed14a
--- /dev/null
+++ b/src/assets/arrow-up.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/bold.svg b/src/assets/bold.svg
new file mode 100644
index 000000000..f10a3d6d6
--- /dev/null
+++ b/src/assets/bold.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/cross.svg b/src/assets/cross.svg
new file mode 100644
index 000000000..540556977
--- /dev/null
+++ b/src/assets/cross.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/dots.svg b/src/assets/dots.svg
new file mode 100644
index 000000000..661f880d0
--- /dev/null
+++ b/src/assets/dots.svg
@@ -0,0 +1,7 @@
+
diff --git a/src/assets/italic.svg b/src/assets/italic.svg
new file mode 100644
index 000000000..0c23b1ffc
--- /dev/null
+++ b/src/assets/italic.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/link.svg b/src/assets/link.svg
new file mode 100644
index 000000000..7a6068f47
--- /dev/null
+++ b/src/assets/link.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/plus.svg b/src/assets/plus.svg
new file mode 100644
index 000000000..5f2fe1b4f
--- /dev/null
+++ b/src/assets/plus.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/unlink.svg b/src/assets/unlink.svg
new file mode 100644
index 000000000..780c3812d
--- /dev/null
+++ b/src/assets/unlink.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/codex.js b/src/codex.js
new file mode 100644
index 000000000..ec04ab365
--- /dev/null
+++ b/src/codex.js
@@ -0,0 +1,111 @@
+/**
+ * Codex Editor
+ *
+ * Short Description (눈_눈;)
+ * @version 2.0.0
+ *
+ * How to start?
+ * Example:
+ * new CodexEditor({
+ * holderId : 'codex-editor',
+ * initialBlock : 'text',
+ * placeholder : 'Write your story....',
+ * tools: {
+ * quote: Quote,
+ * anotherTool : AnotherTool
+ * },
+ * toolsConfig: {
+ * quote: {
+ * iconClassname : 'quote-icon',
+ * displayInToolbox : true,
+ * enableLineBreaks : true
+ * },
+ * anotherTool: {
+ * iconClassname : 'tool-icon'
+ * }
+ * }
+ * });
+ *
+ * - tools is an object: {
+ * pluginName: PluginClass,
+ * .....
+ * }
+ * - toolsConfig is an additional configuration that uses Codex Editor API
+ * iconClassname - CSS classname of toolbox icon
+ * displayInToolbox - if you want to see your Tool in toolbox hided in "plus" button, than set "True". By default : "False"
+ * enableLineBreaks - by default enter creates new block that set as initialblock, but if you set this property "True", enter will break the lines in current block
+ *
+ * @author CodeX-Team
+ *
+ */
+
+'use strict';
+
+/**
+ * Apply polyfills
+ */
+import 'babel-core/register';
+import 'babel-polyfill';
+import 'components/polyfills';
+import Core from './components/core';
+
+export default class CodexEditor {
+ /** Editor version */
+ static get version() {
+ return VERSION;
+ }
+
+ /**
+ * @constructor
+ *
+ * @param {EditorConfig} configuration - user configuration
+ */
+ constructor(configuration) {
+ let {onReady} = configuration;
+
+ onReady = onReady && typeof onReady === 'function' ? onReady : () => {};
+
+ configuration.onReady = () => {};
+
+ const editor = new Core(configuration);
+
+ /**
+ * We need to export isReady promise in the constructor as it can be used before other API methods are exported
+ * @type {Promise}
+ */
+ this.isReady = editor.isReady.then(() => {
+ this.exportAPI(editor);
+ onReady();
+ });
+ }
+
+ /**
+ * Export external API methods
+ *
+ * @param editor
+ */
+ exportAPI(editor) {
+ const fieldsToExport = [ 'configuration' ];
+ const destroy = () => {
+ editor.moduleInstances.Listeners.removeAll();
+ editor.moduleInstances.UI.destroy();
+ editor = null;
+
+ for (const field in this) {
+ delete this[field];
+ }
+
+ Object.setPrototypeOf(this, null);
+ };
+
+ fieldsToExport.forEach(field => {
+ this[field] = editor[field];
+ });
+
+ this.destroy = destroy;
+
+ Object.setPrototypeOf(this, editor.moduleInstances.API.methods);
+
+ delete this['exportAPI'];
+ }
+}
diff --git a/src/components/__module.ts b/src/components/__module.ts
new file mode 100644
index 000000000..f8496fe29
--- /dev/null
+++ b/src/components/__module.ts
@@ -0,0 +1,47 @@
+import IEditor from './interfaces/editor';
+import IEditorConfig from './interfaces/editor-config';
+import IModuleConfig from './interfaces/module-config';
+
+/**
+ * @abstract
+ * @class Module
+ * @classdesc All modules inherits from this class.
+ *
+ * @typedef {Module} Module
+ * @property {Object} config - Editor user settings
+ * @property {IEditorConfig} Editor - List of Editor modules
+ */
+export default class Module {
+
+ /**
+ * Editor modules list
+ * @type {IEditor}
+ */
+ protected Editor: IEditor;
+
+ /**
+ * Editor configuration object
+ * @type {IEditorConfig}
+ */
+ protected config: IEditorConfig;
+
+ /**
+ * @constructor
+ * @param {IModuleConfig}
+ */
+ constructor({config}: IModuleConfig) {
+ if (new.target === Module) {
+ throw new TypeError('Constructors for abstract class Module are not allowed.');
+ }
+
+ this.config = config;
+ }
+
+ /**
+ * Editor modules setter
+ * @param {IEditor} Editor
+ */
+ set state(Editor) {
+ this.Editor = Editor;
+ }
+}
diff --git a/src/components/block-tunes/block-tune-delete.ts b/src/components/block-tunes/block-tune-delete.ts
new file mode 100644
index 000000000..c991d7521
--- /dev/null
+++ b/src/components/block-tunes/block-tune-delete.ts
@@ -0,0 +1,116 @@
+/**
+ * @class DeleteTune
+ * @classdesc Editor's default tune that moves up selected block
+ *
+ * @copyright 2018
+ */
+import IBlockTune from '../interfaces/block-tune';
+
+declare var $: any;
+declare var _: any;
+
+export default class DeleteTune implements IBlockTune {
+
+ /**
+ * Property that contains CodeX Editor API methods
+ * @see {docs/api.md}
+ */
+ private readonly api: any;
+
+ /**
+ * Styles
+ * @type {{wrapper: string}}
+ */
+ private CSS = {
+ wrapper: 'ass',
+ button: 'ce-settings__button',
+ buttonDelete: 'ce-settings__button--delete',
+ buttonConfirm: 'ce-settings__button--confirm',
+ };
+
+ /**
+ * Delete confirmation
+ */
+ private needConfirmation: boolean;
+
+ /**
+ * set false confirmation state
+ */
+ private resetConfirmation: () => void;
+
+ /**
+ * Tune nodes
+ */
+ private nodes = {
+ button: null,
+ };
+
+ /**
+ * DeleteTune constructor
+ *
+ * @param {Object} api
+ */
+ constructor({api}) {
+ this.api = api;
+
+ this.resetConfirmation = () => {
+ this.setConfirmation(false);
+ };
+ }
+
+ /**
+ * Create "Delete" button and add click event listener
+ * @returns [Element}
+ */
+ public render() {
+ this.nodes.button = $.make('div', [this.CSS.button, this.CSS.buttonDelete], {});
+ this.nodes.button.appendChild($.svg('cross', 12, 12));
+ this.api.listener.on(this.nodes.button, 'click', (event) => this.handleClick(event), false);
+ return this.nodes.button;
+ }
+
+ /**
+ * Delete block conditions passed
+ * @param {MouseEvent} event
+ */
+ public handleClick(event: MouseEvent): void {
+
+ /**
+ * if block is not waiting the confirmation, subscribe on block-settings-closing event to reset
+ * otherwise delete block
+ */
+ if (!this.needConfirmation) {
+ this.setConfirmation(true);
+
+ /**
+ * Subscribe on event.
+ * When toolbar block settings is closed but block deletion is not confirmed,
+ * then reset confirmation state
+ */
+ this.api.events.on('block-settings-closed', this.resetConfirmation);
+
+ } else {
+
+ /**
+ * Unsubscribe from block-settings closing event
+ */
+ this.api.events.off('block-settings-closed', this.resetConfirmation);
+
+ this.api.blocks.delete();
+
+ /**
+ * Prevent firing ui~documentClicked that can drop currentBlock pointer
+ */
+ event.stopPropagation();
+ }
+ }
+
+ /**
+ * change tune state
+ */
+ private setConfirmation(state): void {
+ this.needConfirmation = state;
+ this.nodes.button.classList.add(this.CSS.buttonConfirm);
+ }
+
+}
diff --git a/src/components/block-tunes/block-tune-move-down.ts b/src/components/block-tunes/block-tune-move-down.ts
new file mode 100644
index 000000000..e848ca4e7
--- /dev/null
+++ b/src/components/block-tunes/block-tune-move-down.ts
@@ -0,0 +1,88 @@
+/**
+ * @class MoveDownTune
+ * @classdesc Editor's default tune - Moves down highlighted block
+ *
+ * @copyright 2018
+ */
+import IBlockTune from '../interfaces/block-tune';
+
+declare var $: any;
+declare var _: any;
+
+export default class MoveDownTune implements IBlockTune {
+ /**
+ * Property that contains CodeX Editor API methods
+ * @see {api.md}
+ */
+ private readonly api: any;
+
+ /**
+ * Styles
+ * @type {{wrapper: string}}
+ */
+ private CSS = {
+ button: 'ce-settings__button',
+ wrapper: 'ce-tune-move-down',
+ animation: 'wobble',
+ };
+
+ /**
+ * MoveDownTune constructor
+ *
+ * @param {Object} api
+ */
+ public constructor({api}) {
+ this.api = api;
+ }
+
+ /**
+ * Return 'move down' button
+ */
+ public render() {
+ const moveDownButton = $.make('div', [this.CSS.button, this.CSS.wrapper], {});
+ moveDownButton.appendChild($.svg('arrow-down', 14, 14));
+ this.api.listener.on(moveDownButton, 'click', (event) => this.handleClick(event, moveDownButton), false);
+ return moveDownButton;
+ }
+
+ /**
+ * Handle clicks on 'move down' button
+ * @param {MouseEvent} event
+ * @param {HTMLElement} button
+ */
+ public handleClick(event: MouseEvent, button: HTMLElement) {
+
+ const currentBlockIndex = this.api.blocks.getCurrentBlockIndex();
+
+ // If Block is last do nothing
+ if (currentBlockIndex === this.api.blocks.getBlocksCount() - 1) {
+ button.classList.add(this.CSS.animation);
+
+ window.setTimeout( () => {
+ button.classList.remove(this.CSS.animation);
+ }, 500);
+ return;
+ }
+
+ const nextBlockElement = this.api.blocks.getBlockByIndex(currentBlockIndex + 1).holder,
+ nextBlockCoords = nextBlockElement.getBoundingClientRect();
+
+ let scrollOffset = Math.abs(window.innerHeight - nextBlockElement.offsetHeight);
+
+ /**
+ * Next block ends on screen.
+ * Increment scroll by next block's height to save element onscreen-position
+ */
+ if (nextBlockCoords.top < window.innerHeight) {
+
+ scrollOffset = window.scrollY + nextBlockElement.offsetHeight;
+
+ }
+
+ window.scrollTo(0, scrollOffset);
+
+ /** Change blocks positions */
+ this.api.blocks.swap(currentBlockIndex, currentBlockIndex + 1);
+
+ }
+}
diff --git a/src/components/block-tunes/block-tune-move-up.ts b/src/components/block-tunes/block-tune-move-up.ts
new file mode 100644
index 000000000..22b952e9d
--- /dev/null
+++ b/src/components/block-tunes/block-tune-move-up.ts
@@ -0,0 +1,95 @@
+/**
+ * @class MoveUpTune
+ * @classdesc Editor's default tune that moves up selected block
+ *
+ * @copyright 2018
+ */
+import IBlockTune from '../interfaces/block-tune';
+
+declare var $: any;
+declare var _: any;
+
+export default class MoveUpTune implements IBlockTune {
+
+ /**
+ * Property that contains CodeX Editor API methods
+ * @see {api.md}
+ */
+ private readonly api: any;
+
+ /**
+ * Styles
+ * @type {{wrapper: string}}
+ */
+ private CSS = {
+ button: 'ce-settings__button',
+ wrapper: 'ce-tune-move-up',
+ animation: 'wobble',
+ };
+
+ /**
+ * MoveUpTune constructor
+ *
+ * @param {Object} api
+ */
+ public constructor({api}) {
+ this.api = api;
+ }
+
+ /**
+ * Create "MoveUp" button and add click event listener
+ * @returns [HTMLElement}
+ */
+ public render(): HTMLElement {
+ const moveUpButton = $.make('div', [this.CSS.button, this.CSS.wrapper], {});
+ moveUpButton.appendChild($.svg('arrow-up', 14, 14));
+ this.api.listener.on(moveUpButton, 'click', (event) => this.handleClick(event, moveUpButton), false);
+ return moveUpButton;
+ }
+
+ /**
+ * Move current block up
+ * @param {MouseEvent} event
+ * @param {HTMLElement} button
+ */
+ public handleClick(event: MouseEvent, button: HTMLElement): void {
+
+ const currentBlockIndex = this.api.blocks.getCurrentBlockIndex();
+
+ if (currentBlockIndex === 0) {
+ button.classList.add(this.CSS.animation);
+
+ window.setTimeout( () => {
+ button.classList.remove(this.CSS.animation);
+ }, 500);
+ return;
+ }
+
+ const currentBlockElement = this.api.blocks.getBlockByIndex(currentBlockIndex).holder,
+ previousBlockElement = this.api.blocks.getBlockByIndex(currentBlockIndex - 1).holder;
+
+ /**
+ * Here is two cases:
+ * - when previous block has negative offset and part of it is visible on window, then we scroll
+ * by window's height and add offset which is mathematically difference between two blocks
+ *
+ * - when previous block is visible and has offset from the window,
+ * than we scroll window to the difference between this offsets.
+ */
+ const currentBlockCoords = currentBlockElement.getBoundingClientRect(),
+ previousBlockCoords = previousBlockElement.getBoundingClientRect();
+
+ let scrollUpOffset;
+
+ if (previousBlockCoords.top > 0) {
+ scrollUpOffset = Math.abs(currentBlockCoords.top) - Math.abs(previousBlockCoords.top);
+ } else {
+ scrollUpOffset = window.innerHeight - Math.abs(currentBlockCoords.top) + Math.abs(previousBlockCoords.top);
+ }
+
+ window.scrollBy(0, -1 * scrollUpOffset);
+
+ /** Change blocks positions */
+ this.api.blocks.swap(currentBlockIndex, currentBlockIndex - 1);
+ }
+}
diff --git a/src/components/block.ts b/src/components/block.ts
new file mode 100644
index 000000000..f850aec79
--- /dev/null
+++ b/src/components/block.ts
@@ -0,0 +1,379 @@
+import IBlockTune, {IBlockTuneConstructor} from './interfaces/block-tune';
+import $ from './dom';
+import _ from './utils';
+
+type Tool = any;
+
+/**
+ * @class Block
+ * @classdesc This class describes editor`s block, including block`s HTMLElement, data and tool
+ *
+ * @property {Tool} tool — current block tool (Paragraph, for example)
+ * @property {Object} CSS — block`s css classes
+ *
+ */
+
+/** Import default tunes */
+import MoveUpTune from './block-tunes/block-tune-move-up';
+import DeleteTune from './block-tunes/block-tune-delete';
+import MoveDownTune from './block-tunes/block-tune-move-down';
+
+/**
+ * @classdesc Abstract Block class that contains Block information, Tool name and Tool class instance
+ *
+ * @property tool - Tool instance
+ * @property html - Returns HTML content of plugin
+ * @property holder - Div element that wraps block content with Tool's content. Has `ce-block` CSS class
+ * @property pluginsContent - HTML content that returns by Tool's render function
+ */
+export default class Block {
+
+ /**
+ * CSS classes for the Block
+ * @return {{wrapper: string, content: string}}
+ */
+ static get CSS(): {wrapper: string, wrapperStretched: string, content: string, selected: string} {
+ return {
+ wrapper: 'ce-block',
+ wrapperStretched: 'ce-block--stretched',
+ content: 'ce-block__content',
+ selected: 'ce-block--selected',
+ };
+ }
+
+ /**
+ * Find and return all editable elements (contenteditables and native inputs) in the Tool HTML
+ *
+ * @returns {HTMLElement[]}
+ */
+ get inputs(): HTMLElement[] {
+ const content = this.holder;
+ const allowedInputTypes = ['text', 'password', 'email', 'number', 'search', 'tel', 'url'];
+
+ const selector = '[contenteditable], textarea, input, '
+ + allowedInputTypes.map((type) => `input[type="${type}"]`).join(', ');
+
+ const inputs = _.array(content.querySelectorAll(selector));
+
+ /**
+ * If inputs amount was changed we need to check if input index is bigger then inputs array length
+ */
+ if (this.inputIndex > inputs.length - 1) {
+ this.inputIndex = inputs.length - 1;
+ }
+
+ return inputs;
+ }
+
+ /**
+ * Return current Tool`s input
+ *
+ * @returns {HTMLElement}
+ */
+ get currentInput(): HTMLElement {
+ return this.inputs[this.inputIndex];
+ }
+
+ /**
+ * Set input index to the passed element
+ *
+ * @param {HTMLElement} element
+ */
+ set currentInput(element: HTMLElement) {
+ const index = this.inputs.findIndex((input) => input === element || input.contains(element));
+
+ if (index !== -1) {
+ this.inputIndex = index;
+ }
+ }
+
+ /**
+ * Return first Tool`s input
+ *
+ * @returns {HTMLElement}
+ */
+ get firstInput(): HTMLElement {
+ return this.inputs[0];
+ }
+
+ /**
+ * Return first Tool`s input
+ *
+ * @returns {HTMLElement}
+ */
+ get lastInput(): HTMLElement {
+ const inputs = this.inputs;
+
+ return inputs[inputs.length - 1];
+ }
+
+ /**
+ * Return next Tool`s input or undefined if it doesn't exist
+ *
+ * @returns {HTMLElement}
+ */
+ get nextInput(): HTMLElement {
+ return this.inputs[this.inputIndex + 1];
+ }
+
+ /**
+ * Return previous Tool`s input or undefined if it doesn't exist
+ *
+ * @returns {HTMLElement}
+ */
+ get previousInput(): HTMLElement {
+ return this.inputs[this.inputIndex - 1];
+ }
+
+ /**
+ * Returns Plugins content
+ * @return {Node}
+ */
+ get pluginsContent(): Node {
+ const pluginsContent = this.holder.querySelector(`.${Block.CSS.content}`);
+
+ if (pluginsContent && pluginsContent.childNodes.length) {
+ return pluginsContent.childNodes[0];
+ }
+
+ return null;
+ }
+
+ /**
+ * Get Block's JSON data
+ * @return {Object}
+ */
+ get data(): object {
+ return this.save();
+ }
+
+ /**
+ * is block mergeable
+ * We plugin have merge function then we call it mergable
+ * @return {boolean}
+ */
+ get mergeable(): boolean {
+ return typeof this.tool.merge === 'function';
+ }
+
+ /**
+ * Check block for emptiness
+ * @return {Boolean}
+ */
+ get isEmpty(): boolean {
+ /**
+ * Allow Tool to represent decorative contentless blocks: for example "* * *"-tool
+ * That Tools are not empty
+ */
+ if (this.class.contentless) {
+ return false;
+ }
+
+ const emptyText = $.isEmpty(this.pluginsContent),
+ emptyMedia = !this.hasMedia;
+
+ return emptyText && emptyMedia;
+ }
+
+ /**
+ * Check if block has a media content such as images, iframes and other
+ * @return {Boolean}
+ */
+ get hasMedia(): boolean {
+ /**
+ * This tags represents media-content
+ * @type {string[]}
+ */
+ const mediaTags = [
+ 'img',
+ 'iframe',
+ 'video',
+ 'audio',
+ 'source',
+ 'input',
+ 'textarea',
+ 'twitterwidget',
+ ];
+
+ return !!this.holder.querySelector(mediaTags.join(','));
+ }
+
+ /**
+ * Set selected state
+ * @param {Boolean} state - 'true' to select, 'false' to remove selection
+ */
+ set selected(state: boolean) {
+ /**
+ * We don't need to mark Block as Selected when it is not empty
+ */
+ if (state === true && !this.isEmpty) {
+ this.holder.classList.add(Block.CSS.selected);
+ } else {
+ this.holder.classList.remove(Block.CSS.selected);
+ }
+ }
+
+ /**
+ * Set stretched state
+ * @param {Boolean} state - 'true' to enable, 'false' to disable stretched statte
+ */
+ set stretched(state: boolean) {
+ this.holder.classList.toggle(Block.CSS.wrapperStretched, state);
+ }
+
+ public name: string;
+ public tool: Tool;
+ public class: any;
+ public settings: object;
+ public holder: HTMLDivElement;
+ public tunes: IBlockTune[];
+ private readonly api: object;
+ private inputIndex = 0;
+
+ /**
+ * @constructor
+ * @param {String} toolName - Tool name that passed on initialization
+ * @param {Object} toolInstance — passed Tool`s instance that rendered the Block
+ * @param {Object} toolClass — Tool's class
+ * @param {Object} settings - default settings
+ * @param {Object} apiMethods - Editor API
+ */
+ constructor(toolName: string, toolInstance: Tool, toolClass: object, settings: object, apiMethods: object) {
+ this.name = toolName;
+ this.tool = toolInstance;
+ this.class = toolClass;
+ this.settings = settings;
+ this.api = apiMethods;
+ this.holder = this.compose();
+
+ /**
+ * @type {IBlockTune[]}
+ */
+ this.tunes = this.makeTunes();
+ }
+
+ /**
+ * Calls Tool's method
+ *
+ * Method checks tool property {MethodName}. Fires method with passes params If it is instance of Function
+ *
+ * @param {String} methodName
+ * @param {Object} params
+ */
+ public call(methodName: string, params: object) {
+ /**
+ * call Tool's method with the instance context
+ */
+ if (this.tool[methodName] && this.tool[methodName] instanceof Function) {
+ this.tool[methodName].call(this.tool, params);
+ }
+ }
+
+ /**
+ * Call plugins merge method
+ * @param {Object} data
+ */
+ public mergeWith(data: object): Promise {
+ return Promise.resolve()
+ .then(() => {
+ this.tool.merge(data);
+ });
+ }
+ /**
+ * Extracts data from Block
+ * Groups Tool's save processing time
+ * @return {Object}
+ */
+ public save(): Promise {
+ const extractedBlock = this.tool.save(this.pluginsContent);
+
+ /**
+ * Measuring execution time
+ */
+ const measuringStart = window.performance.now();
+ let measuringEnd;
+
+ return Promise.resolve(extractedBlock)
+ .then((finishedExtraction) => {
+ /** measure promise execution */
+ measuringEnd = window.performance.now();
+
+ return {
+ tool: this.name,
+ data: finishedExtraction,
+ time : measuringEnd - measuringStart,
+ };
+ })
+ .catch(function(error) {
+ _.log(`Saving proccess for ${this.tool.name} tool failed due to the ${error}`, 'log', 'red');
+ });
+ }
+
+ /**
+ * Uses Tool's validation method to check the correctness of output data
+ * Tool's validation method is optional
+ *
+ * @description Method also can return data if it passed the validation
+ *
+ * @param {Object} data
+ * @returns {Boolean|Object} valid
+ */
+ public validateData(data: object): object|false {
+ let isValid = true;
+
+ if (this.tool.validate instanceof Function) {
+ isValid = this.tool.validate(data);
+ }
+
+ if (!isValid) {
+ return false;
+ }
+
+ return data;
+ }
+
+ /**
+ * Make an array with default settings
+ * Each block has default tune instance that have states
+ * @return {IBlockTune[]}
+ */
+ public makeTunes(): IBlockTune[] {
+ const tunesList = [MoveUpTune, DeleteTune, MoveDownTune];
+
+ // Pluck tunes list and return tune instances with passed Editor API and settings
+ return tunesList.map( (tune: IBlockTuneConstructor) => {
+ return new tune({
+ api: this.api,
+ settings: this.settings,
+ });
+ });
+ }
+
+ /**
+ * Enumerates initialized tunes and returns fragment that can be appended to the toolbars area
+ * @return {DocumentFragment}
+ */
+ public renderTunes(): DocumentFragment {
+ const tunesElement = document.createDocumentFragment();
+
+ this.tunes.forEach( (tune) => {
+ $.append(tunesElement, tune.render());
+ });
+
+ return tunesElement;
+ }
+
+ /**
+ * Make default Block wrappers and put Tool`s content there
+ * @returns {HTMLDivElement}
+ */
+ private compose(): HTMLDivElement {
+ const wrapper = $.make('div', Block.CSS.wrapper) as HTMLDivElement,
+ contentNode = $.make('div', Block.CSS.content),
+ pluginsContent = this.tool.render();
+
+ contentNode.appendChild(pluginsContent);
+ wrapper.appendChild(contentNode);
+ return wrapper;
+ }
+}
diff --git a/src/components/core.js b/src/components/core.js
new file mode 100644
index 000000000..9baec590d
--- /dev/null
+++ b/src/components/core.js
@@ -0,0 +1,276 @@
+/**
+ * @typedef {Core} Core - editor core class
+ */
+
+/**
+ * Dynamically imported utils
+ *
+ * @typedef {Dom} $ - {@link components/dom.js}
+ * @typedef {Util} _ - {@link components/utils.js}
+ */
+
+/**
+ * Require Editor modules places in components/modules dir
+ */
+// eslint-disable-next-line
+let modules = editorModules.map( module => require('./modules/' + module ));
+
+/**
+ * @class Core
+ *
+ * @classdesc CodeX Editor core class
+ *
+ * @property this.config - all settings
+ * @property this.moduleInstances - constructed editor components
+ *
+ * @type {Core}
+ */
+export default class Core {
+ /**
+ * @param {EditorConfig} config - user configuration
+ *
+ */
+ constructor(config) {
+ /**
+ * Configuration object
+ * @type {EditorConfig}
+ */
+ this.config = {};
+
+ /**
+ * @typedef {Object} EditorComponents
+ * @property {BlockManager} BlockManager
+ * @property {Tools} Tools
+ * @property {Events} Events
+ * @property {UI} UI
+ * @property {Toolbar} Toolbar
+ * @property {Toolbox} Toolbox
+ * @property {BlockSettings} BlockSettings
+ * @property {Renderer} Renderer
+ * @property {InlineToolbar} InlineToolbar
+ */
+ this.moduleInstances = {};
+
+ /**
+ * Ready promise. Resolved if CodeX Editor is ready to work, rejected otherwise
+ */
+ let onReady, onFail;
+
+ this.isReady = new Promise((resolve, reject) => {
+ onReady = resolve;
+ onFail = reject;
+ });
+
+ Promise.resolve()
+ .then(() => {
+ this.configuration = config;
+ })
+ .then(() => this.validate())
+ .then(() => this.init())
+ .then(() => this.start())
+ .then(() => {
+ _.log('I\'m ready! (ノ◕ヮ◕)ノ*:・゚✧');
+
+ setTimeout(() => {
+ this.config.onReady.call();
+ onReady();
+ }, 500);
+ })
+ .catch(error => {
+ _.log(`CodeX Editor does not ready because of ${error}`, 'error');
+ onFail(error);
+ });
+ }
+
+ /**
+ * Setting for configuration
+ * @param {EditorConfig|string|null} config
+ */
+ set configuration(config) {
+ /**
+ * Process zero-configuration or with only holderId
+ */
+ if (typeof config === 'string' || typeof config === 'undefined') {
+ config = {
+ holderId: config || 'codex-editor'
+ };
+ }
+
+ /**
+ * If initial Block's Tool was not passed, use the Paragraph Tool
+ */
+ this.config.initialBlock = config.initialBlock || 'paragraph';
+
+ /**
+ * Initial block type
+ * Uses in case when there is no blocks passed
+ * @type {{type: (*), data: {text: null}}}
+ */
+ let initialBlockData = {
+ type : this.config.initialBlock,
+ data : {}
+ };
+
+ this.config.holderId = config.holderId;
+ this.config.placeholder = config.placeholder || 'write your story...';
+ this.config.sanitizer = config.sanitizer || {
+ p: true,
+ b: true,
+ a: true
+ };
+
+ this.config.hideToolbar = config.hideToolbar ? config.hideToolbar : false;
+ this.config.tools = config.tools || {};
+ this.config.data = config.data || {};
+ this.config.onReady = config.onReady || function () {};
+
+ /**
+ * Initialize Blocks to pass data to the Renderer
+ */
+ if (_.isEmpty(this.config.data)) {
+ this.config.data = {};
+ this.config.data.blocks = [ initialBlockData ];
+ } else {
+ if (!this.config.data.blocks || this.config.data.blocks.length === 0) {
+ this.config.data.blocks = [ initialBlockData ];
+ }
+ }
+ }
+
+ /**
+ * Returns private property
+ * @returns {EditorConfig}
+ */
+ get configuration() {
+ return this.config;
+ }
+
+ /**
+ * Checks for required fields in Editor's config
+ * @returns {void|Promise}
+ */
+ validate() {
+ /**
+ * Check if holderId is not empty
+ */
+ if (!this.config.holderId) {
+ return Promise.reject('«holderId» param must being not empty');
+ }
+
+ /**
+ * Check for a holder element's existence
+ */
+ if (!$.get(this.config.holderId)) {
+ return Promise.reject(`element with ID «${this.config.holderId}» is missing. Pass correct holder's ID.`);
+ }
+
+ /**
+ * Check Tools for a class containing
+ */
+ for (let toolName in this.config.tools) {
+ const tool = this.config.tools[toolName];
+
+ if (!_.isFunction(tool) && !_.isFunction(tool.class)) {
+ return Promise.reject(`Tool «${toolName}» must be a constructor function or an object with that function in the «class» property`);
+ }
+ }
+ }
+
+ /**
+ * Initializes modules:
+ * - make and save instances
+ * - configure
+ */
+ init() {
+ /**
+ * Make modules instances and save it to the @property this.moduleInstances
+ */
+ this.constructModules();
+
+ /**
+ * Modules configuration
+ */
+ this.configureModules();
+ }
+
+ /**
+ * Make modules instances and save it to the @property this.moduleInstances
+ */
+ constructModules() {
+ modules.forEach( Module => {
+ try {
+ /**
+ * We use class name provided by displayName property
+ *
+ * On build, Babel will transform all Classes to the Functions so, name will always be 'Function'
+ * To prevent this, we use 'babel-plugin-class-display-name' plugin
+ * @see https://www.npmjs.com/package/babel-plugin-class-display-name
+ */
+ this.moduleInstances[Module.displayName] = new Module({
+ config : this.configuration
+ });
+ } catch ( e ) {
+ console.log('Module %o skipped because %o', Module, e);
+ }
+ });
+ }
+
+ /**
+ * Modules instances configuration:
+ * - pass other modules to the 'state' property
+ * - ...
+ */
+ configureModules() {
+ for(let name in this.moduleInstances) {
+ /**
+ * Module does not need self-instance
+ */
+ this.moduleInstances[name].state = this.getModulesDiff( name );
+ }
+ }
+
+ /**
+ * Return modules without passed name
+ */
+ getModulesDiff( name ) {
+ let diff = {};
+
+ for(let moduleName in this.moduleInstances) {
+ /**
+ * Skip module with passed name
+ */
+ if (moduleName === name) {
+ continue;
+ }
+ diff[moduleName] = this.moduleInstances[moduleName];
+ }
+
+ return diff;
+ }
+
+ /**
+ * Start Editor!
+ *
+ * Get list of modules that needs to be prepared and return a sequence (Promise)
+ * @return {Promise}
+ */
+ async start() {
+ const modulesToPrepare = ['Tools', 'UI', 'BlockManager', 'Paste'];
+
+ await modulesToPrepare.reduce(
+ (promise, module) => promise.then(async () => {
+ _.log(`Preparing ${module} module`, 'time');
+
+ try {
+ await this.moduleInstances[module].prepare();
+ } catch (e) {
+ _.log(`Module ${module} was skipped because of %o`, 'warn', e);
+ }
+ _.log(`Preparing ${module} module`, 'timeEnd');
+ }),
+ Promise.resolve()
+ );
+
+ return this.moduleInstances.Renderer.render(this.config.data.blocks);
+ }
+};
diff --git a/src/components/dom.ts b/src/components/dom.ts
new file mode 100644
index 000000000..545e76abd
--- /dev/null
+++ b/src/components/dom.ts
@@ -0,0 +1,423 @@
+/**
+ * DOM manipulations helper
+ */
+export default class Dom {
+ /**
+ * Check if passed tag has no closed tag
+ * @param {HTMLElement} tag
+ * @return {Boolean}
+ */
+ public static isSingleTag(tag: HTMLElement): boolean {
+ return tag.tagName && [
+ 'AREA',
+ 'BASE',
+ 'BR',
+ 'COL',
+ 'COMMAND',
+ 'EMBED',
+ 'HR',
+ 'IMG',
+ 'INPUT',
+ 'KEYGEN',
+ 'LINK',
+ 'META',
+ 'PARAM',
+ 'SOURCE',
+ 'TRACK',
+ 'WBR',
+ ].includes(tag.tagName);
+ }
+
+ /**
+ * Helper for making Elements with classname and attributes
+ *
+ * @param {string} tagName - new Element tag name
+ * @param {array|string} classNames - list or name of CSS classname(s)
+ * @param {Object} attributes - any attributes
+ * @return {Element}
+ */
+ public static make(tagName: string, classNames: string|string[] = null, attributes: object = {}): Element {
+ const el = document.createElement(tagName);
+
+ if ( Array.isArray(classNames) ) {
+ el.classList.add(...classNames);
+ } else if ( classNames ) {
+ el.classList.add(classNames);
+ }
+
+ for (const attrName in attributes) {
+ if (attributes.hasOwnProperty(attrName)) {
+ el[attrName] = attributes[attrName];
+ }
+ }
+
+ return el;
+ }
+
+ /**
+ * Creates Text Node with the passed content
+ * @param {String} content - text content
+ * @return {Text}
+ */
+ public static text(content: string): Text {
+ return document.createTextNode(content);
+ }
+
+ /**
+ * Creates SVG icon linked to the sprite
+ * @param {string} name - name (id) of icon from sprite
+ * @param {number} width
+ * @param {number} height
+ * @return {SVGElement}
+ */
+ public static svg(name: string, width: number = 14, height: number = 14): SVGElement {
+ const icon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
+
+ icon.classList.add('icon', 'icon--' + name);
+ icon.setAttribute('width', width + 'px');
+ icon.setAttribute('height', height + 'px');
+ icon.innerHTML = ``;
+
+ return icon;
+ }
+
+ /**
+ * Append one or several elements to the parent
+ *
+ * @param {Element|DocumentFragment} parent - where to append
+ * @param {Element|Element[]} elements - element or elements list
+ */
+ public static append(parent: Element|DocumentFragment, elements: Element|Element[]): void {
+ if ( Array.isArray(elements) ) {
+ elements.forEach( (el) => parent.appendChild(el) );
+ } else {
+ parent.appendChild(elements);
+ }
+ }
+
+ /**
+ * Append element or a couple to the beginning of the parent elements
+ *
+ * @param {Element} parent - where to append
+ * @param {Element|Element[]} elements - element or elements list
+ */
+ public static prepend(parent: Element, elements: Element|Element[]): void {
+ if ( Array.isArray(elements) ) {
+ elements = elements.reverse();
+ elements.forEach( (el) => parent.prepend(el) );
+ } else {
+ parent.prepend(elements);
+ }
+ }
+
+ /**
+ * Swap two elements in parent
+ * @param {HTMLElement} el1 - from
+ * @param {HTMLElement} el2 - to
+ */
+ public static swap(el1: HTMLElement, el2: HTMLElement): void {
+ // create marker element and insert it where el1 is
+ const temp = document.createElement('div'),
+ parent = el1.parentNode;
+
+ parent.insertBefore(temp, el1);
+
+ // move el1 to right before el2
+ parent.insertBefore(el1, el2);
+
+ // move el2 to right before where el1 used to be
+ parent.insertBefore(el2, temp);
+
+ // remove temporary marker node
+ parent.removeChild(temp);
+ }
+
+ /**
+ * Selector Decorator
+ *
+ * Returns first match
+ *
+ * @param {Element} el - element we searching inside. Default - DOM Document
+ * @param {String} selector - searching string
+ *
+ * @returns {Element}
+ */
+ public static find(el: Element|Document = document, selector: string): Element {
+ return el.querySelector(selector);
+ }
+
+ /**
+ * Get Element by Id
+ *
+ * @param {string} id
+ * @returns {HTMLElement | null}
+ */
+ public static get(id: string): HTMLElement {
+ return document.getElementById(id);
+ }
+
+ /**
+ * Selector Decorator.
+ *
+ * Returns all matches
+ *
+ * @param {Element} el - element we searching inside. Default - DOM Document
+ * @param {String} selector - searching string
+ * @returns {NodeList}
+ */
+ public static findAll(el: Element|Document = document, selector: string): NodeList {
+ return el.querySelectorAll(selector);
+ }
+
+ /**
+ * Search for deepest node which is Leaf.
+ * Leaf is the vertex that doesn't have any child nodes
+ *
+ * @description Method recursively goes throw the all Node until it finds the Leaf
+ *
+ * @param {Node} node - root Node. From this vertex we start Deep-first search
+ * {@link https://en.wikipedia.org/wiki/Depth-first_search}
+ * @param {Boolean} atLast - find last text node
+ * @return {Node} - it can be text Node or Element Node, so that caret will able to work with it
+ */
+ public static getDeepestNode(node: Node, atLast: boolean = false): Node {
+ /**
+ * Current function have two directions:
+ * - starts from first child and every time gets first or nextSibling in special cases
+ * - starts from last child and gets last or previousSibling
+ * @type {string}
+ */
+ const child = atLast ? 'lastChild' : 'firstChild',
+ sibling = atLast ? 'previousSibling' : 'nextSibling';
+
+ if (node && node.nodeType === Node.ELEMENT_NODE && node[child]) {
+ let nodeChild = node[child];
+
+ /**
+ * special case when child is single tag that can't contain any content
+ */
+ if (Dom.isSingleTag(nodeChild as HTMLElement) && !Dom.isNativeInput(nodeChild)) {
+ /**
+ * 1) We need to check the next sibling. If it is Node Element then continue searching for deepest
+ * from sibling
+ *
+ * 2) If single tag's next sibling is null, then go back to parent and check his sibling
+ * In case of Node Element continue searching
+ *
+ * 3) If none of conditions above happened return parent Node Element
+ */
+ if (nodeChild[sibling]) {
+ nodeChild = nodeChild[sibling];
+ } else if (nodeChild.parentNode[sibling]) {
+ nodeChild = nodeChild.parentNode[sibling];
+ } else {
+ return nodeChild.parentNode;
+ }
+ }
+
+ return this.getDeepestNode(nodeChild, atLast);
+ }
+
+ return node;
+ }
+
+ /**
+ * Check if object is DOM node
+ *
+ * @param {Object} node
+ * @returns {boolean}
+ */
+ public static isElement(node: any): boolean {
+ return node && typeof node === 'object' && node.nodeType && node.nodeType === Node.ELEMENT_NODE;
+ }
+
+ /**
+ * Check if object is DocumentFragmemt node
+ *
+ * @param {Object} node
+ * @returns {boolean}
+ */
+ public static isFragment(node: any): boolean {
+ return node && typeof node === 'object' && node.nodeType && node.nodeType === Node.DOCUMENT_FRAGMENT_NODE;
+ }
+
+ /**
+ * Checks target if it is native input
+ * @param {Element|String|Node} target - HTML element or string
+ * @return {Boolean}
+ */
+ public static isNativeInput(target: any): boolean {
+ const nativeInputs = [
+ 'INPUT',
+ 'TEXTAREA',
+ ];
+
+ return target && target.tagName ? nativeInputs.includes(target.tagName) : false;
+ }
+
+ /**
+ * Checks node if it is empty
+ *
+ * @description Method checks simple Node without any childs for emptiness
+ * If you have Node with 2 or more children id depth, you better use {@link Dom#isEmpty} method
+ *
+ * @param {Node} node
+ * @return {Boolean} true if it is empty
+ */
+ public static isNodeEmpty(node: Node): boolean {
+ let nodeText;
+
+ if ( this.isElement(node) && this.isNativeInput(node) ) {
+ nodeText = (node as HTMLInputElement).value;
+ } else {
+ nodeText = node.textContent.replace('\u200B', '');
+ }
+
+ return nodeText.trim().length === 0;
+ }
+
+ /**
+ * checks node if it is doesn't have any child nodes
+ * @param {Node} node
+ * @return {boolean}
+ */
+ public static isLeaf(node: Node): boolean {
+ if (!node) {
+ return false;
+ }
+
+ return node.childNodes.length === 0;
+ }
+
+ /**
+ * breadth-first search (BFS)
+ * {@link https://en.wikipedia.org/wiki/Breadth-first_search}
+ *
+ * @description Pushes to stack all DOM leafs and checks for emptiness
+ *
+ * @param {Node} node
+ * @return {boolean}
+ */
+ public static isEmpty(node: Node): boolean {
+ const treeWalker = [],
+ leafs = [];
+
+ if (!node) {
+ return true;
+ }
+
+ if (!node.childNodes.length) {
+ return this.isNodeEmpty(node);
+ }
+
+ treeWalker.push(node.firstChild);
+
+ while ( treeWalker.length > 0 ) {
+ node = treeWalker.shift();
+
+ if (!node) { continue; }
+
+ if ( this.isLeaf(node) ) {
+ leafs.push(node);
+ } else {
+ treeWalker.push(node.firstChild);
+ }
+
+ while ( node && node.nextSibling ) {
+ node = node.nextSibling;
+
+ if (!node) { continue; }
+
+ treeWalker.push(node);
+ }
+
+ /**
+ * If one of childs is not empty, checked Node is not empty too
+ */
+ if (node && !this.isNodeEmpty(node)) {
+ return false;
+ }
+ }
+
+ return leafs.every( (leaf) => this.isNodeEmpty(leaf) );
+ }
+
+ /**
+ * Check if string contains html elements
+ *
+ * @returns {boolean}
+ * @param {String} str
+ */
+ public static isHTMLString(str: string): boolean {
+ const wrapper = Dom.make('div');
+
+ wrapper.innerHTML = str;
+
+ return wrapper.childElementCount > 0;
+ }
+
+ /**
+ * Return length of node`s text content
+ *
+ * @param {Node} node
+ * @returns {number}
+ */
+ public static getContentLength(node: Node): number {
+ if (Dom.isNativeInput(node)) {
+ return (node as HTMLInputElement).value.length;
+ }
+
+ if (node.nodeType === Node.TEXT_NODE) {
+ return (node as Text).length;
+ }
+
+ return node.textContent.length;
+ }
+
+ /**
+ * Return array of names of block html elements
+ *
+ * @returns {string[]}
+ */
+ static get blockElements(): string[] {
+ return [
+ 'address',
+ 'article',
+ 'aside',
+ 'blockquote',
+ 'canvas',
+ 'div',
+ 'dl',
+ 'dt',
+ 'fieldset',
+ 'figcaption',
+ 'figure',
+ 'footer',
+ 'form',
+ 'h1',
+ 'h2',
+ 'h3',
+ 'h4',
+ 'h5',
+ 'h6',
+ 'header',
+ 'hgroup',
+ 'hr',
+ 'li',
+ 'main',
+ 'nav',
+ 'noscript',
+ 'ol',
+ 'output',
+ 'p',
+ 'pre',
+ 'ruby',
+ 'section',
+ 'table',
+ 'tr',
+ 'tfoot',
+ 'ul',
+ 'video',
+ ];
+ }
+}
diff --git a/src/components/inline-tools/inline-tool-bold.ts b/src/components/inline-tools/inline-tool-bold.ts
new file mode 100644
index 000000000..94fee1459
--- /dev/null
+++ b/src/components/inline-tools/inline-tool-bold.ts
@@ -0,0 +1,77 @@
+import InlineTool from '../interfaces/tools/inline-tool';
+import SelectionUtils from '../selection';
+
+declare var $: any;
+
+/**
+ * Bold Tool
+ *
+ * Inline Toolbar Tool
+ *
+ * Makes selected text bolder
+ */
+export default class BoldInlineTool implements InlineTool {
+
+ /**
+ * Native Document's command that uses for Bold
+ */
+ private readonly commandName: string = 'bold';
+
+ /**
+ * Styles
+ */
+ private readonly CSS = {
+ button: 'ce-inline-tool',
+ buttonActive: 'ce-inline-tool--active',
+ buttonModifier: 'ce-inline-tool--bold',
+ };
+
+ /**
+ * Elements
+ */
+ private nodes = {
+ button: undefined,
+ };
+
+ /**
+ * @param {{api: IAPI}} - CodeX Editor API
+ */
+ constructor({api}) {
+ }
+
+ /**
+ * Create button for Inline Toolbar
+ */
+ public render(): HTMLElement {
+ this.nodes.button = document.createElement('button');
+ this.nodes.button.classList.add(this.CSS.button, this.CSS.buttonModifier);
+ this.nodes.button.appendChild($.svg('bold', 13, 15));
+ return this.nodes.button;
+ }
+
+ /**
+ * Wrap range with tag
+ * @param {Range} range
+ */
+ public surround(range: Range): void {
+ document.execCommand(this.commandName);
+ }
+
+ /**
+ * Check selection and set activated state to button if there are tag
+ * @param {Selection} selection
+ */
+ public checkState(selection: Selection): boolean {
+ const isActive = document.queryCommandState(this.commandName);
+
+ this.nodes.button.classList.toggle(this.CSS.buttonActive, isActive);
+ return isActive;
+ }
+
+ /**
+ * Set a shortcut
+ */
+ public get shortcut(): string {
+ return 'CMD+B';
+ }
+}
diff --git a/src/components/inline-tools/inline-tool-italic.ts b/src/components/inline-tools/inline-tool-italic.ts
new file mode 100644
index 000000000..387656a20
--- /dev/null
+++ b/src/components/inline-tools/inline-tool-italic.ts
@@ -0,0 +1,77 @@
+import InlineTool from '../interfaces/tools/inline-tool';
+
+declare var $: any;
+
+/**
+ * Italic Tool
+ *
+ * Inline Toolbar Tool
+ *
+ * Style selected text with italic
+ */
+export default class ItalicInlineTool implements InlineTool {
+
+ /**
+ * Native Document's command that uses for Italic
+ */
+ private readonly commandName: string = 'italic';
+
+ /**
+ * Styles
+ */
+ private readonly CSS = {
+ button: 'ce-inline-tool',
+ buttonActive: 'ce-inline-tool--active',
+ buttonModifier: 'ce-inline-tool--italic',
+ };
+
+ /**
+ * Elements
+ */
+ private nodes = {
+ button: null,
+ };
+
+ /**
+ * @param {{api: IAPI}} - CodeX Editor API
+ */
+ constructor({api}) {
+ }
+
+ /**
+ * Create button for Inline Toolbar
+ */
+ public render(): HTMLElement {
+ this.nodes.button = document.createElement('button');
+ this.nodes.button.classList.add(this.CSS.button, this.CSS.buttonModifier);
+ this.nodes.button.appendChild($.svg('italic', 6, 15));
+ return this.nodes.button;
+ }
+
+ /**
+ * Wrap range with tag
+ * @param {Range} range
+ */
+ public surround(range: Range): void {
+ document.execCommand(this.commandName);
+ }
+
+ /**
+ * Check selection and set activated state to button if there are tag
+ * @param {Selection} selection
+ */
+ public checkState(selection: Selection): boolean {
+ const isActive = document.queryCommandState(this.commandName);
+
+ this.nodes.button.classList.toggle(this.CSS.buttonActive, isActive);
+ return isActive;
+ }
+
+ /**
+ * Set a shortcut
+ */
+ public get shortcut(): string {
+ return 'CMD+I';
+ }
+
+}
diff --git a/src/components/inline-tools/inline-tool-link.ts b/src/components/inline-tools/inline-tool-link.ts
new file mode 100644
index 000000000..0addf2c48
--- /dev/null
+++ b/src/components/inline-tools/inline-tool-link.ts
@@ -0,0 +1,316 @@
+import InlineTool from '../interfaces/tools/inline-tool';
+import SelectionUtils from '../selection';
+
+declare var $: any;
+declare var _: any;
+
+/**
+ * Link Tool
+ *
+ * Inline Toolbar Tool
+ *
+ * Wrap selected text with tag
+ */
+export default class LinkInlineTool implements InlineTool {
+ /**
+ * Native Document's commands for link/unlink
+ */
+ private readonly commandLink: string = 'createLink';
+ private readonly commandUnlink: string = 'unlink';
+
+ /**
+ * Enter key code
+ */
+ private readonly ENTER_KEY: number = 13;
+
+ /**
+ * Styles
+ */
+ private readonly CSS = {
+ button: 'ce-inline-tool',
+ buttonActive: 'ce-inline-tool--active',
+ buttonModifier: 'ce-inline-tool--link',
+ buttonUnlink: 'ce-inline-tool--unlink',
+ input: 'ce-inline-tool-input',
+ inputShowed: 'ce-inline-tool-input--showed',
+ };
+
+ /**
+ * Elements
+ */
+ private nodes = {
+ button: null,
+ input: null,
+ };
+
+ /**
+ * SelectionUtils instance
+ */
+ private selection: SelectionUtils;
+
+ /**
+ * Input opening state
+ */
+ private inputOpened: boolean = false;
+
+ /**
+ * Available Inline Toolbar methods (open/close)
+ */
+ private inlineToolbar: any;
+
+ /**
+ * @param {{api: IAPI}} - CodeX Editor API
+ */
+ constructor({api}) {
+ this.inlineToolbar = api.toolbar;
+ this.selection = new SelectionUtils();
+ }
+
+ /**
+ * Create button for Inline Toolbar
+ */
+ public render(): HTMLElement {
+ this.nodes.button = document.createElement('button');
+ this.nodes.button.classList.add(this.CSS.button, this.CSS.buttonModifier);
+ this.nodes.button.appendChild($.svg('link', 15, 14));
+ this.nodes.button.appendChild($.svg('unlink', 16, 18));
+ return this.nodes.button;
+ }
+
+ /**
+ * Input for the link
+ */
+ public renderActions(): HTMLElement {
+ this.nodes.input = document.createElement('input');
+ this.nodes.input.placeholder = 'Add a link';
+ this.nodes.input.classList.add(this.CSS.input);
+ this.nodes.input.addEventListener('keydown', (event) => {
+ if (event.keyCode === this.ENTER_KEY ) {
+ this.enterPressed(event);
+ }
+ });
+ return this.nodes.input;
+ }
+
+ /**
+ * Handle clicks on the Inline Toolbar icon
+ * @param {Range} range
+ */
+ public surround(range: Range): void {
+ /**
+ * Range will be null when user makes second click on the 'link icon' to close opened input
+ */
+ if (range) {
+ /**
+ * Save selection before change focus to the input
+ */
+ this.selection.save();
+ const parentAnchor = this.selection.findParentTag('A');
+
+ /**
+ * Unlink icon pressed
+ */
+ if (parentAnchor) {
+ this.selection.expandToTag(parentAnchor);
+ this.unlink();
+ this.closeActions();
+ this.checkState();
+ this.inlineToolbar.close();
+ return;
+ }
+ }
+
+ this.toggleActions();
+ }
+
+ /**
+ * Check selection and set activated state to button if there are tag
+ * @param {Selection} selection
+ */
+ public checkState(selection?: Selection): boolean {
+ const anchorTag = this.selection.findParentTag('A');
+
+ if (anchorTag) {
+ this.nodes.button.classList.add(this.CSS.buttonUnlink);
+ this.nodes.button.classList.add(this.CSS.buttonActive);
+ this.openActions();
+
+ /**
+ * Fill input value with link href
+ */
+ const hrefAttr = anchorTag.getAttribute('href');
+ this.nodes.input.value = hrefAttr !== 'null' ? hrefAttr : '';
+
+ this.selection.save();
+ } else {
+ this.nodes.button.classList.remove(this.CSS.buttonUnlink);
+ this.nodes.button.classList.remove(this.CSS.buttonActive);
+ }
+
+ return !!anchorTag;
+ }
+
+ /**
+ * Function called with Inline Toolbar closing
+ */
+ public clear(): void {
+ this.closeActions();
+ }
+
+ /**
+ * Set a shortcut
+ */
+ public get shortcut(): string {
+ return 'CMD+K';
+ }
+
+ private toggleActions(): void {
+ if (!this.inputOpened) {
+ this.openActions(true);
+ } else {
+ this.closeActions(false);
+ }
+ }
+
+ /**
+ * @param {boolean} needFocus - on link creation we need to focus input. On editing - nope.
+ */
+ private openActions(needFocus: boolean = false): void {
+ this.nodes.input.classList.add(this.CSS.inputShowed);
+ if (needFocus) {
+ this.nodes.input.focus();
+ }
+ this.inputOpened = true;
+ }
+
+ /**
+ * Close input
+ * @param {boolean} clearSavedSelection — we don't need to clear saved selection
+ * on toggle-clicks on the icon of opened Toolbar
+ */
+ private closeActions(clearSavedSelection: boolean = true): void {
+ this.nodes.input.classList.remove(this.CSS.inputShowed);
+ this.nodes.input.value = '';
+ if (clearSavedSelection) {
+ this.selection.clearSaved();
+ }
+ this.inputOpened = false;
+ }
+
+ /**
+ * Enter pressed on input
+ * @param {KeyboardEvent} event
+ */
+ private enterPressed(event: KeyboardEvent): void {
+ let value = this.nodes.input.value || '';
+
+ if (!value.trim()) {
+ this.selection.restore();
+ this.unlink();
+ event.preventDefault();
+ this.closeActions();
+ }
+
+ if (!this.validateURL(value)) {
+ /**
+ * @todo show notification 'Incorrect Link'
+ */
+ _.log('Incorrect Link pasted', 'warn', value);
+ return;
+ }
+
+ value = this.prepareLink(value);
+
+ this.selection.restore();
+ this.insertLink(value);
+
+ /**
+ * Preventing events that will be able to happen
+ */
+ event.preventDefault();
+ event.stopPropagation();
+ event.stopImmediatePropagation();
+
+ this.closeActions();
+ this.inlineToolbar.close();
+ this.checkState();
+ }
+
+ /**
+ * Detects if passed string is URL
+ * @param {string} str
+ * @return {Boolean}
+ */
+ private validateURL(str: string): boolean {
+ /**
+ * Don't allow spaces
+ */
+ return !/\s/.test(str);
+ }
+
+ /**
+ * Process link before injection
+ * - sanitize
+ * - add protocol for links like 'google.com'
+ * @param {string} link - raw user input
+ */
+ private prepareLink(link: string): string {
+ link = link.trim();
+ link = this.addProtocol(link);
+ return link;
+ }
+
+ /**
+ * Add 'http' protocol to the links like 'vc.ru', 'google.com'
+ * @param {String} link
+ */
+ private addProtocol(link: string): string {
+ /**
+ * If protocol already exists, do nothing
+ */
+ if (/^(\w+):\/\//.test(link)) {
+ return link;
+ }
+
+ /**
+ * We need to add missed HTTP protocol to the link, but skip 2 cases:
+ * 1) Internal links like "/general"
+ * 2) Anchors looks like "#results"
+ * 3) Protocol-relative URLs like "//google.com"
+ */
+ const isInternal = /^\/[^\/\s]/.test(link),
+ isAnchor = link.substring(0, 1) === '#',
+ isProtocolRelative = /^\/\/[^\/\s]/.test(link);
+
+ if (!isInternal && !isAnchor && !isProtocolRelative) {
+ link = 'http://' + link;
+ }
+
+ return link;
+ }
+
+ /**
+ * Inserts tag with "href"
+ * @param {string} link - "href" value
+ */
+ private insertLink(link: string): void {
+
+ /**
+ * Edit all link, not selected part
+ */
+ const anchorTag = this.selection.findParentTag('A');
+
+ if (anchorTag) {
+ this.selection.expandToTag(anchorTag);
+ }
+
+ document.execCommand(this.commandLink, false, link);
+ }
+
+ /**
+ * Removes tag
+ */
+ private unlink(): void {
+ document.execCommand(this.commandUnlink);
+ }
+}
diff --git a/src/components/interfaces/api.ts b/src/components/interfaces/api.ts
new file mode 100644
index 000000000..15931761e
--- /dev/null
+++ b/src/components/interfaces/api.ts
@@ -0,0 +1,213 @@
+import IInputOutputData from './input-output-data';
+
+/**
+ * CodeX Editor Public API
+ *
+ * @copyright 2018
+ */
+export interface IAPI {
+ blocks: IBlocksAPI;
+ caret: ICaretAPI;
+ events: IEventsAPI;
+ listener: IListenerAPI;
+ sanitizer: ISanitizerAPI;
+ saver: ISaverAPI;
+ selection: ISelectionAPI;
+ styles: IStylesAPI;
+ toolbar: IToolbarAPI;
+}
+
+/**
+ * Working with Blocks list: moving, removing, etc
+ */
+export interface IBlocksAPI {
+
+ /**
+ * Clears Blocks list
+ */
+ clear: () => void;
+
+ /**
+ * Fills editor with Blocks data
+ */
+ render: (data: IInputOutputData) => void;
+
+ /**
+ * Removes block
+ */
+ delete: (blockIndex?: number) => void;
+
+ /**
+ * Swap two Blocks by positions
+ * @param {number} fromIndex - position of first Block
+ * @param {number} toIndex - position of second Block
+ */
+ swap: (fromIndex: number, toIndex: number) => void;
+
+ /**
+ * Returns block by passed index
+ *
+ * @param {Number} index - needed block with index
+ * @return {object}
+ */
+ getBlockByIndex: (index: number) => object;
+
+ /**
+ * Returns current block index
+ * @return {number}
+ */
+ getCurrentBlockIndex: () => number;
+
+ /**
+ * Returns Block's count
+ * @return {number}
+ */
+ getBlocksCount: () => number;
+
+ /**
+ * Stretch Block's content
+ * @param {number} index - index of Block
+ * @param {boolean} [status] - true to enable, false to disable
+ */
+ stretchBlock: (index: number, status: boolean) => void;
+
+ /**
+ * Insert new initial typed Block
+ */
+ insertNewBlock: () => void;
+}
+
+/**
+ * Methods for working with Caret
+ */
+export interface ICaretAPI {
+ /**
+ * @todo Add caret methods
+ */
+}
+
+/**
+ * Events Module API methods
+ */
+export interface IEventsAPI {
+
+ /**
+ * Subsribe on events
+ */
+ on: (eventName: string, callback: () => void) => void;
+
+ /**
+ * Trigger subsribed callbacks
+ */
+ emit: (eventName: string, data: object) => void;
+
+ /**
+ * Unsubsribe callback
+ */
+ off: (eventName: string, callback: () => void) => void;
+}
+
+/**
+ * DOM Listener API
+ */
+export interface IListenerAPI {
+
+ /**
+ * Adds event listener
+ * @param {HTMLElement} element
+ * @param {string} eventType
+ * @param {() => void} handler
+ * @param useCapture
+ * @return {boolean}
+ */
+ on: (element: HTMLElement, eventType: string, handler: () => void, useCapture: boolean) => void;
+
+ /**
+ * Remove event listener
+ * @param {HTMLElement} element
+ * @param {string} eventType
+ * @param {() => void} handler
+ */
+ off: (element: HTMLElement, eventType: string, handler: () => void) => void;
+}
+
+/**
+ * Sanitizer's methods
+ */
+export interface ISanitizerAPI {
+
+ /**
+ * Clean taint string from disallowed tags and attributes
+ *
+ * @param taintString
+ * @param config
+ */
+ clean: (taintString, config?) => string;
+}
+
+/**
+ * Saver's methods
+ */
+export interface ISaverAPI {
+ /**
+ * Return current blocks
+ *
+ * @return {IInputOutputData}
+ */
+ save: () => IInputOutputData;
+}
+
+/**
+ * SelectionUtils's methods
+ */
+export interface ISelectionAPI {
+
+ /**
+ * Looks ahead to find passed tag from current selection
+ *
+ * @param {String} tagName
+ * @param {String} className
+ */
+ findParentTag: (tagName: string, className: string) => HTMLElement|null;
+
+ /**
+ * Expands selection range to the passed parent node
+ *
+ * @param {HTMLElement} node
+ */
+ expandToTag: (node: HTMLElement) => void;
+}
+
+export interface IStylesAPI {
+
+ block: string;
+
+ inlineToolButton: string;
+
+ inlineToolButtonActive: string;
+
+ input: string;
+
+ loader: string;
+
+ settingsButton: string;
+
+ settingsButtonActive: string;
+}
+
+/**
+ * Toolbar's methods
+ * Basic toolbar methods
+ */
+export interface IToolbarAPI {
+
+ /**
+ * Opens only toolbar
+ */
+ open: () => void;
+
+ /**
+ * Closes toolbar. If toolbox or toolbar-blockSettings are opened then they will be closed too
+ */
+ close: () => void;
+}
diff --git a/src/components/interfaces/block-tune.ts b/src/components/interfaces/block-tune.ts
new file mode 100644
index 000000000..831392361
--- /dev/null
+++ b/src/components/interfaces/block-tune.ts
@@ -0,0 +1,29 @@
+export interface IBlockTuneConstructor {
+ new (data: {api: any, settings: any});
+}
+
+/**
+ * BlockTune interface
+ *
+ * All tunes must implement this interface
+ */
+export interface IBlockTune {
+ /**
+ * Settings will be described later
+ */
+ settings?: object;
+
+ /**
+ * Returns tune button that will be appended in default settings area
+ */
+ render(): HTMLElement;
+
+ /**
+ * handle Click event
+ * @param {MouseEvent} event
+ * @param {HTMLElement} button
+ */
+ handleClick(event: MouseEvent, button: HTMLElement): void;
+}
+
+export default IBlockTune;
diff --git a/src/components/interfaces/editor-config.ts b/src/components/interfaces/editor-config.ts
new file mode 100644
index 000000000..0c631589b
--- /dev/null
+++ b/src/components/interfaces/editor-config.ts
@@ -0,0 +1,52 @@
+import ISanitizerConfig from './sanitizer-config';
+import IInputOutputData from './input-output-data';
+import IToolSettings from './tools/tool-settings';
+import ITool from './tools/tool';
+
+/**
+ * Editor Instance config
+ */
+export default interface IEditorConfig {
+
+ /**
+ * Element to append Editor
+ */
+ holderId: string;
+
+ /**
+ * Map of used Tools with or without configuration
+ */
+ tools: {[toolName: string]: ITool|IToolSettings};
+
+ /**
+ * This Tool will be added by default
+ * Name should be equal a one Tool's key of Editor's Tools
+ */
+ initialBlock: string;
+
+ /**
+ * Blocks list in JSON-format
+ */
+ data?: IInputOutputData;
+
+ /**
+ * First Block placeholder
+ */
+ placeholder?: string;
+
+ /**
+ * Define tags not to be stripped off while pasting
+ * @see {@link sanitizer}
+ */
+ sanitizer?: ISanitizerConfig;
+
+ /**
+ * Do not show toolbar
+ */
+ hideToolbar?: boolean;
+
+ /**
+ * Editor initialization callback
+ */
+ onReady?(): void;
+}
diff --git a/src/components/interfaces/editor.ts b/src/components/interfaces/editor.ts
new file mode 100644
index 000000000..72c22e0c1
--- /dev/null
+++ b/src/components/interfaces/editor.ts
@@ -0,0 +1,60 @@
+import BlockEvents from '../modules/block-events';
+import InlineToolbar from '../modules/toolbar-inline';
+import ListenerAPI from '../modules/api-listener';
+import Module from '../__module';
+import SanitizerAPI from '../modules/api-sanitizer';
+import SaverAPI from '../modules/api-saver';
+import SelectionAPI from '../modules/api-selection';
+import ToolbarAPI from '../modules/api-toolbar';
+import API from '../modules/api';
+import StylesAPI from '../modules/api-styles';
+import Shortcuts from '../modules/shortcuts';
+
+export default interface IEditor {
+
+ API: API;
+
+ BlockEvents: BlockEvents;
+
+ BlockSettings: Module; // @todo create interface
+
+ BlocksAPI: Module; // @todo create interface
+
+ Caret: Module; // @todo create interface
+
+ Events: Module; // @todo create interface
+
+ EventsAPI: Module; // @todo create interface
+
+ InlineToolbar: InlineToolbar;
+
+ ListenerAPI: ListenerAPI;
+
+ Listeners: Module; // @todo create interface
+
+ Renderer: Module; // @todo create interface
+
+ Sanitizer: Module; // @todo create interface
+
+ SanitizerAPI: SanitizerAPI;
+
+ Saver: Module; // @todo create interface
+
+ SaverAPI: SaverAPI;
+
+ SelectionAPI: SelectionAPI;
+
+ Shortcuts: Shortcuts;
+
+ StylesAPI: StylesAPI;
+
+ Toolbar: Module; // @todo create interface
+
+ ToolbarAPI: ToolbarAPI;
+
+ Toolbox: Module; // @todo create interface
+
+ Tools: Module; // @todo create interface
+
+ UI: Module; // @todo create interface
+}
diff --git a/src/components/interfaces/input-output-data.ts b/src/components/interfaces/input-output-data.ts
new file mode 100644
index 000000000..824faa206
--- /dev/null
+++ b/src/components/interfaces/input-output-data.ts
@@ -0,0 +1,23 @@
+import IBlockToolData from './tools/block-tool-data';
+
+/**
+ * Interface represents input CodeX Editor data
+ * that passed with initial configuration object as 'data' key
+ */
+export default interface IInputOutputData {
+
+ /**
+ * Timestamp of saving in milliseconds
+ */
+ readonly time?: number;
+
+ /**
+ * Saved Blocks
+ */
+ readonly blocks: IBlockToolData[];
+
+ /**
+ * Editor's version
+ */
+ readonly version?: string;
+}
diff --git a/src/components/interfaces/module-config.ts b/src/components/interfaces/module-config.ts
new file mode 100644
index 000000000..6afa04f39
--- /dev/null
+++ b/src/components/interfaces/module-config.ts
@@ -0,0 +1,12 @@
+import IEditorConfig from './editor-config';
+
+/**
+ * Internal Module's construction parameters
+ */
+export default interface IModuleConfig {
+
+ /**
+ * Editor's config
+ */
+ config: IEditorConfig;
+}
diff --git a/src/components/interfaces/sanitizer-config.ts b/src/components/interfaces/sanitizer-config.ts
new file mode 100644
index 000000000..bbc303d61
--- /dev/null
+++ b/src/components/interfaces/sanitizer-config.ts
@@ -0,0 +1,36 @@
+export default interface ISanitizerConfig {
+
+ /**
+ * Tag name and params not to be stripped off
+ * @see {@link https://github.com/guardian/html-janitor}
+ *
+ * @example Save P tags
+ * p: true
+ *
+ * @example Save A tags and do not strip HREF attribute
+ * a: {
+ * href: true
+ * }
+ *
+ * @example Save A tags with TARGET="_blank" attribute
+ * a: function (aTag) {
+ * return aTag.target === '_black';
+ * }
+ *
+ * @example Save U tags that are not empty
+ * u: function(el){
+ * return el.textContent !== '';
+ * }
+ *
+ * @example For blockquote with class 'indent' save CLASS and STYLE attributes
+ * Otherwise strip all attributes
+ * blockquote: function(el) {
+ * if (el.classList.contains('indent')) {
+ * return { 'class': true, 'style': true };
+ * } else {
+ * return {};
+ * }
+ * }
+ */
+ [key: string]: boolean|object|(() => any);
+}
diff --git a/src/components/interfaces/shortcuts.ts b/src/components/interfaces/shortcuts.ts
new file mode 100644
index 000000000..214aa4019
--- /dev/null
+++ b/src/components/interfaces/shortcuts.ts
@@ -0,0 +1,40 @@
+/**
+ * Shortcuts Interface
+ *
+ * implements CodeX-Team shortcuts Module
+ * @see https://github.com/codex-team/codex.shortcuts
+ */
+export interface IShortcuts {
+
+ /**
+ * Adds shortcut
+ * @param {IShortcut} shortcut
+ */
+ add(shortcut: IShortcut): void;
+
+ /**
+ * removes shortcut
+ * @param {string} shortcut
+ */
+ remove(shortcut: string): void;
+}
+
+/**
+ * Shortcut interface
+ * Each shortcut must have name and handler
+ * `name` is a shortcut, like 'CMD+K', 'CMD+B' etc
+ * `handler` is a callback
+ */
+export interface IShortcut {
+
+ /**
+ * Shortcut name
+ * Ex. CMD+I, CMD+B ....
+ */
+ name: string;
+
+ /**
+ * Shortcut handler
+ */
+ handler(event): (event) => void;
+}
diff --git a/src/components/interfaces/tools/block-tool-data.ts b/src/components/interfaces/tools/block-tool-data.ts
new file mode 100644
index 000000000..66ff166fc
--- /dev/null
+++ b/src/components/interfaces/tools/block-tool-data.ts
@@ -0,0 +1,4 @@
+/**
+ * Object returned by Tool's {@link IBlockTool#save} method
+ */
+export default interface IBlockToolData {}
diff --git a/src/components/interfaces/tools/block-tool.ts b/src/components/interfaces/tools/block-tool.ts
new file mode 100644
index 000000000..729e8dec0
--- /dev/null
+++ b/src/components/interfaces/tools/block-tool.ts
@@ -0,0 +1,62 @@
+import IBlockToolData from './tool-settings';
+import ITool from './tool';
+
+/**
+ * Describe Block Tool object
+ * @see {@link docs/tools.md}
+ */
+export default interface IBlockTool extends ITool {
+
+ /**
+ * Pass `true` if Tool represents decorative empty Block
+ */
+ contentless?: boolean;
+
+ /**
+ * Should this Tool be displayed in the Editor's Toolbox
+ */
+ displayInToolbox?: boolean;
+
+ /**
+ * Disable ability to replace empty Block by Toolbox
+ */
+ irreplaceable?: boolean;
+
+ /**
+ * String with an icon for Toolbox
+ */
+ toolboxIcon?: string;
+
+ /**
+ * Return Tool's main block-wrapper
+ * @return {HTMLElement}
+ */
+ render(): HTMLElement;
+
+ /**
+ * Process Tool's element in DOM and return raw data
+ * @param {HTMLElement} block - element created by {@link IBlockTool#render} function
+ * @return {IBlockToolData}
+ */
+ save(block: HTMLElement): IBlockToolData;
+
+ /**
+ * Create Block's settings block
+ * @return {HTMLElement}
+ */
+ renderSettings?(): HTMLElement;
+
+ /**
+ * Validate Block's data
+ * @param {IBlockToolData} blockData
+ * @return {boolean}
+ */
+ validate?(blockData: IBlockToolData): boolean;
+
+ /**
+ * Method that specified how to merge two Blocks with same type.
+ * Called by backspace at the beginning of the Block
+ * @param {IBlockToolData} blockData
+ */
+ merge?(blockData: IBlockToolData): void;
+}
diff --git a/src/components/interfaces/tools/inline-tool.ts b/src/components/interfaces/tools/inline-tool.ts
new file mode 100644
index 000000000..282dbcf2b
--- /dev/null
+++ b/src/components/interfaces/tools/inline-tool.ts
@@ -0,0 +1,41 @@
+/**
+ * Base structure for the Inline Toolbar Tool
+ */
+import ITool from './tool';
+
+export default interface IInlineTool extends ITool {
+ /**
+ * Public getter with shortcut string
+ */
+ shortcut?: string;
+
+ /**
+ * Returns button for the Inline Toolbar
+ */
+ render(): HTMLElement;
+
+ /**
+ * Method that accepts selected range and wrap it somehow
+ * @param {Range} range - selection's range
+ */
+ surround(range: Range): void;
+
+ /**
+ * Get SelectionUtils and detect if Tool was applied
+ * For example, after that Tool can highlight button or show some details
+ * @param {Selection} selection - current Selection
+ */
+ checkState(selection: Selection): boolean;
+
+ /**
+ * Make additional element with actions
+ * For example, input for the 'link' tool or textarea for the 'comment' tool
+ */
+ renderActions?(): HTMLElement;
+
+ /**
+ * Function called with Inline Toolbar closing
+ */
+ clear?(): void;
+
+}
diff --git a/src/components/interfaces/tools/tool-settings.ts b/src/components/interfaces/tools/tool-settings.ts
new file mode 100644
index 000000000..89a9ec139
--- /dev/null
+++ b/src/components/interfaces/tools/tool-settings.ts
@@ -0,0 +1,39 @@
+/**
+ * Object passed to the Tool's constructor by {@link IEditorConfig#tools}
+ */
+import ITool from './tool';
+
+export default interface IToolSettings {
+
+ /**
+ * Tool's class
+ */
+ class: ITool;
+
+ /**
+ * User configuration object that will be passed to the Tool's constructor
+ */
+ config?: object;
+
+ /**
+ * Disable module {@link Paste} for this Tool
+ * @todo remove this option
+ */
+ disallowPaste?: boolean;
+
+ /**
+ * Is user available to add line brakes in Tool (for example by Shift+Enter)
+ */
+ enableLineBreaks?: boolean;
+
+ /**
+ * Is need to show Inline Toolbar.
+ * Can accept array of Tools for InlineToolbar or boolean.
+ */
+ inlineToolbar?: boolean|string[];
+
+ /**
+ * Define shortcut that will render Tool
+ */
+ shortcut?: string;
+}
diff --git a/src/components/interfaces/tools/tool.ts b/src/components/interfaces/tools/tool.ts
new file mode 100644
index 000000000..f5b6e5dd8
--- /dev/null
+++ b/src/components/interfaces/tools/tool.ts
@@ -0,0 +1,10 @@
+/**
+ * Abstract interface of all Tools
+ */
+export default interface ITool {
+
+ /**
+ * Define Tool type as Inline
+ */
+ isInline?: boolean;
+}
diff --git a/src/components/modules/_destroyer.js b/src/components/modules/_destroyer.js
new file mode 100644
index 000000000..c168f3fb4
--- /dev/null
+++ b/src/components/modules/_destroyer.js
@@ -0,0 +1,70 @@
+/**
+ * Codex Editor Destroyer module
+ *
+ * @auhor Codex Team
+ * @version 1.0
+ */
+
+module.exports = function (destroyer) {
+ let editor = codex.editor;
+
+ destroyer.removeNodes = function () {
+ editor.nodes.wrapper.remove();
+ editor.nodes.notifications.remove();
+ };
+
+ destroyer.destroyPlugins = function () {
+ for (var tool in editor.tools) {
+ if (typeof editor.tools[tool].destroy === 'function') {
+ editor.tools[tool].destroy();
+ }
+ }
+ };
+
+ destroyer.destroyScripts = function () {
+ var scripts = document.getElementsByTagName('SCRIPT');
+
+ for (var i = 0; i < scripts.length; i++) {
+ if (scripts[i].id.indexOf(editor.scriptPrefix) + 1) {
+ scripts[i].remove();
+ i--;
+ }
+ }
+ };
+
+
+ /**
+ * Delete editor data from webpage.
+ * You should send settings argument with boolean flags:
+ * @param settings.ui- remove redactor event listeners and DOM nodes
+ * @param settings.scripts - remove redactor scripts from DOM
+ * @param settings.plugins - remove plugin's objects
+ * @param settings.core - remove editor core. You can remove core only if UI and scripts flags is true
+ * }
+ *
+ */
+ destroyer.destroy = function (settings) {
+ if (!settings || typeof settings !== 'object') {
+ return;
+ }
+
+ if (settings.ui) {
+ destroyer.removeNodes();
+ editor.listeners.removeAll();
+ }
+
+ if (settings.scripts) {
+ destroyer.destroyScripts();
+ }
+
+ if (settings.plugins) {
+ destroyer.destroyPlugins();
+ }
+
+ if (settings.ui && settings.scripts && settings.core) {
+ delete codex.editor;
+ }
+ };
+
+ return destroyer;
+}({});
\ No newline at end of file
diff --git a/src/components/modules/_notifications.js b/src/components/modules/_notifications.js
new file mode 100644
index 000000000..1746ae6fd
--- /dev/null
+++ b/src/components/modules/_notifications.js
@@ -0,0 +1,187 @@
+/**
+ * Codex Editor Notification Module
+ *
+ * @author Codex Team
+ * @version 1.0
+ */
+
+module.exports = (function (notifications) {
+ let editor = codex.editor;
+
+ var queue = [];
+
+ var addToQueue = function (settings) {
+ queue.push(settings);
+
+ var index = 0;
+
+ while ( index < queue.length && queue.length > 5) {
+ if (queue[index].type == 'confirm' || queue[index].type == 'prompt') {
+ index++;
+ continue;
+ }
+
+ queue[index].close();
+ queue.splice(index, 1);
+ }
+ };
+
+ notifications.createHolder = function () {
+ var holder = editor.draw.node('DIV', 'cdx-notifications-block');
+
+ editor.nodes.notifications = document.body.appendChild(holder);
+
+ return holder;
+ };
+
+
+ /**
+ * Error notificator. Shows block with message
+ * @protected
+ */
+ notifications.errorThrown = function (errorMsg, event) {
+ editor.notifications.notification({message: 'This action is not available currently', type: event.type});
+ };
+
+ /**
+ *
+ * Appends notification
+ *
+ * settings = {
+ * type - notification type (reserved types: alert, confirm, prompt). Just add class 'cdx-notification-'+type
+ * message - notification message
+ * okMsg - confirm button text (default - 'Ok')
+ * cancelBtn - cancel button text (default - 'Cancel'). Only for confirm and prompt types
+ * confirm - function-handler for ok button click
+ * cancel - function-handler for cancel button click. Only for confirm and prompt types
+ * time - time (in seconds) after which notification will close (default - 10s)
+ * }
+ *
+ * @param settings
+ */
+ notifications.notification = function (constructorSettings) {
+ /** Private vars and methods */
+ var notification = null,
+ cancel = null,
+ type = null,
+ confirm = null,
+ inputField = null;
+
+ var confirmHandler = function () {
+ close();
+
+ if (typeof confirm !== 'function' ) {
+ return;
+ }
+
+ if (type == 'prompt') {
+ confirm(inputField.value);
+ return;
+ }
+
+ confirm();
+ };
+
+ var cancelHandler = function () {
+ close();
+
+ if (typeof cancel !== 'function' ) {
+ return;
+ }
+
+ cancel();
+ };
+
+
+ /** Public methods */
+ function create(settings) {
+ if (!(settings && settings.message)) {
+ editor.core.log('Can\'t create notification. Message is missed');
+ return;
+ }
+
+ settings.type = settings.type || 'alert';
+ settings.time = settings.time*1000 || 10000;
+
+ var wrapper = editor.draw.node('DIV', 'cdx-notification'),
+ message = editor.draw.node('DIV', 'cdx-notification__message'),
+ input = editor.draw.node('INPUT', 'cdx-notification__input'),
+ okBtn = editor.draw.node('SPAN', 'cdx-notification__ok-btn'),
+ cancelBtn = editor.draw.node('SPAN', 'cdx-notification__cancel-btn');
+
+ message.textContent = settings.message;
+ okBtn.textContent = settings.okMsg || 'ОК';
+ cancelBtn.textContent = settings.cancelMsg || 'Отмена';
+
+ editor.listeners.add(okBtn, 'click', confirmHandler);
+ editor.listeners.add(cancelBtn, 'click', cancelHandler);
+
+ wrapper.appendChild(message);
+
+ if (settings.type == 'prompt') {
+ wrapper.appendChild(input);
+ }
+
+ wrapper.appendChild(okBtn);
+
+ if (settings.type == 'prompt' || settings.type == 'confirm') {
+ wrapper.appendChild(cancelBtn);
+ }
+
+ wrapper.classList.add('cdx-notification-' + settings.type);
+ wrapper.dataset.type = settings.type;
+
+ notification = wrapper;
+ type = settings.type;
+ confirm = settings.confirm;
+ cancel = settings.cancel;
+ inputField = input;
+
+ if (settings.type != 'prompt' && settings.type != 'confirm') {
+ window.setTimeout(close, settings.time);
+ }
+ };
+
+ /**
+ * Show notification block
+ */
+ function send() {
+ editor.nodes.notifications.appendChild(notification);
+ inputField.focus();
+
+ editor.nodes.notifications.classList.add('cdx-notification__notification-appending');
+
+ window.setTimeout(function () {
+ editor.nodes.notifications.classList.remove('cdx-notification__notification-appending');
+ }, 100);
+
+ addToQueue({type: type, close: close});
+ };
+
+ /**
+ * Remove notification block
+ */
+ function close() {
+ notification.remove();
+ };
+
+
+ if (constructorSettings) {
+ create(constructorSettings);
+ send();
+ }
+
+ return {
+ create: create,
+ send: send,
+ close: close
+ };
+ };
+
+ notifications.clear = function () {
+ editor.nodes.notifications.innerHTML = '';
+ queue = [];
+ };
+
+ return notifications;
+})({});
\ No newline at end of file
diff --git a/src/components/modules/api-blocks.ts b/src/components/modules/api-blocks.ts
new file mode 100644
index 000000000..eae5fad70
--- /dev/null
+++ b/src/components/modules/api-blocks.ts
@@ -0,0 +1,145 @@
+declare var Module: any;
+
+import { IBlocksAPI } from '../interfaces/api';
+import IInputOutputData from '../interfaces/input-output-data';
+import IModuleConfig from '../interfaces/module-config';
+
+/**
+ * @class BlocksAPI
+ * provides with methods working with Block
+ */
+export default class BlocksAPI extends Module implements IBlocksAPI {
+
+ /**
+ * Save Editor config. API provides passed configuration to the Blocks
+ */
+ constructor({config}: IModuleConfig) {
+ super({config});
+ }
+
+ /**
+ * Available methods
+ * @return {IBlocksAPI}
+ */
+ get methods(): IBlocksAPI {
+ return {
+ clear: () => this.clear(),
+ render: (data: IInputOutputData) => this.render(data),
+ delete: () => this.delete(),
+ swap: (fromIndex: number, toIndex: number) => this.swap(fromIndex, toIndex),
+ getBlockByIndex: (index: number) => this.getBlockByIndex(index),
+ getCurrentBlockIndex: () => this.getCurrentBlockIndex(),
+ getBlocksCount: () => this.getBlocksCount(),
+ stretchBlock: (index: number, status: boolean) => this.stretchBlock(index, status),
+ insertNewBlock: () => this.insertNewBlock(),
+ };
+ }
+
+ /**
+ * Returns Blocks count
+ * @return {number}
+ */
+ public getBlocksCount(): number {
+ return this.Editor.BlockManager.blocks.length;
+ }
+
+ /**
+ * Returns current block index
+ * @return {number}
+ */
+ public getCurrentBlockIndex(): number {
+ return this.Editor.BlockManager.currentBlockIndex;
+ }
+
+ /**
+ * Returns Current Block
+ * @param {Number} index
+ *
+ * @return {Object}
+ */
+ public getBlockByIndex(index: number): object {
+ return this.Editor.BlockManager.getBlockByIndex(index);
+ }
+
+ /**
+ * Call Block Manager method that swap Blocks
+ * @param {number} fromIndex - position of first Block
+ * @param {number} toIndex - position of second Block
+ */
+ public swap(fromIndex: number, toIndex: number): void {
+ this.Editor.BlockManager.swap(fromIndex, toIndex);
+
+ /**
+ * Move toolbar
+ * DO not close the settings
+ */
+ this.Editor.Toolbar.move(false);
+ }
+
+ /**
+ * Deletes Block
+ * @param blockIndex
+ */
+ public delete(blockIndex?: number): void {
+ this.Editor.BlockManager.removeBlock(blockIndex);
+
+ /**
+ * in case of last block deletion
+ * Insert new initial empty block
+ */
+ if (this.Editor.BlockManager.blocks.length === 0) {
+ this.Editor.BlockManager.insert();
+ }
+
+ /**
+ * In case of deletion first block we need to set caret to the current Block
+ */
+ if (this.Editor.BlockManager.currentBlockIndex === 0) {
+ this.Editor.Caret.setToBlock(this.Editor.BlockManager.currentBlock);
+ } else {
+ this.Editor.Caret.navigatePrevious(true);
+ }
+
+ this.Editor.Toolbar.close();
+ }
+
+ /**
+ * Clear Editor's area
+ */
+ public clear(): void {
+ this.Editor.BlockManager.clear(true);
+ }
+
+ /**
+ * Fills Editor with Blocks data
+ * @param {IInputOutputData} data — Saved Editor data
+ */
+ public render(data: IInputOutputData): void {
+ this.Editor.BlockManager.clear();
+ this.Editor.Renderer.render(data.blocks);
+ }
+
+ /**
+ * Stretch Block's content
+ * @param {number} index
+ * @param {boolean} status - true to enable, false to disable
+ */
+ public stretchBlock(index: number, status: boolean): void {
+ const block = this.Editor.BlockManager.getBlockByIndex(index);
+
+ if (!block) {
+ return;
+ }
+
+ block.stretched = status !== undefined ? status : true;
+ }
+
+ /**
+ * Insert new Block
+ * After set caret to this Block
+ */
+ public insertNewBlock() {
+ const newBlock = this.Editor.BlockManager.insert();
+ this.Editor.Caret.setToBlock(newBlock);
+ }
+}
diff --git a/src/components/modules/api-caret.ts b/src/components/modules/api-caret.ts
new file mode 100644
index 000000000..5fb27a0f7
--- /dev/null
+++ b/src/components/modules/api-caret.ts
@@ -0,0 +1,26 @@
+declare var Module: any;
+
+import {ICaretAPI} from '../interfaces/api';
+import IModuleConfig from '../interfaces/module-config';
+
+/**
+ * @class CaretAPI
+ * provides with methods to work with caret
+ */
+export default class CaretAPI extends Module implements ICaretAPI {
+
+ /**
+ * Save Editor config. API provides passed configuration to the Blocks
+ */
+ constructor({config}: IModuleConfig) {
+ super({config});
+ }
+
+ /**
+ * Available methods
+ * @return {ICaretAPI}
+ */
+ get methods(): ICaretAPI {
+ return {};
+ }
+}
diff --git a/src/components/modules/api-events.ts b/src/components/modules/api-events.ts
new file mode 100644
index 000000000..43bb55b0f
--- /dev/null
+++ b/src/components/modules/api-events.ts
@@ -0,0 +1,58 @@
+declare var Module: any;
+
+import {IEventsAPI} from '../interfaces/api';
+import IModuleConfig from '../interfaces/module-config';
+
+/**
+ * @class EventsAPI
+ * provides with methods working with Toolbar
+ */
+export default class EventsAPI extends Module implements IEventsAPI {
+
+ /**
+ * Save Editor config. API provides passed configuration to the Blocks
+ */
+ constructor({config}: IModuleConfig) {
+ super({config});
+ }
+
+ /**
+ * Available methods
+ * @return {IEventsAPI}
+ */
+ get methods(): IEventsAPI {
+ return {
+ emit: (eventName: string, data: object) => this.emit(eventName, data),
+ off: (eventName: string, callback: () => void) => this.off(eventName, callback),
+ on: (eventName: string, callback: () => void) => this.on(eventName, callback),
+ };
+ }
+
+ /**
+ * Subscribe on Events
+ * @param {String} eventName
+ * @param {Function} callback
+ */
+ public on(eventName, callback): void {
+ this.Editor.Events.on(eventName, callback);
+ }
+
+ /**
+ * Emit event with data
+ * @param {String} eventName
+ * @param {Object} data
+ */
+ public emit(eventName, data): void {
+ this.Editor.Events.emit(eventName, data);
+ }
+
+ /**
+ * Unsubscribe from Event
+ * @param {String} eventName
+ * @param {Function} callback
+ */
+ public off(eventName, callback): void {
+ this.Editor.Events.off(eventName, callback);
+ }
+
+}
diff --git a/src/components/modules/api-listener.ts b/src/components/modules/api-listener.ts
new file mode 100644
index 000000000..4e3eb8d2d
--- /dev/null
+++ b/src/components/modules/api-listener.ts
@@ -0,0 +1,52 @@
+declare var Module: any;
+
+import {IListenerAPI} from '../interfaces/api';
+import IModuleConfig from '../interfaces/module-config';
+
+/**
+ * @class API
+ * Provides with methods working with DOM Listener
+ */
+export default class ListenerAPI extends Module implements IListenerAPI {
+
+ /**
+ * Save Editor config. API provides passed configuration to the Blocks
+ */
+ constructor({config}: IModuleConfig) {
+ super({config});
+ }
+
+ /**
+ * Available methods
+ * @return {IToolbarAPI}
+ */
+ get methods(): IListenerAPI {
+ return {
+ on: (element, eventType, handler, useCapture) => this.on(element, eventType, handler, useCapture),
+ off: (element, eventType, handler) => this.off(element, eventType, handler),
+ };
+ }
+
+ /**
+ * adds DOM event listener
+ *
+ * @param {HTMLElement} element
+ * @param {string} eventType
+ * @param {() => void} handler
+ * @param {boolean} useCapture
+ */
+ public on(element: HTMLElement, eventType: string, handler: () => void, useCapture?: boolean): void {
+ this.Editor.Listeners.on(element, eventType, handler, useCapture);
+ }
+
+ /**
+ * Removes DOM listener from element
+ *
+ * @param element
+ * @param eventType
+ * @param handler
+ */
+ public off(element, eventType, handler): void {
+ this.Editor.Listeners.off(element, eventType, handler);
+ }
+}
diff --git a/src/components/modules/api-sanitizer.ts b/src/components/modules/api-sanitizer.ts
new file mode 100644
index 000000000..3baf074da
--- /dev/null
+++ b/src/components/modules/api-sanitizer.ts
@@ -0,0 +1,33 @@
+declare var Module: any;
+
+import {ISanitizerAPI} from '../interfaces/api';
+import IModuleConfig from '../interfaces/module-config';
+
+/**
+ * @class API
+ * Provides CodeX Editor Sanitizer that allows developers to clean their HTML
+ */
+export default class SanitizerAPI extends Module implements ISanitizerAPI {
+
+ /**
+ * Save Editor config. API provides passed configuration to the Blocks
+ */
+ constructor({config}: IModuleConfig) {
+ super({config});
+ }
+
+ /**
+ * Available methods
+ * @return {ISanitizerAPI}
+ */
+ get methods(): ISanitizerAPI {
+ return {
+ clean: (taintString, config) => this.clean(taintString, config),
+ };
+ }
+
+ public clean(taintString, config) {
+ return this.Editor.Sanitizer.clean(taintString, config);
+ }
+
+}
diff --git a/src/components/modules/api-saver.ts b/src/components/modules/api-saver.ts
new file mode 100644
index 000000000..fef987c89
--- /dev/null
+++ b/src/components/modules/api-saver.ts
@@ -0,0 +1,36 @@
+declare var Module: any;
+
+import {ISaverAPI} from '../interfaces/api';
+import IInputOutputData from '../interfaces/input-output-data';
+import IModuleConfig from '../interfaces/module-config';
+
+/**
+ * @class SaverAPI
+ * provides with methods to save data
+ */
+export default class SaverAPI extends Module implements ISaverAPI {
+
+ /**
+ * Save Editor config. API provides passed configuration to the Blocks
+ */
+ constructor({config}: IModuleConfig) {
+ super({config});
+ }
+
+ /**
+ * Available methods
+ * @return {ISaverAPI}
+ */
+ get methods(): ISaverAPI {
+ return {
+ save: () => this.save(),
+ };
+ }
+
+ /**
+ * Return Editor's data
+ */
+ public save(): IInputOutputData {
+ return this.Editor.Saver.save();
+ }
+}
diff --git a/src/components/modules/api-selection.ts b/src/components/modules/api-selection.ts
new file mode 100644
index 000000000..187bd8f29
--- /dev/null
+++ b/src/components/modules/api-selection.ts
@@ -0,0 +1,49 @@
+declare var Module: any;
+
+import {ISelectionAPI} from '../interfaces/api';
+import IModuleConfig from '../interfaces/module-config';
+import Selection from '../selection';
+
+/**
+ * @class API
+ * Provides with methods working with SelectionUtils
+ */
+export default class SelectionAPI extends Module implements ISelectionAPI {
+
+ /**
+ * Save Editor config. API provides passed configuration to the Blocks
+ */
+ constructor({config}: IModuleConfig) {
+ super({config});
+ }
+
+ /**
+ * Available methods
+ * @return {ISelectionAPI}
+ */
+ get methods(): ISelectionAPI {
+ return {
+ findParentTag: (tagName: string, className: string) => this.findParentTag(tagName, className),
+ expandToTag: (node: HTMLElement) => this.expandToTag(node),
+ };
+ }
+
+ /**
+ * Looks ahead from selection and find passed tag with class name
+ * @param {string} tagName - tag to find
+ * @param {string} className - tag's class name
+ * @return {HTMLElement|null}
+ */
+ public findParentTag(tagName: string, className: string): HTMLElement|null {
+ return new Selection().findParentTag(tagName, className);
+ }
+
+ /**
+ * Expand selection to passed tag
+ * @param {HTMLElement} node - tag that should contain selection
+ */
+ public expandToTag(node: HTMLElement): void {
+ new Selection().expandToTag(node);
+ }
+
+}
diff --git a/src/components/modules/api-styles.ts b/src/components/modules/api-styles.ts
new file mode 100644
index 000000000..901f76307
--- /dev/null
+++ b/src/components/modules/api-styles.ts
@@ -0,0 +1,45 @@
+declare var Module: any;
+
+import IModuleConfig from '../interfaces/module-config';
+import {IStylesAPI} from '../interfaces/api';
+
+/**
+ *
+ */
+export default class StylesAPI extends Module {
+
+ /**
+ * Save Editor config
+ * API provides passed configuration to the Blocks
+ */
+ constructor({config}: IModuleConfig) {
+ super({config});
+ }
+
+ get classes(): IStylesAPI {
+ return {
+ /**
+ * Base Block styles
+ */
+ block: 'cdx-block',
+
+ /**
+ * Inline Tools styles
+ */
+ inlineToolButton: 'ce-inline-tool',
+ inlineToolButtonActive: 'ce-inline-tool--active',
+
+ /**
+ * UI elements
+ */
+ input: 'cdx-input',
+ loader: 'cdx-loader',
+
+ /**
+ * Settings styles
+ */
+ settingsButton: 'cdx-settings-button',
+ settingsButtonActive: 'cdx-settings-button--active',
+ };
+ }
+}
diff --git a/src/components/modules/api-toolbar.ts b/src/components/modules/api-toolbar.ts
new file mode 100644
index 000000000..d3b116604
--- /dev/null
+++ b/src/components/modules/api-toolbar.ts
@@ -0,0 +1,44 @@
+declare var Module: any;
+
+import {IToolbarAPI} from '../interfaces/api';
+import IModuleConfig from '../interfaces/module-config';
+
+/**
+ * @class ToolbarsAPI
+ * provides with methods working with Toolbar
+ */
+export default class ToolbarAPI extends Module implements IToolbarAPI {
+
+ /**
+ * Save Editor config. API provides passed configuration to the Blocks
+ */
+ constructor({config}: IModuleConfig) {
+ super({config});
+ }
+
+ /**
+ * Available methods
+ * @return {IToolbarAPI}
+ */
+ get methods(): IToolbarAPI {
+ return {
+ close: () => this.close(),
+ open: () => this.open(),
+ };
+ }
+
+ /**
+ * Open toolbar
+ */
+ public open(): void {
+ this.Editor.Toolbar.open();
+ }
+
+ /**
+ * Close toolbar and all included elements
+ */
+ public close(): void {
+ this.Editor.Toolbar.close();
+ }
+
+}
diff --git a/src/components/modules/api.ts b/src/components/modules/api.ts
new file mode 100644
index 000000000..b9f6687cb
--- /dev/null
+++ b/src/components/modules/api.ts
@@ -0,0 +1,40 @@
+/**
+ * @module API
+ * @copyright 2018
+ *
+ * Each block has an Editor API instance to use provided public methods
+ * if you cant to read more about how API works, please see docs
+ */
+declare var Module: any;
+declare var $: any;
+declare var _: any;
+
+import { IAPI } from '../interfaces/api';
+
+/**
+ * @class API
+ */
+export default class API extends Module {
+
+ /**
+ * Save Editor config. API provides passed configuration to the Blocks
+ * @param {EditorConfig} config
+ */
+ constructor({config}) {
+ super({config});
+ }
+
+ public get methods(): IAPI {
+ return {
+ blocks: this.Editor.BlocksAPI.methods,
+ caret: this.Editor.CaretAPI.methods,
+ events: this.Editor.EventsAPI.methods,
+ listener: this.Editor.ListenerAPI.methods,
+ sanitizer: this.Editor.SanitizerAPI.methods,
+ saver: this.Editor.SaverAPI.methods,
+ selection: this.Editor.SelectionAPI.methods,
+ styles: this.Editor.StylesAPI.classes,
+ toolbar: this.Editor.ToolbarAPI.methods,
+ };
+ }
+}
diff --git a/src/components/modules/block-events.ts b/src/components/modules/block-events.ts
new file mode 100644
index 000000000..bdd65f9bb
--- /dev/null
+++ b/src/components/modules/block-events.ts
@@ -0,0 +1,301 @@
+/**
+ * Contains keyboard and mouse events binded on each Block by Block Manager
+ */
+declare var Module: any;
+declare var $: any;
+declare var _: any;
+
+export default class BlockEvents extends Module {
+ /**
+ * @constructor
+ */
+ constructor({config}) {
+ super({config});
+ }
+
+ /**
+ * All keydowns on Block
+ * @param {KeyboardEvent} event - keydown
+ */
+ public keydown(event: KeyboardEvent): void {
+ /**
+ * Run common method for all keydown events
+ */
+ this.beforeKeydownProcessing(event);
+
+ /**
+ * Fire keydown processor by event.keyCode
+ */
+ switch (event.keyCode) {
+ case _.keyCodes.BACKSPACE:
+ this.backspace(event);
+ break;
+
+ case _.keyCodes.ENTER:
+ this.enter(event);
+ break;
+
+ case _.keyCodes.DOWN:
+ case _.keyCodes.RIGHT:
+ this.arrowRightAndDown(event);
+ break;
+
+ case _.keyCodes.UP:
+ case _.keyCodes.LEFT:
+ this.arrowLeftAndUp(event);
+ break;
+
+ case _.keyCodes.TAB:
+ this.tabPressed(event);
+ break;
+
+ default:
+ this.defaultHandler();
+ break;
+ }
+ }
+
+ /**
+ * Fires on keydown before event processing
+ * @param {KeyboardEvent} event - keydown
+ */
+ public beforeKeydownProcessing(event): void {
+ /**
+ * Clear all highlightings
+ */
+ this.Editor.BlockManager.clearHighlightings();
+
+ /**
+ * Do not close Toolbox on Tabs or on Enter with opened Toolbox
+ */
+ if (!this.needToolbarClosing(event)) {
+ return;
+ }
+
+ this.Editor.Toolbar.close();
+ }
+
+ /**
+ * Key up on Block:
+ * - shows Inline Toolbar if something selected
+ */
+ public keyup(event): void {
+ this.Editor.InlineToolbar.handleShowingEvent(event);
+ }
+
+ /**
+ * Mouse up on Block:
+ * - shows Inline Toolbar if something selected
+ */
+ public mouseUp(event): void {
+ this.Editor.InlineToolbar.handleShowingEvent(event);
+ }
+
+ /**
+ * Open Toolbox to leaf Tools
+ * @param {KeyboardEvent} event
+ */
+ public tabPressed(event): void {
+
+ const {currentBlock} = this.Editor.BlockManager;
+
+ /** Prevent Default behaviour */
+ event.preventDefault();
+ event.stopPropagation();
+
+ /** this property defines leaf direction */
+ const shiftKey = event.shiftKey,
+ direction = shiftKey ? 'left' : 'right';
+
+ if (this.Editor.Toolbar.opened && currentBlock.isEmpty) {
+ this.Editor.Toolbox.open();
+ } else if (currentBlock.isEmpty) {
+ this.Editor.Toolbar.open();
+ this.Editor.Toolbox.open();
+ }
+
+ if (this.Editor.Toolbox.opened) {
+ this.Editor.Toolbox.leaf(direction);
+ }
+ }
+
+ /**
+ * ENTER pressed on block
+ * @param {KeyboardEvent} event - keydown
+ */
+ private enter(event: KeyboardEvent): void {
+ const currentBlock = this.Editor.BlockManager.currentBlock,
+ tool = this.Editor.Tools.toolsAvailable[currentBlock.name];
+
+ /**
+ * Don't handle Enter keydowns when Tool sets enableLineBreaks to true.
+ * Uses for Tools like where line breaks should be handled by default behaviour.
+ */
+ if (tool && tool[this.Editor.Tools.apiSettings.IS_ENABLED_LINE_BREAKS]) {
+ return;
+ }
+
+ if (this.Editor.Toolbox.opened && this.Editor.Toolbox.getActiveTool) {
+ event.preventDefault();
+ event.stopPropagation();
+ event.stopImmediatePropagation();
+ this.Editor.Toolbox.toolButtonActivate(event, this.Editor.Toolbox.getActiveTool);
+ return;
+ }
+
+ /**
+ * Allow to create linebreaks by Shift+Enter
+ */
+ if (event.shiftKey) {
+ return;
+ }
+ /**
+ * Split the Current Block into two blocks
+ * Renew local current node after split
+ */
+ const newCurrent = this.Editor.BlockManager.split();
+
+ this.Editor.Caret.setToBlock(newCurrent);
+
+ /**
+ * If new Block is empty
+ */
+ if (this.Editor.Tools.isInitial(newCurrent.tool) && newCurrent.isEmpty) {
+ /**
+ * Show Toolbar
+ */
+ this.Editor.Toolbar.open();
+
+ /**
+ * Show Plus Button
+ */
+ this.Editor.Toolbar.plusButton.show();
+ }
+
+ event.preventDefault();
+ event.stopPropagation();
+ event.stopImmediatePropagation();
+ }
+
+ /**
+ * Handle backspace keydown on Block
+ * @param {KeyboardEvent} event - keydown
+ */
+ private backspace(event: KeyboardEvent): void {
+ const BM = this.Editor.BlockManager;
+ const currentBlock = this.Editor.BlockManager.currentBlock,
+ tool = this.Editor.Tools.toolsAvailable[currentBlock.name];
+
+ /**
+ * Don't handle Backspaces when Tool sets enableLineBreaks to true.
+ * Uses for Tools like where line breaks should be handled by default behaviour.
+ */
+ if (tool && tool[this.Editor.Tools.apiSettings.IS_ENABLED_LINE_BREAKS]) {
+ return;
+ }
+
+ const isFirstBlock = BM.currentBlockIndex === 0,
+ canMergeBlocks = this.Editor.Caret.isAtStart && !isFirstBlock;
+
+ /** If current Block is empty just remove this Block */
+ if (this.Editor.BlockManager.currentBlock.isEmpty) {
+ this.Editor.BlockManager.removeBlock();
+
+ /**
+ * in case of last block deletion
+ * Insert new initial empty block
+ */
+ if (this.Editor.BlockManager.blocks.length === 0) {
+ this.Editor.BlockManager.insert();
+ }
+
+ /**
+ * In case of deletion first block we need to set caret to the current Block
+ * After BlockManager removes the Block (which is current now),
+ * pointer that references to the current Block, now points to the Next
+ */
+ if (this.Editor.BlockManager.currentBlockIndex === 0) {
+ this.Editor.Caret.setToBlock(this.Editor.BlockManager.currentBlock);
+ } else {
+ this.Editor.Caret.navigatePrevious(true);
+ }
+
+ this.Editor.Toolbar.close();
+ return;
+ }
+
+ if (!canMergeBlocks) {
+ return;
+ }
+
+ // preventing browser default behaviour
+ event.preventDefault();
+
+ const targetBlock = BM.getBlockByIndex(BM.currentBlockIndex - 1),
+ blockToMerge = BM.currentBlock;
+
+ /**
+ * Blocks that can be merged:
+ * 1) with the same Name
+ * 2) Tool has 'merge' method
+ *
+ * other case will handle as usual ARROW LEFT behaviour
+ */
+ if (blockToMerge.name !== targetBlock.name || !targetBlock.mergeable) {
+ if (this.Editor.Caret.navigatePrevious()) {
+ this.Editor.Toolbar.close();
+ }
+
+ return;
+ }
+
+ this.Editor.Caret.createShadow(targetBlock.pluginsContent);
+ BM.mergeBlocks(targetBlock, blockToMerge)
+ .then( () => {
+ /** Restore caret position after merge */
+ this.Editor.Caret.restoreCaret(targetBlock.pluginsContent);
+ targetBlock.pluginsContent.normalize();
+ this.Editor.Toolbar.close();
+ });
+ }
+
+ /**
+ * Handle right and down keyboard keys
+ */
+ private arrowRightAndDown(event: KeyboardEvent): void {
+ if (this.Editor.Caret.navigateNext()) {
+ /**
+ * Default behaviour moves cursor by 1 character, we need to prevent it
+ */
+ event.preventDefault();
+ }
+ }
+
+ /**
+ * Handle left and up keyboard keys
+ */
+ private arrowLeftAndUp(event: KeyboardEvent): void {
+ if (this.Editor.Caret.navigatePrevious()) {
+ /**
+ * Default behaviour moves cursor by 1 character, we need to prevent it
+ */
+ event.preventDefault();
+ }
+ }
+
+ /**
+ * Default keydown handler
+ */
+ private defaultHandler(): void {}
+
+ /**
+ * Cases when we need to close Toolbar
+ */
+ private needToolbarClosing(event) {
+ const toolboxItemSelected = (event.keyCode === _.keyCodes.ENTER && this.Editor.Toolbox.opened),
+ flippingToolboxItems = event.keyCode === _.keyCodes.TAB;
+
+ return !(event.shiftKey || flippingToolboxItems || toolboxItemSelected);
+ }
+
+}
diff --git a/src/components/modules/blockManager.js b/src/components/modules/blockManager.js
new file mode 100644
index 000000000..7cff7359a
--- /dev/null
+++ b/src/components/modules/blockManager.js
@@ -0,0 +1,663 @@
+/**
+ * @class BlockManager
+ * @classdesc Manage editor`s blocks storage and appearance
+ *
+ * @module BlockManager
+ *
+ * @version 2.0.0
+ */
+
+import Block from '../block';
+
+/**
+ * @typedef {BlockManager} BlockManager
+ * @property {Number} currentBlockIndex - Index of current working block
+ * @property {Proxy} _blocks - Proxy for Blocks instance {@link Blocks}
+ */
+export default class BlockManager extends Module {
+ /**
+ * @constructor
+ * @param {EditorConfig} config
+ */
+ constructor({config}) {
+ super({config});
+
+ /**
+ * Proxy for Blocks instance {@link Blocks}
+ *
+ * @type {Proxy}
+ * @private
+ */
+ this._blocks = null;
+
+ /**
+ * Index of current working block
+ *
+ * @type {number}
+ * @private
+ */
+ this.currentBlockIndex = -1;
+ }
+
+ /**
+ * Should be called after Editor.UI preparation
+ * Define this._blocks property
+ *
+ * @returns {Promise}
+ */
+ prepare() {
+ return new Promise(resolve => {
+ let blocks = new Blocks(this.Editor.UI.nodes.redactor);
+
+ /**
+ * We need to use Proxy to overload set/get [] operator.
+ * So we can use array-like syntax to access blocks
+ *
+ * @example
+ * this._blocks[0] = new Block(...);
+ *
+ * block = this._blocks[0];
+ *
+ * @todo proxy the enumerate method
+ *
+ * @type {Proxy}
+ * @private
+ */
+ this._blocks = new Proxy(blocks, {
+ set: Blocks.set,
+ get: Blocks.get
+ });
+
+ resolve();
+ });
+ }
+
+ /**
+ * Creates Block instance by tool name
+ *
+ * @param {String} toolName - tools passed in editor config {@link EditorConfig#tools}
+ * @param {Object} data - constructor params
+ * @param {Object} settings - block settings
+ *
+ * @return {Block}
+ */
+ composeBlock(toolName, data, settings) {
+ let toolInstance = this.Editor.Tools.construct(toolName, data),
+ toolClass = this.Editor.Tools.available[toolName],
+ block = new Block(toolName, toolInstance, toolClass, settings, this.Editor.API.methods);
+
+ this.bindEvents(block);
+ /**
+ * Apply callback before inserting html
+ */
+ block.call('appendCallback', {});
+
+ return block;
+ }
+
+ /**
+ * Bind Events
+ * @param {Object} block
+ */
+ bindEvents(block) {
+ this.Editor.Listeners.on(block.holder, 'keydown', (event) => this.Editor.BlockEvents.keydown(event), true);
+ this.Editor.Listeners.on(block.holder, 'mouseup', (event) => this.Editor.BlockEvents.mouseUp(event));
+ this.Editor.Listeners.on(block.holder, 'keyup', (event) => this.Editor.BlockEvents.keyup(event));
+ }
+
+ /**
+ * Insert new block into _blocks
+ *
+ * @param {String} toolName — plugin name, by default method inserts initial block type
+ * @param {Object} data — plugin data
+ * @param {Object} settings - default settings
+ *
+ * @return {Block}
+ */
+ insert(toolName = this.config.initialBlock, data = {}, settings = {}) {
+ // Increment index before construct,
+ // because developers can use API/Blocks/getCurrentInputIndex on the render() method
+ let newIndex = ++this.currentBlockIndex;
+ let block = this.composeBlock(toolName, data, settings);
+
+ this._blocks[newIndex] = block;
+ return block;
+ }
+
+ /**
+ * Always inserts at the end
+ * @return {Block}
+ */
+ insertAtEnd() {
+ /**
+ * Define new value for current block index
+ */
+ this.currentBlockIndex = this.blocks.length - 1;
+
+ /**
+ * Insert initial typed block
+ */
+ return this.insert();
+ }
+
+ /**
+ * Merge two blocks
+ * @param {Block} targetBlock - previous block will be append to this block
+ * @param {Block} blockToMerge - block that will be merged with target block
+ *
+ * @return {Promise} - the sequence that can be continued
+ */
+ mergeBlocks(targetBlock, blockToMerge) {
+ let blockToMergeIndex = this._blocks.indexOf(blockToMerge);
+
+ return Promise.resolve()
+ .then( () => {
+ if (blockToMerge.isEmpty) {
+ return;
+ }
+
+ return blockToMerge.data
+ .then((blockToMergeInfo) => {
+ targetBlock.mergeWith(blockToMergeInfo.data);
+ });
+ })
+ .then( () => {
+ this.removeBlock(blockToMergeIndex);
+ this.currentBlockIndex = this._blocks.indexOf(targetBlock);
+ });
+ }
+
+ /**
+ * Remove block with passed index or remove last
+ * @param {Number|null} index
+ */
+ removeBlock(index) {
+ if (!index) {
+ index = this.currentBlockIndex;
+ }
+ this._blocks.remove(index);
+
+ /**
+ * If first Block was removed, insert new Initial Block and set focus on it`s first input
+ */
+ if (!this.blocks.length) {
+ this.currentBlockIndex = -1;
+ this.insert();
+ this.currentBlock.firstInput.focus();
+ }
+ }
+
+ /**
+ * Split current Block
+ * 1. Extract content from Caret position to the Block`s end
+ * 2. Insert a new Block below current one with extracted content
+ *
+ * @return {Block}
+ */
+ split() {
+ let extractedFragment = this.Editor.Caret.extractFragmentFromCaretPosition(),
+ wrapper = $.make('div');
+
+ wrapper.append(extractedFragment);
+
+ /**
+ * @todo make object in accordance with Tool
+ */
+ let data = {
+ text: $.isEmpty(wrapper) ? '' : wrapper.innerHTML,
+ };
+
+ /**
+ * Renew current Block
+ * @type {Block}
+ */
+ return this.insert(this.config.initialBlock, data);
+ }
+
+ /**
+ * Replace current working block
+ *
+ * @param {String} toolName — plugin name
+ * @param {Object} data — plugin data
+ *
+ * @return {Block}
+ */
+ replace(toolName, data = {}) {
+ let block = this.composeBlock(toolName, data);
+
+ this._blocks.insert(this.currentBlockIndex, block, true);
+
+ return block;
+ }
+
+ /**
+ * returns last Block
+ * @return {Block}
+ */
+ get lastBlock() {
+ return this._blocks[this._blocks.length - 1];
+ }
+
+ /**
+ * Returns Block by passed index
+ * @param {Number} index
+ * @return {Block}
+ */
+ getBlockByIndex(index) {
+ return this._blocks[index];
+ }
+
+ /**
+ * Get Block instance by html element
+ * @param {Node} element
+ * @returns {Block}
+ */
+ getBlock(element) {
+ if (!$.isElement(element)) {
+ element = element.parentNode;
+ }
+
+ let nodes = this._blocks.nodes,
+ firstLevelBlock = element.closest(`.${Block.CSS.wrapper}`),
+ index = nodes.indexOf(firstLevelBlock);
+
+ if (index >= 0) {
+ return this._blocks[index];
+ }
+ }
+
+ /**
+ * Get current Block instance
+ *
+ * @return {Block}
+ */
+ get currentBlock() {
+ return this._blocks[this.currentBlockIndex];
+ }
+
+ /**
+ * Returns next Block instance
+ * @return {Block|null}
+ */
+ get nextBlock() {
+ let isLastBlock = this.currentBlockIndex === (this._blocks.length - 1);
+
+ if (isLastBlock) {
+ return null;
+ }
+
+ return this._blocks[this.currentBlockIndex + 1];
+ }
+
+ /**
+ * Return first Block with inputs after current Block
+ *
+ * @returns {Block | undefined}
+ */
+ get nextContentfulBlock() {
+ const nextBlocks = this.blocks.slice(this.currentBlockIndex + 1);
+
+ return nextBlocks.find(block => !!block.inputs.length);
+ }
+
+ /**
+ * Return first Block with inputs before current Block
+ *
+ * @returns {Block | undefined}
+ */
+ get previousContentfulBlock() {
+ const previousBlocks = this.blocks.slice(0, this.currentBlockIndex).reverse();
+
+ return previousBlocks.find(block => !!block.inputs.length);
+ }
+
+ /**
+ * Returns previous Block instance
+ * @return {Block|null}
+ */
+ get previousBlock() {
+ let isFirstBlock = this.currentBlockIndex === 0;
+
+ if (isFirstBlock) {
+ return null;
+ }
+
+ return this._blocks[this.currentBlockIndex - 1];
+ }
+
+ /**
+ * Get working html element
+ *
+ * @return {HTMLElement}
+ */
+ get currentNode() {
+ return this._blocks.nodes[this.currentBlockIndex];
+ }
+
+ /**
+ * Set currentBlockIndex to passed block
+ * @param {Node} element
+ */
+ set currentNode(element) {
+ if (!$.isElement(element)) {
+ element = element.parentNode;
+ }
+
+ let nodes = this._blocks.nodes,
+ firstLevelBlock = element.closest(`.${Block.CSS.wrapper}`);
+
+ if (!firstLevelBlock) {
+ throw Error('Passed element is not a Block.');
+ }
+
+
+ /**
+ * Update current Block's index
+ * @type {number}
+ */
+ this.currentBlockIndex = nodes.indexOf(firstLevelBlock);
+ }
+
+ /**
+ * Remove selection from all Blocks then highlight only Current Block
+ */
+ highlightCurrentNode() {
+ /**
+ * Remove previous selected Block's state
+ */
+ this.clearHighlightings();
+
+ /**
+ * Mark current Block as selected
+ * @type {boolean}
+ */
+ this.currentBlock.selected = true;
+ }
+
+ /**
+ * Remove selection from all Blocks
+ */
+ clearHighlightings() {
+ this.blocks.forEach( block => block.selected = false);
+ }
+
+ /**
+ * Get array of Block instances
+ *
+ * @returns {Block[]} {@link Blocks#array}
+ */
+ get blocks() {
+ return this._blocks.array;
+ }
+
+ /**
+ * 1) Find first-level Block from passed child Node
+ * 2) Mark it as current
+ *
+ * @param {Element|Text} childNode - look ahead from this node.
+ * @throws Error - when passed Node is not included at the Block
+ */
+ setCurrentBlockByChildNode(childNode) {
+ /**
+ * If node is Text TextNode
+ */
+ if (!$.isElement(childNode)) {
+ childNode = childNode.parentNode;
+ }
+
+ let parentFirstLevelBlock = childNode.closest(`.${Block.CSS.wrapper}`);
+
+ if (parentFirstLevelBlock) {
+ this.currentNode = parentFirstLevelBlock;
+ this.Editor.Caret.setToInput(childNode);
+ } else {
+ throw new Error('Can not find a Block from this child Node');
+ }
+ }
+
+ /**
+ * Swap Blocks Position
+ * @param {Number} fromIndex
+ * @param {Number} toIndex
+ */
+ swap(fromIndex, toIndex) {
+ /** Move up current Block */
+ this._blocks.swap(fromIndex, toIndex);
+
+ /** Now actual block moved up so that current block index decreased */
+ this.currentBlockIndex = toIndex;
+ }
+
+ /**
+ * Sets current Block Index -1 which means unknown
+ * and clear highlightings
+ */
+ dropPointer() {
+ this.currentBlockIndex = -1;
+ this.clearHighlightings();
+ }
+
+ /**
+ * Clears Editor
+ * @param {boolean} needAddInitialBlock - 1) in internal calls (for example, in api.blocks.render)
+ * we don't need to add empty initial block
+ * 2) in api.blocks.clear we should add empty block
+ */
+ clear(needAddInitialBlock = false) {
+ this._blocks.removeAll();
+ this.dropPointer();
+
+ if (needAddInitialBlock) {
+ this.insert(this.config.initialBlock);
+ }
+ }
+};
+
+/**
+ * @class Blocks
+ * @classdesc Class to work with Block instances array
+ *
+ * @private
+ *
+ * @property {HTMLElement} workingArea — editor`s working node
+ *
+ */
+class Blocks {
+ /**
+ * @constructor
+ *
+ * @param {HTMLElement} workingArea — editor`s working node
+ */
+ constructor(workingArea) {
+ this.blocks = [];
+ this.workingArea = workingArea;
+ }
+
+ /**
+ * Push back new Block
+ *
+ * @param {Block} block
+ */
+ push(block) {
+ this.blocks.push(block);
+ this.workingArea.appendChild(block.holder);
+ }
+
+ /**
+ * Swaps blocks with indexes first and second
+ * @param {Number} first - first block index
+ * @param {Number} second - second block index
+ */
+ swap(first, second) {
+ let secondBlock = this.blocks[second];
+
+ /**
+ * Change in DOM
+ */
+ $.swap(this.blocks[first].holder, secondBlock.holder);
+
+ /**
+ * Change in array
+ */
+ this.blocks[second] = this.blocks[first];
+ this.blocks[first] = secondBlock;
+ }
+
+ /**
+ * Insert new Block at passed index
+ *
+ * @param {Number} index — index to insert Block
+ * @param {Block} block — Block to insert
+ * @param {Boolean} replace — it true, replace block on given index
+ */
+ insert(index, block, replace = false) {
+ if (!this.length) {
+ this.push(block);
+ return;
+ }
+
+ if (index > this.length) {
+ index = this.length;
+ }
+
+ if (replace) {
+ this.blocks[index].holder.remove();
+ }
+
+ let deleteCount = replace ? 1 : 0;
+
+ this.blocks.splice(index, deleteCount, block);
+
+ if (index > 0) {
+ let previousBlock = this.blocks[index - 1];
+
+ previousBlock.holder.insertAdjacentElement('afterend', block.holder);
+ } else {
+ let nextBlock = this.blocks[index + 1];
+
+ if (nextBlock) {
+ nextBlock.holder.insertAdjacentElement('beforebegin', block.holder);
+ } else {
+ this.workingArea.appendChild(block.holder);
+ }
+ }
+ }
+
+ /**
+ * Remove block
+ * @param {Number|null} index
+ */
+ remove(index) {
+ if (isNaN(index)) {
+ index = this.length - 1;
+ }
+
+ this.blocks[index].holder.remove();
+ this.blocks.splice(index, 1);
+ }
+
+ /**
+ * Remove all blocks
+ */
+ removeAll() {
+ this.workingArea.innerHTML = '';
+ this.blocks.length = 0;
+ }
+
+ /**
+ * Insert Block after passed target
+ *
+ * @todo decide if this method is necessary
+ *
+ * @param {Block} targetBlock — target after wich Block should be inserted
+ * @param {Block} newBlock — Block to insert
+ */
+ insertAfter(targetBlock, newBlock) {
+ let index = this.blocks.indexOf(targetBlock);
+
+ this.insert(index + 1, newBlock);
+ }
+
+ /**
+ * Get Block by index
+ *
+ * @param {Number} index — Block index
+ * @returns {Block}
+ */
+ get(index) {
+ return this.blocks[index];
+ }
+
+ /**
+ * Return index of passed Block
+ *
+ * @param {Block} block
+ * @returns {Number}
+ */
+ indexOf(block) {
+ return this.blocks.indexOf(block);
+ }
+
+ /**
+ * Get length of Block instances array
+ *
+ * @returns {Number}
+ */
+ get length() {
+ return this.blocks.length;
+ }
+
+ /**
+ * Get Block instances array
+ *
+ * @returns {Block[]}
+ */
+ get array() {
+ return this.blocks;
+ }
+
+ /**
+ * Get blocks html elements array
+ *
+ * @returns {HTMLElement[]}
+ */
+ get nodes() {
+ return _.array(this.workingArea.children);
+ }
+
+ /**
+ * Proxy trap to implement array-like setter
+ *
+ * @example
+ * blocks[0] = new Block(...)
+ *
+ * @param {Blocks} instance — Blocks instance
+ * @param {Number|String} index — block index
+ * @param {Block} block — Block to set
+ * @returns {Boolean}
+ */
+ static set(instance, index, block) {
+ if (isNaN(Number(index))) {
+ return false;
+ }
+
+ instance.insert(index, block);
+
+ return true;
+ }
+
+ /**
+ * Proxy trap to implement array-like getter
+ *
+ * @param {Blocks} instance — Blocks instance
+ * @param {Number|String} index — Block index
+ * @returns {Block|*}
+ */
+ static get(instance, index) {
+ if (isNaN(Number(index))) {
+ return instance[index];
+ }
+
+ return instance.get(index);
+ }
+}
diff --git a/src/components/modules/caret.js b/src/components/modules/caret.js
new file mode 100644
index 000000000..f0b8b8c5f
--- /dev/null
+++ b/src/components/modules/caret.js
@@ -0,0 +1,469 @@
+/**
+ * @class Caret
+ * @classdesc Contains methods for working Caret
+ *
+ * Uses Range methods to manipulate with caret
+ *
+ * @module Caret
+ *
+ * @version 2.0.0
+ */
+
+import Selection from '../selection';
+
+/**
+ * @typedef {Caret} Caret
+ */
+export default class Caret extends Module {
+ /**
+ * @constructor
+ */
+ constructor({config}) {
+ super({config});
+ }
+
+ /**
+ * Elements styles that can be useful for Caret Module
+ */
+ static get CSS() {
+ return {
+ shadowCaret: 'cdx-shadow-caret'
+ };
+ };
+
+ /**
+ * Allowed caret positions in input
+ *
+ * @static
+ * @returns {{START: string, END: string, DEFAULT: string}}
+ */
+ static get positions() {
+ return {
+ START: 'start',
+ END: 'end',
+ DEFAULT: 'default'
+ };
+ }
+
+ /**
+ * Method gets Block instance and puts caret to the text node with offset
+ * There two ways that method applies caret position:
+ * - first found text node: sets at the beginning, but you can pass an offset
+ * - last found text node: sets at the end of the node. Also, you can customize the behaviour
+ *
+ * @param {Block} block - Block class
+ * @param {String} position - position where to set caret. If default - leave default behaviour and apply offset if it's passed
+ * @param {Number} offset - caret offset regarding to the text node
+ */
+ setToBlock(block, position = Caret.positions.DEFAULT, offset = 0) {
+ const {BlockManager} = this.Editor;
+ let element;
+
+ switch(position) {
+ case Caret.positions.START:
+ element = block.firstInput;
+ break;
+ case Caret.positions.END:
+ element = block.lastInput;
+ break;
+ default:
+ element = block.currentInput;
+ }
+
+ if (!element) {
+ return;
+ }
+
+ const nodeToSet = $.getDeepestNode(element, position === Caret.positions.END);
+ const contentLength = $.getContentLength(nodeToSet);
+
+ switch (true) {
+ case position === Caret.positions.START:
+ offset = 0;
+ break;
+ case position === Caret.positions.END:
+ case offset > contentLength:
+ offset = contentLength;
+ break;
+ }
+
+ /**
+ * @todo try to fix via Promises or use querySelectorAll to not to use timeout
+ */
+ _.delay( () => {
+ this.set(nodeToSet, offset);
+ }, 20)();
+
+ BlockManager.currentNode = block.holder;
+ BlockManager.currentBlock.currentInput = element;
+ }
+
+ /**
+ * Set caret to the current input of current Block.
+ *
+ * @param {HTMLElement} input - input where caret should be set
+ * @param {String} position - position of the caret. If default - leave default behaviour and apply offset if it's passed
+ * @param {number} offset - caret offset regarding to the text node
+ */
+ setToInput(input, position = Caret.positions.DEFAULT, offset = 0) {
+ const {currentBlock} = this.Editor.BlockManager;
+ const nodeToSet = $.getDeepestNode(input);
+
+ switch (position) {
+ case Caret.positions.START:
+ this.set(nodeToSet, 0);
+ break;
+
+ case Caret.positions.END:
+ const contentLength = $.getContentLength(nodeToSet);
+
+ this.set(nodeToSet, contentLength);
+ break;
+
+ default:
+ if (offset) {
+ this.set(nodeToSet, offset);
+ }
+ }
+
+ currentBlock.currentInput = input;
+ }
+
+ /**
+ * Creates Document Range and sets caret to the element with offset
+ * @param {Element} element - target node.
+ * @param {Number} offset - offset
+ */
+ set( element, offset = 0) {
+ const range = document.createRange(),
+ selection = Selection.get();
+
+ /** if found deepest node is native input */
+ if ($.isNativeInput(element)) {
+ element.focus();
+ element.selectionStart = element.selectionEnd = offset;
+ return;
+ }
+
+ range.setStart(element, offset);
+ range.setEnd(element, offset);
+
+ selection.removeAllRanges();
+ selection.addRange(range);
+
+
+ /** If new cursor position is not visible, scroll to it */
+ const {top, bottom} = range.getBoundingClientRect();
+ const {innerHeight} = window;
+
+ if (top < 0) window.scrollBy(0, top);
+ if (bottom > innerHeight) window.scrollBy(0, bottom - innerHeight);
+ };
+
+ /**
+ * Set Caret to the last Block
+ * If last block is not empty, append another empty block
+ */
+ setToTheLastBlock() {
+ let lastBlock = this.Editor.BlockManager.lastBlock;
+
+ if (!lastBlock) return;
+
+ /**
+ * If last block is empty and it is an initialBlock, set to that.
+ * Otherwise, append new empty block and set to that
+ */
+ if (lastBlock.isEmpty) {
+ this.setToBlock(lastBlock);
+ } else {
+ const newBlock = this.Editor.BlockManager.insertAtEnd();
+
+ this.setToBlock(newBlock);
+ }
+ }
+
+ /**
+ * Extract content fragment of current Block from Caret position to the end of the Block
+ */
+ extractFragmentFromCaretPosition() {
+ let selection = Selection.get();
+
+ if (selection.rangeCount) {
+ const selectRange = selection.getRangeAt(0);
+ const currentBlockInput = this.Editor.BlockManager.currentBlock.currentInput;
+
+
+ selectRange.deleteContents();
+
+ if (currentBlockInput) {
+ let range = selectRange.cloneRange(true);
+
+ range.selectNodeContents(currentBlockInput);
+ range.setStart(selectRange.endContainer, selectRange.endOffset);
+ return range.extractContents();
+ }
+ }
+ }
+
+ /**
+ * Get all first-level (first child of [contenteditabel]) siblings from passed node
+ * Then you can check it for emptiness
+ *
+ * @example
+ *
+ * |
+ * | left first-level siblings
+ * |
+ * adaddad <-- passed node for example
+ * |
+ * | right first-level siblings
+ * |
+ *
+ *
+ * @return {Element[]}
+ */
+ getHigherLevelSiblings(from, direction ) {
+ let current = from,
+ siblings = [];
+
+ /**
+ * Find passed node's firs-level parent (in example - blockquote)
+ */
+ while (current.parentNode && current.parentNode.contentEditable !== 'true') {
+ current = current.parentNode;
+ }
+
+ let sibling = direction === 'left' ? 'previousSibling' : 'nextSibling';
+
+ /**
+ * Find all left/right siblings
+ */
+ while (current[sibling]) {
+ current = current[sibling];
+ siblings.push(current);
+ }
+
+ return siblings;
+ }
+
+ /**
+ * Set's caret to the next Block or Tool`s input
+ * Before moving caret, we should check if caret position is at the end of Plugins node
+ * Using {@link Dom#getDeepestNode} to get a last node and match with current selection
+ *
+ * @param {Boolean} force - force navigation even if caret is not at the end
+ *
+ * @return {Boolean}
+ */
+ navigateNext(force = false) {
+ const {currentBlock, nextContentfulBlock} = this.Editor.BlockManager;
+ const {nextInput} = currentBlock;
+
+ if (!nextContentfulBlock && !nextInput) {
+ return false;
+ }
+
+ if (force) {
+ this.setToBlock(nextContentfulBlock, Caret.positions.START);
+ return true;
+ }
+
+ if (this.isAtEnd) {
+ /** If next Tool`s input exists, focus on it. Otherwise set caret to the next Block */
+ if (!nextInput) {
+ this.setToBlock(nextContentfulBlock, Caret.positions.START);
+ } else {
+ this.setToInput(nextInput, Caret.positions.START);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Set's caret to the previous Tool`s input or Block
+ * Before moving caret, we should check if caret position is start of the Plugins node
+ * Using {@link Dom#getDeepestNode} to get a last node and match with current selection
+ *
+ * @param {Boolean} force - force navigation even if caret is not at the start
+ *
+ * @return {Boolean}
+ */
+ navigatePrevious(force = false) {
+ const {currentBlock, previousContentfulBlock} = this.Editor.BlockManager;
+ const {previousInput} = currentBlock || {};
+
+ if (!previousContentfulBlock && !previousInput) {
+ return false;
+ }
+
+ if (force) {
+ this.setToBlock( previousContentfulBlock, Caret.positions.END );
+ }
+
+ if (this.isAtStart) {
+ /** If previous Tool`s input exists, focus on it. Otherwise set caret to the previous Block */
+ if (!previousInput) {
+ this.setToBlock( previousContentfulBlock, Caret.positions.END );
+ } else {
+ this.setToInput(previousInput, Caret.positions.END);
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Get's deepest first node and checks if offset is zero
+ * @return {boolean}
+ */
+ get isAtStart() {
+ /**
+ * Don't handle ranges
+ */
+ if (!Selection.isCollapsed) {
+ return false;
+ }
+
+ let selection = Selection.get(),
+ anchorNode = selection.anchorNode,
+ firstNode = $.getDeepestNode(this.Editor.BlockManager.currentBlock.currentInput);
+
+ /** In case lastNode is native input */
+ if ($.isNativeInput(firstNode)) {
+ return firstNode.selectionEnd === 0;
+ }
+
+ /**
+ * Workaround case when caret in the text like " |Hello!"
+ * selection.anchorOffset is 1, but real caret visible position is 0
+ * @type {number}
+ */
+ let firstLetterPosition = anchorNode.textContent.search(/\S/);
+
+ if (firstLetterPosition === -1) { // empty text
+ firstLetterPosition = 0;
+ }
+
+ /**
+ * In case of
+ *
+ *
<-- first (and deepest) node is
+ * |adaddad <-- anchor node
+ *
+ */
+ if ($.isEmpty(firstNode)) {
+ let leftSiblings = this.getHigherLevelSiblings(anchorNode, 'left'),
+ nothingAtLeft = leftSiblings.every( node => $.isEmpty(node) );
+
+
+
+ if (nothingAtLeft && selection.anchorOffset === firstLetterPosition) {
+ return true;
+ }
+ }
+
+ /**
+ * We use <= comparison for case:
+ * "| Hello" <--- selection.anchorOffset is 0, but firstLetterPosition is 1
+ */
+ return firstNode === null || anchorNode === firstNode && selection.anchorOffset <= firstLetterPosition;
+ }
+
+ /**
+ * Get's deepest last node and checks if offset is last node text length
+ * @return {boolean}
+ */
+ get isAtEnd() {
+ /**
+ * Don't handle ranges
+ */
+ if (!Selection.isCollapsed) {
+ return false;
+ }
+
+ let selection = Selection.get(),
+ anchorNode = selection.anchorNode,
+ lastNode = $.getDeepestNode(this.Editor.BlockManager.currentBlock.currentInput, true);
+
+ /** In case lastNode is native input */
+ if ($.isNativeInput(lastNode)) {
+ return lastNode.selectionEnd === lastNode.value.length;
+ }
+
+ /**
+ * In case of
+ *
+ * adaddad| <-- anchor node
+ *
<-- first (and deepest) node is
+ *
+ */
+ if ($.isEmpty(lastNode)) {
+ let leftSiblings = this.getHigherLevelSiblings(anchorNode, 'right'),
+ nothingAtRight = leftSiblings.every( node => $.isEmpty(node) );
+
+ if (nothingAtRight && selection.anchorOffset === anchorNode.textContent.length) {
+ return true;
+ }
+ }
+
+ /**
+ * Workaround case:
+ * hello | <--- anchorOffset will be 5, but textContent.length will be 6.
+ * Why not regular .trim():
+ * in case of ' hello |' trim() will also remove space at the beginning, so length will be lower than anchorOffset
+ */
+ let rightTrimmedText = lastNode.textContent.replace(/\s+$/, '');
+
+ /**
+ * We use >= comparison for case:
+ * "Hello |" <--- selection.anchorOffset is 7, but rightTrimmedText is 6
+ */
+ return anchorNode === lastNode && selection.anchorOffset >= rightTrimmedText.length;
+ }
+
+ /**
+ * Inserts shadow element after passed element where caret can be placed
+ * @param {Node} element
+ */
+ createShadow(element) {
+ let shadowCaret = document.createElement('span');
+
+ shadowCaret.classList.add(Caret.CSS.shadowCaret);
+ element.insertAdjacentElement('beforeEnd', shadowCaret);
+ }
+
+ /**
+ * Restores caret position
+ * @param {Node} element
+ */
+ restoreCaret(element) {
+ let shadowCaret = element.querySelector(`.${Caret.CSS.shadowCaret}`);
+
+ if (!shadowCaret) {
+ return;
+ }
+
+ /**
+ * After we set the caret to the required place
+ * we need to clear shadow caret
+ *
+ * - make new range
+ * - select shadowed span
+ * - use extractContent to remove it from DOM
+ */
+ let sel = new Selection();
+
+ sel.expandToTag(shadowCaret);
+
+ setTimeout(() => {
+ let newRange = document.createRange();
+
+ newRange.selectNode(shadowCaret);
+ newRange.extractContents();
+ }, 50);
+ }
+}
diff --git a/src/components/modules/events.js b/src/components/modules/events.js
new file mode 100644
index 000000000..5cb422831
--- /dev/null
+++ b/src/components/modules/events.js
@@ -0,0 +1,78 @@
+/**
+ * @module eventDispatcher
+ *
+ * Has two important methods:
+ * - {Function} on - appends subscriber to the event. If event doesn't exist - creates new one
+ * - {Function} emit - fires all subscribers with data
+ * - {Function off - unsubsribes callback
+ *
+ * @version 1.0.0
+ *
+ * @typedef {Events} Events
+ * @property {Object} subscribers - all subscribers grouped by event name
+ */
+export default class Events extends Module {
+ /**
+ * @constructor
+ */
+ constructor({config}) {
+ super({config});
+ this.subscribers = {};
+ }
+
+ /**
+ * Subscribe any event on callback
+ *
+ * @param {String} eventName - event name
+ * @param {Function} callback - subscriber
+ */
+ on(eventName, callback) {
+ if (!(eventName in this.subscribers)) {
+ this.subscribers[eventName] = [];
+ }
+
+ // group by events
+ this.subscribers[eventName].push(callback);
+ }
+
+ /**
+ * Emit callbacks with passed data
+ *
+ * @param {String} eventName - event name
+ * @param {Object} data - subscribers get this data when they were fired
+ */
+ emit(eventName, data) {
+ if (!this.subscribers[eventName]) {
+ return;
+ }
+
+ this.subscribers[eventName].reduce(function (previousData, currentHandler) {
+ let newData = currentHandler(previousData);
+
+ return newData ? newData : previousData;
+ }, data);
+ }
+
+ /**
+ * Unsubsribe callback from event
+ *
+ * @param eventName
+ * @param callback
+ */
+ off(eventName, callback) {
+ for(let i = 0; i < this.subscribers[eventName].length; i++) {
+ if (this.subscribers[eventName][i] === callback) {
+ delete this.subscribers[eventName][i];
+ break;
+ }
+ }
+ }
+
+ /**
+ * Destroyer
+ * clears subsribers list
+ */
+ destroy() {
+ this.subscribers = null;
+ }
+}
diff --git a/src/components/modules/listeners.js b/src/components/modules/listeners.js
new file mode 100644
index 000000000..435d75e57
--- /dev/null
+++ b/src/components/modules/listeners.js
@@ -0,0 +1,174 @@
+/**
+ * Codex Editor Listeners module
+ *
+ * @module Listeners
+ *
+ * Module-decorator for event listeners assignment
+ *
+ * @author Codex Team
+ * @version 2.0.0
+ */
+
+/**
+ * @typedef {Listeners} Listeners
+ * @property {Array} allListeners
+ */
+export default class Listeners extends Module {
+ /**
+ * @constructor
+ * @param {EditorConfig} config
+ */
+ constructor({config}) {
+ super({config});
+ this.allListeners = [];
+ }
+
+ /**
+ * Assigns event listener on element
+ *
+ * @param {Element} element - DOM element that needs to be listened
+ * @param {String} eventType - event type
+ * @param {Function} handler - method that will be fired on event
+ * @param {Boolean} useCapture - use event bubbling
+ */
+ on(element, eventType, handler, useCapture = false) {
+ let assignedEventData = {
+ element,
+ eventType,
+ handler,
+ useCapture
+ };
+
+ let alreadyExist = this.findOne(element, eventType, handler);
+
+ if (alreadyExist) return;
+
+ this.allListeners.push(assignedEventData);
+ element.addEventListener(eventType, handler, useCapture);
+ }
+
+ /**
+ * Removes event listener from element
+ *
+ * @param {Element} element - DOM element that we removing listener
+ * @param {String} eventType - event type
+ * @param {Function} handler - remove handler, if element listens several handlers on the same event type
+ * @param {Boolean} useCapture - use event bubbling
+ */
+ off(element, eventType, handler, useCapture = false) {
+ let existingListeners = this.findAll(element, eventType, handler);
+
+ for (let i = 0; i < existingListeners.length; i++) {
+ let index = this.allListeners.indexOf(existingListeners[i]);
+
+ if (index > 0) {
+ this.allListeners.splice(index, 1);
+ }
+ }
+
+ element.removeEventListener(eventType, handler, useCapture);
+ }
+
+ /**
+ * Search method: looks for listener by passed element
+ * @param {Element} element - searching element
+ * @returns {Array} listeners that found on element
+ */
+ findByElement(element) {
+ let listenersOnElement = [];
+
+ for (let i = 0; i < this.allListeners.length; i++) {
+ let listener = this.allListeners[i];
+
+ if (listener.element === element) {
+ listenersOnElement.push(listener);
+ }
+ }
+
+ return listenersOnElement;
+ }
+
+ /**
+ * Search method: looks for listener by passed event type
+ * @param {String} eventType
+ * @return {Array} listeners that found on element
+ */
+ findByType(eventType) {
+ let listenersWithType = [];
+
+ for (let i = 0; i < this.allListeners.length; i++) {
+ let listener = this.allListeners[i];
+
+ if (listener.type === eventType) {
+ listenersWithType.push(listener);
+ }
+ }
+
+ return listenersWithType;
+ }
+
+ /**
+ * Search method: looks for listener by passed handler
+ * @param {Function} handler
+ * @return {Array} listeners that found on element
+ */
+ findByHandler(handler) {
+ let listenersWithHandler = [];
+
+ for (let i = 0; i < this.allListeners.length; i++) {
+ let listener = this.allListeners[i];
+
+ if (listener.handler === handler) {
+ listenersWithHandler.push(listener);
+ }
+ }
+
+ return listenersWithHandler;
+ }
+
+ /**
+ * @param {Element} element
+ * @param {String} eventType
+ * @param {Function} handler
+ * @return {Element|null}
+ */
+ findOne(element, eventType, handler) {
+ let foundListeners = this.findAll(element, eventType, handler);
+
+ return foundListeners.length > 0 ? foundListeners[0] : null;
+ }
+
+ /**
+ * @param {Element} element
+ * @param {String} eventType
+ * @param {Function} handler
+ * @return {Array}
+ */
+ findAll(element, eventType, handler) {
+ let found,
+ foundByElements = element ? this.findByElement(element) : [];
+ // foundByEventType = eventType ? this.findByType(eventType) : [],
+ // foundByHandler = handler ? this.findByHandler(handler) : [];
+
+ if (element && eventType && handler) {
+ found = foundByElements.filter( event => event.eventType === eventType && event.handler === handler );
+ } else if (element && eventType) {
+ found = foundByElements.filter( event => event.eventType === eventType);
+ } else {
+ found = foundByElements;
+ }
+
+ return found;
+ }
+
+ /**
+ * Removes all listeners
+ */
+ removeAll() {
+ this.allListeners.map( (current) => {
+ current.element.removeEventListener(current.eventType, current.handler);
+ });
+
+ this.allListeners = [];
+ }
+}
diff --git a/src/components/modules/paste.ts b/src/components/modules/paste.ts
new file mode 100644
index 000000000..2e51ce93d
--- /dev/null
+++ b/src/components/modules/paste.ts
@@ -0,0 +1,490 @@
+import IBlockToolData from '../interfaces/tools/block-tool';
+import IEditorConfig from '../interfaces/editor-config';
+import CaretClass from './caret';
+
+declare const Module: any;
+declare const $: any;
+declare const _: any;
+
+/**
+ * Tag substitute object.
+ *
+ * @param {string} tool - name of related Tool
+ * @param {Function} handler - callback to handle pasted element
+ */
+interface ITagSubstitute {
+ tool: string;
+ handler: (element: HTMLElement) => IBlockToolData;
+}
+
+/**
+ * Pattern substitute object.
+ *
+ * @param {string} key - pattern`s key
+ * @param {RegExp} pattern - pasted pattern
+ * @param {Function} handler - callback to handle pasted pattern
+ * @param {string} tool - name of related Tool
+ */
+interface IPatternSubstitute {
+ key: string;
+ pattern: RegExp;
+ handler: (text: string, key: string) => IBlockToolData;
+ tool: string;
+}
+
+/**
+ * Processed paste data object.
+ *
+ * @param {string} tool - name of related Tool
+ * @param {HTMLElement} content - processed pasted content
+ * @param {boolean} isBlock - true if content should be inserted as new Block
+ * @param {Function} handler - callback that returns pasted data in IBlockToolData format
+ */
+interface IPasteData {
+ tool: string;
+ content: HTMLElement;
+ isBlock: boolean;
+ handler: (content: HTMLElement|string, patten?: RegExp) => IBlockToolData;
+}
+/**
+ * @class Paste
+ * @classdesc Contains methods to handle paste on editor
+ *
+ * @module Paste
+ *
+ * @version 2.0.0
+ */
+export default class Paste extends Module {
+
+ /** If string`s length is greater than this number we don't check paste patterns */
+ public static readonly PATTERN_PROCESSING_MAX_LENGTH = 450;
+
+ /**
+ * Tags` substitutions parameters
+ */
+ private toolsTags: {[tag: string]: ITagSubstitute} = {};
+
+ /** Patterns` substitutions parameters */
+ private toolsPatterns: IPatternSubstitute[] = [];
+
+ /**
+ * @constructor
+ * @param {IEditorConfig} config
+ */
+ constructor({config}) {
+ super({config});
+ }
+
+ public async prepare(): Promise {
+ this.setCallback();
+ this.processTools();
+ }
+
+ /**
+ * Set onPaste callback handler
+ */
+ private setCallback(): void {
+ const {Listeners, UI} = this.Editor;
+
+ Listeners.on(UI.nodes.redactor, 'paste', this.processPastedData);
+ }
+
+ /**
+ * Get and process tool`s paste configs
+ */
+ private processTools(): void {
+ const tools = this.Editor.Tools.blockTools;
+
+ Object.entries(tools).forEach(this.processTool);
+ }
+
+ /**
+ * Process paste config for each tools
+ *
+ * @param {string} tool
+ */
+ private processTool = ([name, tool]) => {
+ const toolPasteConfig = tool.onPaste || {};
+
+ if (this.config.initialBlock === name && !toolPasteConfig.handler) {
+ _.log(
+ `«${name}» Tool must provide a paste handler.`,
+ 'warn',
+ );
+ }
+
+ if (toolPasteConfig.handler && typeof toolPasteConfig.handler !== 'function') {
+ _.log(
+ `Paste handler for «${name}» Tool should be a function.`,
+ 'warn',
+ );
+ } else {
+ const tags = toolPasteConfig.tags || [];
+
+ tags.forEach((tag) => {
+ if (this.toolsTags.hasOwnProperty(tag)) {
+ _.log(
+ `Paste handler for «${name}» Tool on «${tag}» tag is skipped ` +
+ `because it is already used by «${this.toolsTags[tag].tool}» Tool.`,
+ 'warn',
+ );
+ return;
+ }
+
+ this.toolsTags[tag] = {
+ handler: toolPasteConfig.handler,
+ tool: name,
+ };
+ });
+ }
+
+ if (!toolPasteConfig.patternHandler || _.isEmpty(toolPasteConfig.patterns)) {
+ return;
+ }
+
+ if (typeof toolPasteConfig.patternHandler !== 'function') {
+ _.log(
+ `Pattern parser for "${name}" Tool should be a function.`,
+ 'warn',
+ );
+ } else {
+ Object.entries(toolPasteConfig.patterns).forEach(([key, pattern]: [string, RegExp]) => {
+ /** Still need to validate pattern as it provided by user */
+ if (!(pattern instanceof RegExp)) {
+ _.log(
+ `Pattern ${pattern} for "${tool}" Tool is skipped because it should be a Regexp instance.`,
+ 'warn',
+ );
+ }
+
+ this.toolsPatterns.push({
+ key,
+ pattern,
+ handler: toolPasteConfig.patternHandler,
+ tool: name,
+ });
+ });
+ }
+ }
+
+ /**
+ * Check if browser behavior suits better
+ *
+ * @param {EventTarget} element - element where content has been pasted
+ * @returns {boolean}
+ */
+ private isNativeBehaviour(element: EventTarget): boolean {
+ const {Editor: {BlockManager}} = this;
+
+ if ( $.isNativeInput(element) ) {
+ return true;
+ }
+
+ const block = BlockManager.getBlock(element);
+
+ return !block;
+ }
+
+ /**
+ * Get pasted data, process it and insert into editor
+ *
+ * @param {ClipboardEvent} event
+ */
+ private processPastedData = async (event: ClipboardEvent): Promise => {
+ const {
+ Editor: {Tools, Sanitizer, BlockManager, Caret},
+ } = this;
+
+ /** If target is native input or is not Block, use browser behaviour */
+ if (this.isNativeBehaviour(event.target)) {
+ return;
+ }
+
+ event.preventDefault();
+
+ const htmlData = event.clipboardData.getData('text/html'),
+ plainData = event.clipboardData.getData('text/plain');
+
+ /** Add all tags that can be substituted to sanitizer configuration */
+ const toolsTags = Object.keys(this.toolsTags).reduce((result, tag) => {
+ result[tag.toLowerCase()] = {};
+
+ return result;
+ }, {});
+
+ const customConfig = {tags: Object.assign({}, toolsTags, Sanitizer.defaultConfig.tags)};
+ const cleanData = Sanitizer.clean(htmlData, customConfig);
+
+ let dataToInsert = [];
+
+ /** If there is no HTML or HTML string is equal to plain one, process it as plain text */
+ if (!cleanData.trim() || cleanData.trim() === plainData || !$.isHTMLString(cleanData)) {
+ dataToInsert = this.processPlain(plainData);
+ } else {
+ dataToInsert = this.processHTML(htmlData);
+ }
+
+ if (dataToInsert.length === 1 && !dataToInsert[0].isBlock) {
+ this.processSingleBlock(dataToInsert.pop());
+ return;
+ }
+
+ this.splitBlock();
+
+ await Promise.all(dataToInsert.map(
+ async (data, i) => await this.insertBlock(data, i === 0),
+ ));
+
+ Caret.setToBlock(BlockManager.currentBlock, CaretClass.positions.END);
+ }
+
+ /**
+ * Process paste to single Block:
+ * 1. Find patterns` matches
+ * 2. Insert new block if it is not the same type as current one
+ * 3. Just insert text if there is no substitutions
+ *
+ * @param {IPasteData} dataToInsert
+ */
+ private async processSingleBlock(dataToInsert: IPasteData): Promise {
+ const initialTool = this.config.initialBlock,
+ {BlockManager, Caret} = this.Editor,
+ {content, tool} = dataToInsert;
+
+ if (tool === initialTool && content.textContent.length < Paste.PATTERN_PROCESSING_MAX_LENGTH) {
+ const blockData = await this.processPattern(content.textContent);
+
+ if (blockData) {
+ this.splitBlock();
+ let insertedBlock;
+
+ if (BlockManager.currentBlock && BlockManager.currentBlock.isEmpty) {
+ BlockManager.replace(blockData.tool, blockData.data);
+ } else {
+ insertedBlock = BlockManager.insert(blockData.tool, blockData.data);
+ }
+ Caret.setToBlock(insertedBlock, CaretClass.positions.END);
+ return;
+ }
+ }
+
+ /** If there is no pattern substitute - insert string as it is */
+ document.execCommand('insertHTML', false, content.innerHTML);
+ }
+
+ /**
+ * Get patterns` matches
+ *
+ * @param {string} text
+ * @returns Promise<{data: IBlockToolData, tool: string}>
+ */
+ private async processPattern(text: string): Promise<{data: IBlockToolData, tool: string}> {
+ const pattern = this.toolsPatterns.find((substitute) => {
+ const execResult = substitute.pattern.exec(text);
+
+ if (!execResult) {
+ return false;
+ }
+
+ return text === execResult.shift();
+ });
+
+ const data = pattern && await pattern.handler(text, pattern.key);
+
+ return data && {
+ data,
+ tool: pattern.tool,
+ };
+ }
+
+ /**
+ *
+ * @param {IPasteData} data
+ * @param {Boolean} canReplaceCurrentBlock - if true and is current Block is empty, will replace current Block
+ * @returns {Promise}
+ */
+ private async insertBlock(data: IPasteData, canReplaceCurrentBlock: boolean = false): Promise {
+ const blockData = await data.handler(data.content),
+ {BlockManager, Caret} = this.Editor,
+ {currentBlock} = BlockManager;
+
+ if (canReplaceCurrentBlock && currentBlock && currentBlock.isEmpty) {
+ BlockManager.replace(data.tool, blockData);
+ return;
+ }
+
+ const Block = BlockManager.insert(data.tool, blockData);
+
+ Caret.setToBlock(Block);
+ }
+
+ /**
+ * Split current block if paste isn't in the end of the block
+ */
+ private splitBlock() {
+ const {BlockManager, Caret} = this.Editor;
+
+ if (!BlockManager.currentBlock) {
+ return;
+ }
+
+ /** If we paste into middle of the current block:
+ * 1. Split
+ * 2. Navigate to the first part
+ */
+ if (!BlockManager.currentBlock.isEmpty && !Caret.isAtEnd) {
+ BlockManager.split();
+ BlockManager.currentBlockIndex--;
+ }
+ }
+
+ /**
+ * Split HTML string to blocks and return it as array of Block data
+ *
+ * @param {string} innerHTML
+ * @returns {IPasteData[]}
+ */
+ private processHTML(innerHTML: string): IPasteData[] {
+ const {Tools, Sanitizer} = this.Editor,
+ initialTool = this.config.initialBlock,
+ wrapper = $.make('DIV');
+
+ wrapper.innerHTML = innerHTML;
+
+ const nodes = this.getNodes(wrapper);
+
+ return nodes
+ .map((node) => {
+ let content, tool = initialTool, isBlock = false;
+
+ switch (node.nodeType) {
+ /** If node is a document fragment, use temp wrapper to get innerHTML */
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ content = $.make('div');
+ content.appendChild(node);
+ break;
+
+ /** If node is an element, then there might be a substitution */
+ case Node.ELEMENT_NODE:
+ content = node as HTMLElement;
+ isBlock = true;
+
+ if (this.toolsTags[content.tagName]) {
+ tool = this.toolsTags[content.tagName].tool;
+ }
+ break;
+ }
+
+ const {handler, tags} = Tools.blockTools[tool].onPaste;
+
+ const toolTags = tags.reduce((result, tag) => {
+ result[tag.toLowerCase()] = {};
+
+ return result;
+ }, {});
+ const customConfig = {tags: Object.assign({}, toolTags, Sanitizer.defaultConfig.tags)};
+
+ content.innerHTML = Sanitizer.clean(content.innerHTML, customConfig);
+
+ return {content, isBlock, handler, tool};
+ })
+ .filter((data) => !$.isNodeEmpty(data.content));
+ }
+
+ /**
+ * Split plain text by new line symbols and return it as array of Block data
+ *
+ * @param {string} plain
+ * @returns {IPasteData[]}
+ */
+ private processPlain(plain: string): IPasteData[] {
+ const {initialBlock} = this.config as {initialBlock: string},
+ {Tools} = this.Editor;
+
+ if (!plain) {
+ return [];
+ }
+
+ const tool = initialBlock,
+ handler = Tools.blockTools[tool].onPaste.handler;
+
+ return plain.split('\n\n').map((text) => {
+ const content = $.make('div');
+
+ content.innerHTML = text;
+
+ return {content, tool, isBlock: false, handler};
+ });
+ }
+
+ /**
+ * Recursively divide HTML string to two types of nodes:
+ * 1. Block element
+ * 2. Document Fragments contained text and markup tags like a, b, i etc.
+ *
+ * @param {Node} wrapper
+ * @returns {Node[]}
+ */
+ private getNodes(wrapper: Node): Node[] {
+ const children = Array.from(wrapper.childNodes),
+ tags = Object.keys(this.toolsTags);
+
+ const reducer = (nodes: Node[], node: Node): Node[] => {
+ if ($.isEmpty(node)) {
+ return nodes;
+ }
+
+ const lastNode = nodes[nodes.length - 1];
+
+ let destNode: Node = new DocumentFragment();
+
+ if (lastNode && $.isFragment(lastNode)) {
+ destNode = nodes.pop();
+ }
+
+ switch (node.nodeType) {
+ /**
+ * If node is HTML element:
+ * 1. Check if it is inline element
+ * 2. Check if it contains another block or substitutable elements
+ */
+ case Node.ELEMENT_NODE:
+ const element = node as HTMLElement;
+
+ /** Append inline elements to previous fragment */
+ if (
+ !$.blockElements.includes(element.tagName.toLowerCase()) &&
+ !tags.includes(element.tagName)
+ ) {
+ destNode.appendChild(element);
+ return [...nodes, destNode];
+ }
+
+ if (tags.includes(element.tagName) || (
+ $.blockElements.includes(element.tagName.toLowerCase()) &&
+ Array.from(element.children).every(
+ ({tagName}) => !$.blockElements.includes(tagName.toLowerCase()),
+ )
+ )
+ ) {
+ return [...nodes, element];
+ }
+ break;
+
+ /**
+ * If node is text node, wrap it with DocumentFragment
+ */
+ case Node.TEXT_NODE:
+ destNode.appendChild(node);
+ return [...nodes, destNode];
+
+ default:
+ return [...nodes, destNode];
+ }
+
+ return [...nodes, ...Array.from(node.childNodes).reduce(reducer, [])];
+ };
+
+ return children.reduce(reducer, []);
+ }
+}
diff --git a/src/components/modules/renderer.js b/src/components/modules/renderer.js
new file mode 100644
index 000000000..81f7a809e
--- /dev/null
+++ b/src/components/modules/renderer.js
@@ -0,0 +1,92 @@
+/**
+ * Codex Editor Renderer Module
+ *
+ * @module Renderer
+ * @author CodeX Team
+ *
+ * @version 2.0.0
+ */
+export default class Renderer extends Module {
+ /**
+ * @constructor
+ * @param {EditorConfig} config
+ */
+ constructor({config}) {
+ super({config});
+ }
+
+ /**
+ * @typedef {Object} RendererBlocks
+ * @property {String} type - tool name
+ * @property {Object} data - tool data
+ */
+
+ /**
+ * @example
+ *
+ * blocks: [
+ * {
+ * type : 'paragraph',
+ * data : {
+ * text : 'Hello from Codex!'
+ * }
+ * },
+ * {
+ * type : 'paragraph',
+ * data : {
+ * text : 'Leave feedback if you like it!'
+ * }
+ * },
+ * ]
+ *
+ */
+
+ /**
+ * Make plugin blocks from array of plugin`s data
+ * @param {RendererBlocks[]} blocks
+ */
+ render(blocks) {
+ let chainData = [];
+
+ for (let i = 0; i < blocks.length; i++) {
+ chainData.push({
+ function: () => this.insertBlock(blocks[i])
+ });
+ }
+
+ return _.sequence(chainData);
+ }
+
+ /**
+ * Get plugin instance
+ * Add plugin instance to BlockManager
+ * Insert block to working zone
+ *
+ * @param {Object} item
+ * @returns {Promise.}
+ * @private
+ */
+ insertBlock(item) {
+ let tool = item.type,
+ data = item.data,
+ settings = item.settings;
+
+ if (tool in this.Editor.Tools.available) {
+ try {
+ this.Editor.BlockManager.insert(tool, data, settings);
+ } catch (error) {
+ _.log(`Block «${tool}» skipped because of plugins error`, 'warn', data);
+ Promise.reject(error);
+ }
+ } else {
+ /**
+ * @todo show warning notification message
+ *
+ * `${tool} blocks was skipped.`
+ */
+ _.log(`Tool «${tool}» is not found. Check 'tools' property at your initial CodeX Editor config.`, 'warn');
+ }
+
+ return Promise.resolve();
+ }
+}
diff --git a/src/components/modules/sanitizer.js b/src/components/modules/sanitizer.js
new file mode 100644
index 000000000..b0cb51d67
--- /dev/null
+++ b/src/components/modules/sanitizer.js
@@ -0,0 +1,131 @@
+/**
+ * CodeX Sanitizer
+ *
+ * @module Sanitizer
+ * Clears HTML from taint tags
+ *
+ * @version 2.0.0
+ *
+ * @example
+ * Module can be used within two ways:
+ * 1) When you have an instance
+ * - this.Editor.Sanitizer.clean(yourTaintString);
+ * 2) As static method
+ * - CodexEditor.Sanitizer.clean(yourTaintString, yourCustomConfiguration);
+ *
+ * {@link SanitizerConfig}
+ */
+
+
+/**
+ * @typedef {Object} SanitizerConfig
+ * @property {Object} tags - define tags restrictions
+ *
+ * @example
+ *
+ * tags : {
+ * p: true,
+ * a: {
+ * href: true,
+ * rel: "nofollow",
+ * target: "_blank"
+ * }
+ * }
+ */
+export default class Sanitizer extends Module {
+ /**
+ * Initializes Sanitizer module
+ * Sets default configuration if custom not exists
+ *
+ * @property {SanitizerConfig} this.defaultConfig
+ * @property {HTMLJanitor} this._sanitizerInstance - Sanitizer library
+ *
+ * @param {SanitizerConfig} config
+ */
+ constructor({config}) {
+ super({config});
+
+ // default config
+ this.defaultConfig = null;
+ this._sanitizerInstance = null;
+
+ /** Custom configuration */
+ this.sanitizerConfig = config.settings ? config.settings.sanitizer : {};
+
+ /** HTML Janitor library */
+ this.sanitizerInstance = require('html-janitor');
+ }
+
+ /**
+ * If developer uses editor's API, then he can customize sanitize restrictions.
+ * Or, sanitizing config can be defined globally in editors initialization. That config will be used everywhere
+ * At least, if there is no config overrides, that API uses Default configuration
+ *
+ * @uses https://www.npmjs.com/package/html-janitor
+ *
+ * @param {HTMLJanitor} library - sanitizer extension
+ */
+ set sanitizerInstance(library) {
+ this._sanitizerInstance = new library(this.defaultConfig);
+ }
+
+ /**
+ * Sets sanitizer configuration. Uses default config if user didn't pass the restriction
+ * @param {SanitizerConfig} config
+ */
+ set sanitizerConfig(config) {
+ if (_.isEmpty(config)) {
+ this.defaultConfig = {
+ tags: {
+ p: {},
+ a: {
+ href: true,
+ target: '_blank',
+ rel: 'nofollow'
+ },
+ b: {},
+ i: {}
+ }
+ };
+ } else {
+ this.defaultConfig = config;
+ }
+ }
+
+ /**
+ * Cleans string from unwanted tags
+ * @param {String} taintString - HTML string
+ * @param {Object} customConfig - custom sanitizer configuration. Method uses default if param is empty
+ * @return {String} clean HTML
+ */
+ clean(taintString, customConfig = {}) {
+ if (_.isEmpty(customConfig)) {
+ return this._sanitizerInstance.clean(taintString);
+ } else {
+ return Sanitizer.clean(taintString, customConfig);
+ }
+ }
+
+ /**
+ * Cleans string from unwanted tags
+ * @static
+ *
+ * Method allows to use default config
+ *
+ * @param {String} taintString - taint string
+ * @param {SanitizerConfig} customConfig - allowed tags
+ *
+ * @return {String} clean HTML
+ */
+ static clean(taintString, customConfig) {
+ let newInstance = new Sanitizer({
+ config: {
+ settings: {
+ sanitizer: customConfig
+ }
+ }
+ });
+
+ return newInstance.clean(taintString);
+ }
+}
diff --git a/src/components/modules/saver.js b/src/components/modules/saver.js
new file mode 100644
index 000000000..c0e007e05
--- /dev/null
+++ b/src/components/modules/saver.js
@@ -0,0 +1,243 @@
+/**
+ * Codex Editor Saver
+ *
+ * @module Saver
+ * @author Codex Team
+ * @version 2.0.0
+ */
+
+/**
+ * @typedef {Object} SavedData
+ * @property {Date} time - saving proccess time
+ * @property {Object} items - extracted data
+ * @property {String} version - CodexEditor version
+ */
+
+/**
+ * @classdesc This method reduces all Blocks asyncronically and calls Block's save method to extract data
+ *
+ * @typedef {Saver} Saver
+ * @property {Element} html - Editor HTML content
+ * @property {String} json - Editor JSON output
+ */
+export default class Saver extends Module {
+ /**
+ * @constructor
+ * @param config
+ */
+ constructor({config}) {
+ super({config});
+
+ this.output = null;
+ this.blocksData = [];
+ }
+
+ /**
+ * Composes new chain of Promises to fire them alternatelly
+ * @return {SavedData}
+ */
+ save() {
+ let blocks = this.Editor.BlockManager.blocks,
+ chainData = [];
+
+ blocks.forEach((block) => {
+ chainData.push(block.data);
+ });
+
+ return Promise.all(chainData)
+ .then((allExtractedData) => this.makeOutput(allExtractedData))
+ .then((outputData) => {
+ return outputData;
+ });
+ }
+
+ /**
+ * Creates output object with saved data, time and version of editor
+ * @param {Object} allExtractedData
+ * @return {SavedData}
+ */
+ makeOutput(allExtractedData) {
+ let blocks = [],
+ totalTime = 0;
+
+ console.groupCollapsed('[CodexEditor saving]:');
+
+ allExtractedData.forEach((extraction) => {
+ /** Group process info */
+ console.log(`«${extraction.tool}» saving info`, extraction);
+ totalTime += extraction.time;
+ blocks.push({
+ type: extraction.tool,
+ data: extraction.data
+ });
+ });
+
+ console.log('Total', totalTime);
+ console.groupEnd();
+
+ return {
+ time: +new Date(),
+ blocks: blocks,
+ version: VERSION,
+ };
+ }
+}
+
+// module.exports = (function (saver) {
+//
+// let editor = codex.editor;
+//
+// /**
+// * @public
+// * Save blocks
+// */
+// saver.save = function () {
+//
+// /** Save html content of redactor to memory */
+// editor.state.html = editor.nodes.redactor.innerHTML;
+//
+// /** Clean jsonOutput state */
+// editor.state.jsonOutput = [];
+//
+// return saveBlocks(editor.nodes.redactor.childNodes);
+//
+// };
+//
+// /**
+// * @private
+// * Save each block data
+// *
+// * @param blocks
+// * @returns {Promise.}
+// */
+// let saveBlocks = function (blocks) {
+//
+// let data = [];
+//
+// for(let index = 0; index < blocks.length; index++) {
+//
+// data.push(getBlockData(blocks[index]));
+//
+// }
+//
+// return Promise.all(data)
+// .then(makeOutput)
+// .catch(editor.core.log);
+//
+// };
+//
+// /** Save and validate block data */
+// let getBlockData = function (block) {
+//
+// return saveBlockData(block)
+// .then(validateBlockData)
+// .catch(editor.core.log);
+//
+// };
+//
+// /**
+// * @private
+// * Call block`s plugin save method and return saved data
+// *
+// * @param block
+// * @returns {Object}
+// */
+// let saveBlockData = function (block) {
+//
+// let pluginName = block.dataset.tool;
+//
+// /** Check for plugin existence */
+// if (!editor.tools[pluginName]) {
+//
+// editor.core.log(`Plugin «${pluginName}» not found`, 'error');
+// return {data: null, pluginName: null};
+//
+// }
+//
+// /** Check for plugin having save method */
+// if (typeof editor.tools[pluginName].save !== 'function') {
+//
+// editor.core.log(`Plugin «${pluginName}» must have save method`, 'error');
+// return {data: null, pluginName: null};
+//
+// }
+//
+// /** Result saver */
+// let blockContent = block.childNodes[0],
+// pluginsContent = blockContent.childNodes[0],
+// position = pluginsContent.dataset.inputPosition;
+//
+// /** If plugin wasn't available then return data from cache */
+// if ( editor.tools[pluginName].available === false ) {
+//
+// return Promise.resolve({data: codex.editor.state.blocks.items[position].data, pluginName});
+//
+// }
+//
+// return Promise.resolve(pluginsContent)
+// .then(editor.tools[pluginName].save)
+// .then(data => Object({data, pluginName}));
+//
+// };
+//
+// /**
+// * Call plugin`s validate method. Return false if validation failed
+// *
+// * @param data
+// * @param pluginName
+// * @returns {Object|Boolean}
+// */
+// let validateBlockData = function ({data, pluginName}) {
+//
+// if (!data || !pluginName) {
+//
+// return false;
+//
+// }
+//
+// if (editor.tools[pluginName].validate) {
+//
+// let result = editor.tools[pluginName].validate(data);
+//
+// /**
+// * Do not allow invalid data
+// */
+// if (!result) {
+//
+// return false;
+//
+// }
+//
+// }
+//
+// return {data, pluginName};
+//
+//
+// };
+//
+// /**
+// * Compile article output
+// *
+// * @param savedData
+// * @returns {{time: number, version, items: (*|Array)}}
+// */
+// let makeOutput = function (savedData) {
+//
+// savedData = savedData.filter(blockData => blockData);
+//
+// let items = savedData.map(blockData => Object({type: blockData.pluginName, data: blockData.data}));
+//
+// editor.state.jsonOutput = items;
+//
+// return {
+// id: editor.state.blocks.id || null,
+// time: +new Date(),
+// version: editor.version,
+// items
+// };
+//
+// };
+//
+// return saver;
+//
+// })({});
diff --git a/src/components/modules/shortcuts.ts b/src/components/modules/shortcuts.ts
new file mode 100644
index 000000000..5be9520a6
--- /dev/null
+++ b/src/components/modules/shortcuts.ts
@@ -0,0 +1,54 @@
+
+import Shortcut from '@codexteam/shortcuts';
+import {IShortcut, IShortcuts} from '../interfaces/shortcuts';
+import IEditorConfig from '../interfaces/editor-config';
+
+/**
+ * Contains keyboard and mouse events binded on each Block by Block Manager
+ */
+declare var Module: any;
+
+/**
+ * @class Shortcut
+ * @classdesc Allows to register new shortcut
+ *
+ * Internal Shortcuts Module
+ */
+export default class Shortcuts extends Module implements IShortcuts {
+ /**
+ * All registered shortcuts
+ * @type {IShortcut[]}
+ */
+ private registeredShortcuts: IShortcut[];
+
+ /**
+ * @constructor
+ * @param {IEditorConfig} config
+ */
+ constructor({config}) {
+ super({config});
+ this.registeredShortcuts = [];
+ }
+
+ /**
+ * Register shortcut
+ * @param {IShortcut} shortcut
+ */
+ public add(shortcut: IShortcut): void {
+ const newShortcut = new Shortcut({
+ name: shortcut.name,
+ on: document,
+ callback: shortcut.handler,
+ });
+
+ this.registeredShortcuts.push(newShortcut);
+ }
+
+ /**
+ * Remove shortcut
+ * @param {IShortcut} shortcut
+ */
+ public remove(shortcut: string): void {
+ // Remove
+ }
+}
diff --git a/src/components/modules/toolbar-blockSettings.js b/src/components/modules/toolbar-blockSettings.js
new file mode 100644
index 000000000..e57163d8a
--- /dev/null
+++ b/src/components/modules/toolbar-blockSettings.js
@@ -0,0 +1,126 @@
+/**
+ * Block Settings
+ *
+ * ____ Settings Panel ____
+ * | ...................... |
+ * | . Tool Settings . |
+ * | ...................... |
+ * | . Default Settings . |
+ * | ...................... |
+ * |________________________|
+ */
+export default class BlockSettings extends Module {
+ /**
+ * @constructor
+ */
+ constructor({config}) {
+ super({config});
+
+ this.nodes = {
+ wrapper: null,
+ toolSettings: null,
+ defaultSettings: null
+ };
+ }
+
+ /**
+ * Module Events
+ * @return {{opened: string, closed: string}}
+ */
+ get events() {
+ return {
+ opened: 'block-settings-opened',
+ closed: 'block-settings-closed',
+ };
+ }
+
+ /**
+ * Block Settings CSS
+ * @return {{wrapper, wrapperOpened, toolSettings, defaultSettings, button}}
+ */
+ static get CSS() {
+ return {
+ // Settings Panel
+ wrapper: 'ce-settings',
+ wrapperOpened: 'ce-settings--opened',
+ toolSettings: 'ce-settings__plugin-zone',
+ defaultSettings: 'ce-settings__default-zone',
+
+ button: 'ce-settings__button'
+ };
+ }
+
+ /**
+ * Panel with block settings with 2 sections:
+ * - Tool's Settings
+ * - Default Settings [Move, Remove, etc]
+ *
+ * @return {Element}
+ */
+ make() {
+ this.nodes.wrapper = $.make('div', BlockSettings.CSS.wrapper);
+
+ this.nodes.toolSettings = $.make('div', BlockSettings.CSS.toolSettings);
+ this.nodes.defaultSettings = $.make('div', BlockSettings.CSS.defaultSettings);
+
+ $.append(this.nodes.wrapper, [this.nodes.toolSettings, this.nodes.defaultSettings]);
+ }
+
+ /**
+ * Add Tool's settings
+ */
+ addToolSettings() {
+ if (typeof this.Editor.BlockManager.currentBlock.tool.renderSettings === 'function') {
+ $.append(this.nodes.toolSettings, this.Editor.BlockManager.currentBlock.tool.renderSettings());
+ }
+ }
+
+ /**
+ * Add default settings
+ */
+ addDefaultSettings() {
+ $.append(this.nodes.defaultSettings, this.Editor.BlockManager.currentBlock.renderTunes());
+ }
+
+ /**
+ * Is Block Settings opened or not
+ * @returns {boolean}
+ */
+ get opened() {
+ return this.nodes.wrapper.classList.contains(BlockSettings.CSS.wrapperOpened);
+ }
+
+ /**
+ * Open Block Settings pane
+ */
+ open() {
+ this.nodes.wrapper.classList.add(BlockSettings.CSS.wrapperOpened);
+
+ /**
+ * Fill Tool's settings
+ */
+ this.addToolSettings();
+
+ /**
+ * Add default settings that presents for all Blocks
+ */
+ this.addDefaultSettings();
+
+ /** Tell to subscribers that block settings is opened */
+ this.Editor.Events.emit(this.events.opened);
+ }
+
+ /**
+ * Close Block Settings pane
+ */
+ close() {
+ this.nodes.wrapper.classList.remove(BlockSettings.CSS.wrapperOpened);
+
+ /** Clear settings */
+ this.nodes.toolSettings.innerHTML = '';
+ this.nodes.defaultSettings.innerHTML = '';
+
+ /** Tell to subscribers that block settings is closed */
+ this.Editor.Events.emit(this.events.closed);
+ }
+}
diff --git a/src/components/modules/toolbar-inline.ts b/src/components/modules/toolbar-inline.ts
new file mode 100644
index 000000000..218da0581
--- /dev/null
+++ b/src/components/modules/toolbar-inline.ts
@@ -0,0 +1,403 @@
+declare var Module: any;
+declare var $: any;
+
+import BoldInlineTool from '../inline-tools/inline-tool-bold';
+import ItalicInlineTool from '../inline-tools/inline-tool-italic';
+import LinkInlineTool from '../inline-tools/inline-tool-link';
+import EditorConfig from '../interfaces/editor-config';
+import InlineTool from '../interfaces/tools/inline-tool';
+import SelectionUtils from '../selection';
+import _ from '../utils';
+
+/**
+ * Inline toolbar with actions that modifies selected text fragment
+ *
+ * |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
+ * | B i [link] [mark] |
+ * |________________________|
+ */
+export default class InlineToolbar extends Module {
+
+ /**
+ * CSS styles
+ */
+ public CSS = {
+ inlineToolbar: 'ce-inline-toolbar',
+ inlineToolbarShowed: 'ce-inline-toolbar--showed',
+ buttonsWrapper: 'ce-inline-toolbar__buttons',
+ actionsWrapper: 'ce-inline-toolbar__actions',
+ inlineToolButton: 'ce-inline-tool',
+ inlineToolButtonLast: 'ce-inline-tool--last',
+ };
+
+ /**
+ * Inline Toolbar elements
+ */
+ private nodes = {
+ wrapper: null,
+ buttons: null,
+ /**
+ * Zone below the buttons where Tools can create additional actions by 'renderActions()' method
+ * For example, input for the 'link' tool or textarea for the 'comment' tool
+ */
+ actions: null,
+ };
+
+ /**
+ * Margin above/below the Toolbar
+ */
+ private readonly toolbarVerticalMargin: number = 20;
+
+ /**
+ * Tools instances
+ */
+ private toolsInstances: Map;
+
+ /**
+ * @constructor
+ * @param {EditorConfig} config
+ */
+ constructor({config}) {
+ super({config});
+ }
+
+ /**
+ * Inline Toolbar Tools
+ * includes internal and external tools
+ *
+ * @returns Map
+ */
+ get tools(): Map {
+ if (!this.toolsInstances || this.toolsInstances.size === 0) {
+ const allTools = {...this.internalTools, ...this.externalTools};
+
+ this.toolsInstances = new Map();
+ for (const tool in allTools) {
+ if (allTools.hasOwnProperty(tool)) {
+ this.toolsInstances.set(tool, allTools[tool]);
+ }
+ }
+ }
+
+ return this.toolsInstances;
+ }
+
+ /**
+ * Making DOM
+ */
+ public make() {
+ this.nodes.wrapper = $.make('div', this.CSS.inlineToolbar);
+ this.nodes.buttons = $.make('div', this.CSS.buttonsWrapper);
+ this.nodes.actions = $.make('div', this.CSS.actionsWrapper);
+
+ /**
+ * Append Inline Toolbar to the Editor
+ */
+ $.append(this.nodes.wrapper, [this.nodes.buttons, this.nodes.actions]);
+ $.append(this.Editor.UI.nodes.wrapper, this.nodes.wrapper);
+
+ /**
+ * Append Inline Toolbar Tools
+ */
+ this.addTools();
+
+ }
+
+ /**
+ * Moving / appearance
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+ /**
+ * Shows Inline Toolbar by keyup/mouseup
+ * @param {KeyboardEvent|MouseEvent} event
+ */
+ public handleShowingEvent(event): void {
+ if (!this.allowedToShow(event)) {
+ this.close();
+ return;
+ }
+
+ this.move();
+ this.open();
+
+ /** Check Tools state for selected fragment */
+ this.checkToolsState();
+ }
+
+ /**
+ * Move Toolbar to the selected text
+ */
+ public move(): void {
+ const selectionRect = SelectionUtils.rect as DOMRect;
+ const wrapperOffset = this.Editor.UI.nodes.wrapper.getBoundingClientRect();
+ const newCoords = {
+ x: selectionRect.x - wrapperOffset.left,
+ y: selectionRect.y
+ + selectionRect.height
+ // + window.scrollY
+ - wrapperOffset.top
+ + this.toolbarVerticalMargin,
+ };
+
+ /**
+ * If we know selections width, place InlineToolbar to center
+ */
+ if (selectionRect.width) {
+ newCoords.x += Math.floor(selectionRect.width / 2);
+ }
+
+ this.nodes.wrapper.style.left = Math.floor(newCoords.x) + 'px';
+ this.nodes.wrapper.style.top = Math.floor(newCoords.y) + 'px';
+ }
+
+ /**
+ * Shows Inline Toolbar
+ */
+ private open() {
+ /**
+ * Filter inline-tools and show only allowed by Block's Tool
+ */
+ this.filterTools();
+
+ /**
+ * Show Inline Toolbar
+ */
+ this.nodes.wrapper.classList.add(this.CSS.inlineToolbarShowed);
+
+ /**
+ * Call 'clear' method for Inline Tools (for example, 'link' want to clear input)
+ */
+ this.tools.forEach( (toolInstance, toolName) => {
+ if (typeof toolInstance.clear === 'function') {
+ toolInstance.clear();
+ }
+ });
+ }
+
+ /**
+ * Hides Inline Toolbar
+ */
+ private close() {
+ this.nodes.wrapper.classList.remove(this.CSS.inlineToolbarShowed);
+ this.tools.forEach( (toolInstance, toolName) => {
+ if (typeof toolInstance.clear === 'function') {
+ toolInstance.clear();
+ }
+ });
+ }
+
+ /**
+ * Need to show Inline Toolbar or not
+ * @param {KeyboardEvent|MouseEvent} event
+ */
+ private allowedToShow(event): boolean {
+ /**
+ * Tags conflicts with window.selection function.
+ * Ex. IMG tag returns null (Firefox) or Redactors wrapper (Chrome)
+ */
+ const tagsConflictsWithSelection = ['IMG', 'INPUT'];
+
+ if (event && tagsConflictsWithSelection.includes(event.target.tagName)) {
+ return false;
+ }
+
+ const currentSelection = SelectionUtils.get(),
+ selectedText = SelectionUtils.text;
+
+ // old browsers
+ if (!currentSelection || !currentSelection.anchorNode) {
+ return false;
+ }
+
+ // empty selection
+ if (currentSelection.isCollapsed || selectedText.length < 1) {
+ return false;
+ }
+
+ // is enabled by current Block's Tool
+ const currentBlock = this.Editor.BlockManager.getBlock(currentSelection.anchorNode);
+
+ if (!currentBlock) {
+ return false;
+ }
+
+ const toolSettings = this.Editor.Tools.getToolSettings(currentBlock.name);
+
+ return toolSettings && toolSettings[this.Editor.Tools.apiSettings.IS_ENABLED_INLINE_TOOLBAR];
+ }
+
+ /**
+ * Show only allowed Tools
+ */
+ private filterTools(): void {
+ const currentSelection = SelectionUtils.get(),
+ currentBlock = this.Editor.BlockManager.getBlock(currentSelection.anchorNode);
+
+ const toolSettings = this.Editor.Tools.getToolSettings(currentBlock.name),
+ inlineToolbarSettings = toolSettings && toolSettings[this.Editor.Tools.apiSettings.IS_ENABLED_INLINE_TOOLBAR];
+
+ /**
+ * All Inline Toolbar buttons
+ * @type {HTMLElement[]}
+ */
+ const buttons = Array.from(this.nodes.buttons.querySelectorAll(`.${this.CSS.inlineToolButton}`)) as HTMLElement[];
+
+ /**
+ * Show previously hided
+ */
+ buttons.forEach((button) => {
+ button.hidden = false;
+ button.classList.remove(this.CSS.inlineToolButtonLast);
+ });
+
+ /**
+ * Filter buttons if Block Tool pass config like inlineToolbar=['link']
+ */
+ if (Array.isArray(inlineToolbarSettings)) {
+ buttons.forEach((button) => {
+ button.hidden = !inlineToolbarSettings.includes(button.dataset.tool);
+ });
+ }
+
+ /**
+ * Tick for removing right-margin from last visible button.
+ * Current generation of CSS does not allow to filter :visible elements
+ */
+ const lastVisibleButton = buttons.filter((button) => !button.hidden).pop();
+
+ if (lastVisibleButton) {
+ lastVisibleButton.classList.add(this.CSS.inlineToolButtonLast);
+ }
+ }
+
+ /**
+ * Working with Tools
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+ /**
+ * Fill Inline Toolbar with Tools
+ */
+ private addTools(): void {
+ this.tools.forEach( (toolInstance, toolName) => {
+ this.addTool(toolName, toolInstance);
+ });
+ }
+
+ /**
+ * Add tool button and activate clicks
+ */
+ private addTool(toolName: string, tool: InlineTool): void {
+ const button = tool.render();
+
+ if (!button) {
+ _.log('Render method must return an instance of Node', 'warn', toolName);
+ return;
+ }
+
+ button.dataset.tool = toolName;
+ this.nodes.buttons.appendChild(button);
+
+ if (typeof tool.renderActions === 'function') {
+ const actions = tool.renderActions();
+ this.nodes.actions.appendChild(actions);
+ }
+
+ this.Editor.Listeners.on(button, 'click', () => {
+ this.toolClicked(tool);
+ });
+
+ /**
+ * Enable shortcuts
+ * Ignore tool that doesn't have shortcut or empty string
+ */
+ const toolSettings = this.Editor.Tools.getToolSettings(toolName);
+
+ let shortcut = null;
+
+ /**
+ * 1) For internal tools, check public getter 'shortcut'
+ * 2) For external tools, check tool's settings
+ */
+ if (this.internalTools[toolName]) {
+ shortcut = this.internalTools[toolName].shortcut;
+ } else if (toolSettings && toolSettings[this.Editor.Tools.apiSettings.SHORTCUT]) {
+ shortcut = toolSettings[this.Editor.Tools.apiSettings.SHORTCUT];
+ }
+
+ if (shortcut) {
+ this.enableShortcuts(tool, shortcut);
+ }
+ }
+
+ /**
+ * Enable Tool shortcut with Editor Shortcuts Module
+ * @param {InlineTool} tool - Tool instance
+ * @param {string} shortcut - shortcut according to the Shortcut Module format
+ */
+ private enableShortcuts(tool: InlineTool, shortcut: string): void {
+ this.Editor.Shortcuts.add({
+ name: shortcut,
+ handler: (event) => {
+ const {currentBlock} = this.Editor.BlockManager,
+ toolSettings = this.Editor.Tools.getToolSettings(currentBlock.name);
+
+ if (!toolSettings || !toolSettings[this.Editor.Tools.apiSettings.IS_ENABLED_INLINE_TOOLBAR]) {
+ return;
+ }
+
+ event.preventDefault();
+ this.toolClicked(tool);
+ },
+ });
+ }
+
+ /**
+ * Inline Tool button clicks
+ * @param {InlineTool} tool - Tool's instance
+ */
+ private toolClicked(tool: InlineTool): void {
+ const range = SelectionUtils.range;
+
+ tool.surround(range);
+ this.checkToolsState();
+ }
+
+ /**
+ * Check Tools` state by selection
+ */
+ private checkToolsState(): void {
+ this.tools.forEach( (toolInstance, toolName) => {
+ toolInstance.checkState(SelectionUtils.get());
+ });
+ }
+
+ /**
+ * Returns internal inline tools
+ * Includes Bold, Italic, Link
+ */
+ private get internalTools(): {[name: string]: InlineTool} {
+ return {
+ bold: this.Editor.Tools.constructInline(BoldInlineTool),
+ italic: this.Editor.Tools.constructInline(ItalicInlineTool),
+ link: this.Editor.Tools.constructInline(LinkInlineTool),
+ };
+ }
+
+ /**
+ * Get external tools
+ * Tools that has isInline is true
+ */
+ private get externalTools(): {[name: string]: InlineTool} {
+ const result = {};
+
+ for (const tool in this.Editor.Tools.inline) {
+ if (this.Editor.Tools.inline.hasOwnProperty(tool)) {
+ result[tool] = this.Editor.Tools.constructInline(this.Editor.Tools.inline[tool]);
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/src/components/modules/toolbar-toolbox.js b/src/components/modules/toolbar-toolbox.js
new file mode 100644
index 000000000..063996fa0
--- /dev/null
+++ b/src/components/modules/toolbar-toolbox.js
@@ -0,0 +1,303 @@
+import IEditorConfig from '../interfaces/editor-config';
+
+/**
+ * @class Toolbox
+ * @classdesc Holder for Tools
+ *
+ * @typedef {Toolbox} Toolbox
+ * @property {Boolean} opened - opening state
+ * @property {Object} nodes - Toolbox nodes
+ * @property {Object} CSS - CSS class names
+ *
+ */
+export default class Toolbox extends Module {
+ /**
+ * @constructor
+ * @param {IEditorConfig} config
+ */
+ constructor({config}) {
+ super({config});
+
+ this.nodes = {
+ toolbox: null,
+ buttons: []
+ };
+
+ /**
+ * Opening state
+ * @type {boolean}
+ */
+ this.opened = false;
+
+ /**
+ * Active button index
+ * -1 equals no chosen Tool
+ * @type {number}
+ */
+ this.activeButtonIndex = -1;
+ }
+
+ /**
+ * CSS styles
+ * @return {{toolbox: string, toolboxButton: string, toolboxOpened: string}}
+ */
+ static get CSS() {
+ return {
+ toolbox: 'ce-toolbox',
+ toolboxButton: 'ce-toolbox__button',
+ toolboxButtonActive : 'ce-toolbox__button--active',
+ toolboxOpened: 'ce-toolbox--opened',
+ };
+ }
+
+ /**
+ * Makes the Toolbox
+ */
+ make() {
+ this.nodes.toolbox = $.make('div', Toolbox.CSS.toolbox);
+ $.append(this.Editor.Toolbar.nodes.content, this.nodes.toolbox);
+
+ this.addTools();
+ }
+
+ /**
+ * Iterates available tools and appends them to the Toolbox
+ */
+ addTools() {
+ let tools = this.Editor.Tools.toolsAvailable;
+
+ for (let toolName in tools) {
+ this.addTool(toolName, tools[toolName]);
+ }
+ }
+
+ /**
+ * Append Tool to the Toolbox
+ *
+ * @param {string} toolName - tool name
+ * @param {IBlockTool} tool - tool class
+ */
+ addTool(toolName, tool) {
+ const api = this.Editor.Tools.apiSettings;
+
+ if (tool[api.IS_DISPLAYED_IN_TOOLBOX] && !tool[api.TOOLBAR_ICON]) {
+ _.log('Toolbar icon is missed. Tool %o skipped', 'warn', toolName);
+ return;
+ }
+
+ /**
+ * @todo Add checkup for the render method
+ */
+ // if (typeof tool.render !== 'function') {
+ // _.log('render method missed. Tool %o skipped', 'warn', tool);
+ // return;
+ // }
+
+ /**
+ * Skip tools that pass 'displayInToolbox=false'
+ */
+ if (!tool[api.IS_DISPLAYED_IN_TOOLBOX]) {
+ return;
+ }
+
+ let button = $.make('li', [ Toolbox.CSS.toolboxButton ], {
+ title: toolName
+ });
+
+ button.innerHTML = tool.toolboxIcon;
+
+ $.append(this.nodes.toolbox, button);
+
+ this.nodes.toolbox.appendChild(button);
+ this.nodes.buttons.push(button);
+
+ /**
+ * Add click listener
+ */
+ this.Editor.Listeners.on(button, 'click', (event) => {
+ this.toolButtonActivate(event, toolName);
+ });
+
+ /**
+ * Enable shortcut
+ */
+ const toolSettings = this.Editor.Tools.getToolSettings(toolName);
+
+ if (toolSettings && toolSettings[this.Editor.Tools.apiSettings.SHORTCUT]) {
+ this.enableShortcut(tool, toolName, toolSettings[this.Editor.Tools.apiSettings.SHORTCUT]);
+ }
+ }
+
+ /**
+ * Enable shortcut Block Tool implemented shortcut
+ * @param {IBlockTool} tool - Tool class
+ * @param {String} toolName - Tool name
+ * @param {String} shortcut - shortcut according to the Shortcut Module format
+ */
+ enableShortcut(tool, toolName, shortcut) {
+ this.Editor.Shortcuts.add({
+ name: shortcut,
+ handler: (event) => {
+ event.preventDefault();
+ this.insertNewBlock(tool, toolName);
+ }
+ });
+ }
+
+ /**
+ * Inserts new block
+ * Can be called when button clicked on Toolbox or by Shortcut
+ *
+ * @param {IBlockTool} tool - Tool Class
+ * @param {String} toolName - Tool name
+ */
+ insertNewBlock(tool, toolName) {
+ /**
+ * @type {Block}
+ */
+ const currentBlock = this.Editor.BlockManager.currentBlock;
+
+ /**
+ * We do replace if:
+ * - block is empty
+ * - block is not irreplaceable
+ * @type {Array}
+ */
+ let newBlock;
+
+ if (!tool[this.Editor.Tools.apiSettings.IS_IRREPLACEBLE_TOOL] && currentBlock.isEmpty) {
+ newBlock = this.Editor.BlockManager.replace(toolName);
+ } else {
+ newBlock = this.Editor.BlockManager.insert(toolName);
+ }
+
+ this.Editor.Caret.setToBlock(newBlock);
+
+ /**
+ * close toolbar when node is changed
+ */
+ this.Editor.Toolbar.close();
+ }
+
+ /**
+ * Toolbox Tool's button click handler
+ *
+ * @param {MouseEvent|KeyboardEvent} event
+ * @param {string} toolName
+ */
+ toolButtonActivate(event, toolName) {
+ const tool = this.Editor.Tools.toolsClasses[toolName];
+
+ this.insertNewBlock(tool, toolName);
+ }
+
+ /**
+ * Open Toolbox with Tools
+ */
+ open() {
+ this.nodes.toolbox.classList.add(Toolbox.CSS.toolboxOpened);
+ this.opened = true;
+ }
+
+ /**
+ * Close Toolbox
+ */
+ close() {
+ this.nodes.toolbox.classList.remove(Toolbox.CSS.toolboxOpened);
+ this.opened = false;
+
+ /** remove active item pointer */
+ this.activeButtonIndex = -1;
+ const activeButton = this.nodes.toolbox.querySelector(`.${Toolbox.CSS.toolboxButtonActive}`);
+
+ if (activeButton) {
+ activeButton.classList.remove(Toolbox.CSS.toolboxButtonActive);
+ }
+ }
+
+ /**
+ * Close Toolbox
+ */
+ toggle() {
+ if (!this.opened) {
+ this.open();
+ } else {
+ this.close();
+ }
+ }
+
+ /**
+ * Leaf
+ * flip through the toolbox items
+ * @param {String} direction - leaf direction, right is default
+ */
+ leaf(direction = 'right') {
+ const childNodes = this.nodes.toolbox.childNodes;
+
+ /**
+ * If activeButtonIndex === -1 then we have no chosen Tool in Toolbox
+ */
+ if (this.activeButtonIndex === -1) {
+ /**
+ * Normalize "previous" Tool index depending on direction.
+ * We need to do this to highlight "first" Tool correctly
+ *
+ * Order of Tools: [0] [1] ... [n - 1]
+ * [0 = n] because of: n % n = 0 % n
+ *
+ * Direction 'right': for [0] the [n - 1] is a previous index
+ * [n - 1] -> [0]
+ *
+ * Direction 'left': for [n - 1] the [0] is a previous index
+ * [n - 1] <- [0]
+ *
+ * @type {number}
+ */
+ this.activeButtonIndex = direction === 'right' ? -1 : 0;
+ } else {
+ /**
+ * If we have chosen Tool then remove highlighting
+ */
+ childNodes[this.activeButtonIndex].classList.remove(Toolbox.CSS.toolboxButtonActive);
+ }
+
+ /**
+ * Count index for next Tool
+ */
+ if (direction === 'right') {
+ /**
+ * If we go right then choose next (+1) Tool
+ * @type {number}
+ */
+ this.activeButtonIndex = (this.activeButtonIndex + 1) % childNodes.length;
+ } else {
+ /**
+ * If we go left then choose previous (-1) Tool
+ * Before counting module we need to add length before because of "The JavaScript Modulo Bug"
+ * @type {number}
+ */
+ this.activeButtonIndex = (childNodes.length + this.activeButtonIndex - 1) % childNodes.length;
+ }
+
+ /**
+ * Highlight new chosen Tool
+ */
+ childNodes[this.activeButtonIndex].classList.add(Toolbox.CSS.toolboxButtonActive);
+ }
+
+ /**
+ * get tool name when it is selected
+ * In case when nothing selection returns null
+ *
+ * @return {String|null}
+ */
+ get getActiveTool() {
+ const childNodes = this.nodes.toolbox.childNodes;
+
+ if (this.activeButtonIndex === -1) {
+ return null;
+ }
+
+ return childNodes[this.activeButtonIndex].title;
+ }
+}
diff --git a/src/components/modules/toolbar.js b/src/components/modules/toolbar.js
new file mode 100644
index 000000000..cc0908ef1
--- /dev/null
+++ b/src/components/modules/toolbar.js
@@ -0,0 +1,259 @@
+/**
+ *
+ * «Toolbar» is the node that moves up/down over current block
+ *
+ * ______________________________________ Toolbar ____________________________________________
+ * | |
+ * | ..................... Content .................... ......... Block Actions .......... |
+ * | . . . . |
+ * | . . . [Open Settings] . |
+ * | . [Plus Button] [Toolbox: {Tool1}, {Tool2}] . . . |
+ * | . . . [Settings Panel] . |
+ * | .................................................. .................................. |
+ * | |
+ * |___________________________________________________________________________________________|
+ *
+ *
+ * Toolbox — its an Element contains tools buttons. Can be shown by Plus Button.
+ *
+ * _______________ Toolbox _______________
+ * | |
+ * | [Header] [Image] [List] [Quote] ... |
+ * |_______________________________________|
+ *
+ *
+ * Settings Panel — is an Element with block settings:
+ *
+ * ____ Settings Panel ____
+ * | ...................... |
+ * | . Tool Settings . |
+ * | ...................... |
+ * | . Default Settings . |
+ * | ...................... |
+ * |________________________|
+ *
+ *
+ * @class
+ * @classdesc Toolbar module
+ *
+ * @typedef {Toolbar} Toolbar
+ * @property {Object} nodes
+ * @property {Element} nodes.wrapper - Toolbar main element
+ * @property {Element} nodes.content - Zone with Plus button and toolbox.
+ * @property {Element} nodes.actions - Zone with Block Settings and Remove Button
+ * @property {Element} nodes.blockActionsButtons - Zone with Block Buttons: [Settings]
+ * @property {Element} nodes.plusButton - Button that opens or closes Toolbox
+ * @property {Element} nodes.toolbox - Container for tools
+ * @property {Element} nodes.settingsToggler - open/close Settings Panel button
+ * @property {Element} nodes.settings - Settings Panel
+ * @property {Element} nodes.pluginSettings - Plugin Settings section of Settings Panel
+ * @property {Element} nodes.defaultSettings - Default Settings section of Settings Panel
+ */
+export default class Toolbar extends Module {
+ /**
+ * @constructor
+ */
+ constructor({config}) {
+ super({config});
+
+ this.nodes = {
+ wrapper : null,
+ content : null,
+ actions : null,
+
+ // Content Zone
+ plusButton : null,
+
+ // Actions Zone
+ blockActionsButtons: null,
+ settingsToggler : null,
+ };
+ }
+
+ /**
+ * CSS styles
+ * @return {Object}
+ * @constructor
+ */
+ static get CSS() {
+ return {
+ toolbar: 'ce-toolbar',
+ content: 'ce-toolbar__content',
+ actions: 'ce-toolbar__actions',
+
+ toolbarOpened: 'ce-toolbar--opened',
+
+ // Content Zone
+ plusButton: 'ce-toolbar__plus',
+ plusButtonHidden: 'ce-toolbar__plus--hidden',
+
+ // Actions Zone
+ blockActionsButtons: 'ce-toolbar__actions-buttons',
+ settingsToggler: 'ce-toolbar__settings-btn',
+ };
+ }
+
+ /**
+ * Makes toolbar
+ */
+ make() {
+ this.nodes.wrapper = $.make('div', Toolbar.CSS.toolbar);
+
+ /**
+ * Make Content Zone and Actions Zone
+ */
+ ['content', 'actions'].forEach( el => {
+ this.nodes[el] = $.make('div', Toolbar.CSS[el]);
+ $.append(this.nodes.wrapper, this.nodes[el]);
+ });
+
+
+ /**
+ * Fill Content Zone:
+ * - Plus Button
+ * - Toolbox
+ */
+ this.nodes.plusButton = $.make('div', Toolbar.CSS.plusButton);
+ $.append(this.nodes.plusButton, $.svg('plus', 14, 14));
+ $.append(this.nodes.content, this.nodes.plusButton);
+ this.nodes.plusButton.addEventListener('click', event => this.plusButtonClicked(event), false);
+
+
+ /**
+ * Make a Toolbox
+ */
+ this.Editor.Toolbox.make();
+
+ /**
+ * Fill Actions Zone:
+ * - Settings Toggler
+ * - Remove Block Button
+ * - Settings Panel
+ */
+ this.nodes.blockActionsButtons = $.make('div', Toolbar.CSS.blockActionsButtons);
+ this.nodes.settingsToggler = $.make('span', Toolbar.CSS.settingsToggler);
+ const settingsIcon = $.svg('dots', 18, 4);
+
+ $.append(this.nodes.settingsToggler, settingsIcon);
+ $.append(this.nodes.blockActionsButtons, this.nodes.settingsToggler);
+ $.append(this.nodes.actions, this.nodes.blockActionsButtons);
+
+ /**
+ * Make and append Settings Panel
+ */
+ this.Editor.BlockSettings.make();
+ $.append(this.nodes.actions, this.Editor.BlockSettings.nodes.wrapper);
+
+ /**
+ * Append toolbar to the Editor
+ */
+ $.append(this.Editor.UI.nodes.wrapper, this.nodes.wrapper);
+
+ /**
+ * Bind events on the Toolbar elements
+ */
+ this.bindEvents();
+ }
+
+ /**
+ * Move Toolbar to the Current Block
+ * @param {Boolean} forceClose - force close Toolbar Settings and Toolbar
+ */
+ move(forceClose = true) {
+ if (forceClose) {
+ /** Close Toolbox when we move toolbar */
+ this.Editor.Toolbox.close();
+ this.Editor.BlockSettings.close();
+ }
+
+ let currentNode = this.Editor.BlockManager.currentNode;
+
+ /**
+ * If no one Block selected as a Current
+ */
+ if (!currentNode) {
+ return;
+ }
+
+ /**
+ * @todo Compute dynamically on prepare
+ * @type {number}
+ */
+ const defaultToolbarHeight = 49;
+ const defaultOffset = 34;
+
+ var newYCoordinate = currentNode.offsetTop - (defaultToolbarHeight / 2) + defaultOffset;
+
+ this.nodes.wrapper.style.transform = `translate3D(0, ${Math.floor(newYCoordinate)}px, 0)`;
+ }
+
+ /**
+ * Open Toolbar with Plus Button
+ */
+ open() {
+ this.move();
+ this.nodes.wrapper.classList.add(Toolbar.CSS.toolbarOpened);
+ }
+
+ /**
+ * returns toolbar opened state
+ * @return {Boolean}
+ */
+ get opened() {
+ return this.nodes.wrapper.classList.contains(Toolbar.CSS.toolbarOpened);
+ }
+
+ /**
+ * Close the Toolbar
+ */
+ close() {
+ this.nodes.wrapper.classList.remove(Toolbar.CSS.toolbarOpened);
+
+ /** Close components */
+ this.Editor.Toolbox.close();
+ this.Editor.BlockSettings.close();
+ }
+
+ /**
+ * Plus Button public methods
+ * @return {{hide: function(): void, show: function(): void}}
+ */
+ get plusButton() {
+ return {
+ hide: () => this.nodes.plusButton.classList.add(Toolbar.CSS.plusButtonHidden),
+ show: () => this.nodes.plusButton.classList.remove(Toolbar.CSS.plusButtonHidden)
+ };
+ }
+
+ /**
+ * Handler for Plus Button
+ * @param {MouseEvent} event
+ */
+ plusButtonClicked() {
+ this.Editor.Toolbox.toggle();
+ }
+
+ /**
+ * Bind events on the Toolbar Elements:
+ * - Block Settings
+ */
+ bindEvents() {
+ /**
+ * Settings toggler
+ */
+ this.Editor.Listeners.on(this.nodes.settingsToggler, 'click', (event) => {
+ this.settingsTogglerClicked(event);
+ });
+ }
+
+ /**
+ * Clicks on the Block Settings toggler
+ */
+ settingsTogglerClicked() {
+ if (this.Editor.BlockSettings.opened) {
+ this.Editor.BlockSettings.close();
+ } else {
+ this.Editor.BlockSettings.open();
+ }
+ }
+}
diff --git a/src/components/modules/tools.js b/src/components/modules/tools.js
new file mode 100644
index 000000000..812138fc2
--- /dev/null
+++ b/src/components/modules/tools.js
@@ -0,0 +1,371 @@
+const Paragraph = require('../tools/paragraph/dist/bundle');
+
+/**
+ * @module Codex Editor Tools Submodule
+ *
+ * Creates Instances from Plugins and binds external config to the instances
+ */
+
+/**
+ * Each Tool must contain the following important objects:
+ *
+ * @typedef {Object} ToolConfig {@link docs/tools.md}
+ * @property {String} iconClassname - this a icon in toolbar
+ * @property {Boolean} displayInToolbox - will be displayed in toolbox. Default value is TRUE
+ * @property {Boolean} enableLineBreaks - inserts new block or break lines. Default value is FALSE
+ * @property {Boolean|String[]} inlineToolbar - Pass `true` to enable the Inline Toolbar with all Tools, all pass an array with specified Tools list |
+ * @property render @todo add description
+ * @property save @todo add description
+ * @property settings @todo add description
+ * @property validate - method that validates output data before saving
+ */
+
+/**
+ * @typedef {Function} Tool {@link docs/tools.md}
+ * @property {Boolean} displayInToolbox - By default, tools won't be added in the Toolbox. Pass true to add.
+ * @property {String} iconClassName - CSS class name for the Toolbox button
+ * @property {Boolean} irreplaceable - Toolbox behaviour: replace or add new block below
+ * @property render
+ * @property save
+ * @property settings
+ * @property validate
+ *
+ * @todo update according to current API
+ * @todo describe Tool in the {@link docs/tools.md}
+ */
+
+/**
+ * Class properties:
+ *
+ * @typedef {Tools} Tools
+ * @property {Tools[]} toolsAvailable - available Tools
+ * @property {Tools[]} toolsUnavailable - unavailable Tools
+ * @property {object} toolsClasses - all classes
+ * @property {object} toolsSettings - Tools settings
+ * @property {EditorConfig} config - Editor config
+ */
+export default class Tools extends Module {
+ /**
+ * @constructor
+ *
+ * @param {EditorConfig} config
+ */
+ constructor({config}) {
+ super({config});
+
+ /**
+ * Map {name: Class, ...} where:
+ * name — block type name in JSON. Got from EditorConfig.tools keys
+ * @type {Object}
+ */
+ this.toolsClasses = {};
+
+ /**
+ * Tools settings in a map {name: settings, ...}
+ * @type {Object}
+ */
+ this.toolsSettings = {};
+
+ /**
+ * Available tools list
+ * {name: Class, ...}
+ * @type {Object}
+ */
+ this.toolsAvailable = {};
+
+ /**
+ * Tools that rejected a prepare method
+ * {name: Class, ... }
+ * @type {Object}
+ */
+ this.toolsUnavailable = {};
+
+ /**
+ * Cache for the prepared inline tools
+ * @type {null|object}
+ * @private
+ */
+ this._inlineTools = null;
+ }
+
+ /**
+ * Returns available Tools
+ * @return {Tool[]}
+ */
+ get available() {
+ return this.toolsAvailable;
+ }
+
+ /**
+ * Returns unavailable Tools
+ * @return {Tool[]}
+ */
+ get unavailable() {
+ return this.toolsUnavailable;
+ }
+
+ /**
+ * Return Tools for the Inline Toolbar
+ * @return {Object} - object of Inline Tool's classes
+ */
+ get inline() {
+ if (this._inlineTools) {
+ return this._inlineTools;
+ }
+
+ const tools = Object.entries(this.available).filter( ([name, tool]) => {
+ if (!tool[this.apiSettings.IS_INLINE]) {
+ return false;
+ }
+
+ /**
+ * Some Tools validation
+ */
+ const inlineToolRequiredMethods = ['render', 'surround', 'checkState'];
+ const notImplementedMethods = inlineToolRequiredMethods.filter( method => !this.constructInline(tool)[method]);
+
+ if (notImplementedMethods.length) {
+ _.log(`Incorrect Inline Tool: ${tool.name}. Some of required methods is not implemented %o`, 'warn', notImplementedMethods);
+ return false;
+ }
+
+ return true;
+ });
+
+ /**
+ * collected inline tools with key of tool name
+ */
+ const result = {};
+
+ tools.forEach(([name, tool]) => result[name] = tool);
+
+ /**
+ * Cache prepared Tools
+ */
+ this._inlineTools = result;
+
+ return this._inlineTools;
+ }
+
+ /**
+ * Return editor block tools
+ */
+ get blockTools() {
+ // eslint-disable-next-line no-unused-vars
+ const tools = Object.entries(this.available).filter( ([name, tool]) => {
+ if (tool[this.apiSettings.IS_INLINE]) {
+ return false;
+ }
+
+ return true;
+ });
+
+ /**
+ * collected block tools with key of tool name
+ */
+ const result = {};
+
+ tools.forEach(([name, tool]) => result[name] = tool);
+
+ return result;
+ }
+
+ /**
+ * Constant for available Tools Settings
+ * @return {object}
+ */
+ get apiSettings() {
+ return {
+ CONFIG: 'config',
+ IS_CONTENTLESS: 'contentless',
+ IS_DISPLAYED_IN_TOOLBOX: 'displayInToolbox',
+ IS_ENABLED_INLINE_TOOLBAR: 'inlineToolbar',
+ IS_ENABLED_LINE_BREAKS: 'enableLineBreaks',
+ IS_INLINE: 'isInline',
+ IS_IRREPLACEBLE_TOOL: 'irreplaceable',
+ IS_PASTE_DISALLOWED: 'disallowPaste',
+ SHORTCUT: 'shortcut',
+ TOOLBAR_ICON: 'toolboxIcon',
+ };
+ }
+
+ /**
+ * Creates instances via passed or default configuration
+ * @return {Promise}
+ */
+ prepare() {
+ this.config.tools.paragraph = {
+ class: Paragraph,
+ inlineToolbar: true
+ };
+
+ if (!this.config.hasOwnProperty('tools') || Object.keys(this.config.tools).length === 0) {
+ return Promise.reject('Can\'t start without tools');
+ }
+
+ /**
+ * Save Tools settings to a map
+ */
+ for(let toolName in this.config.tools) {
+ /**
+ * If Tool is an object not a Tool's class then
+ * save class and settings separately
+ */
+ if (typeof this.config.tools[toolName] === 'object') {
+ /**
+ * Save Tool's class from 'class' field
+ * @type {ITool}
+ */
+ this.toolsClasses[toolName] = this.config.tools[toolName].class;
+
+ /**
+ * Save Tool's settings
+ * @type {IToolSettings}
+ */
+ this.toolsSettings[toolName] = this.config.tools[toolName];
+
+ /**
+ * Remove Tool's class from settings
+ */
+ delete this.toolsSettings[toolName].class;
+ } else {
+ /**
+ * Save Tool's class
+ * @type {ITool}
+ */
+ this.toolsClasses[toolName] = this.config.tools[toolName];
+
+ /**
+ * Set empty settings for Block by default
+ * @type {{}}
+ */
+ this.toolsSettings[toolName] = {};
+ }
+ }
+
+ /**
+ * getting classes that has prepare method
+ */
+ let sequenceData = this.getListOfPrepareFunctions();
+
+ /**
+ * if sequence data contains nothing then resolve current chain and run other module prepare
+ */
+ if (sequenceData.length === 0) {
+ return Promise.resolve();
+ }
+
+ /**
+ * to see how it works {@link Util#sequence}
+ */
+ return _.sequence(sequenceData, (data) => {
+ this.success(data);
+ }, (data) => {
+ this.fallback(data);
+ });
+ }
+
+ /**
+ * Binds prepare function of plugins with user or default config
+ * @return {Array} list of functions that needs to be fired sequentially
+ */
+ getListOfPrepareFunctions() {
+ let toolPreparationList = [];
+
+ for(let toolName in this.toolsClasses) {
+ let toolClass = this.toolsClasses[toolName];
+
+ if (typeof toolClass.prepare === 'function') {
+ toolPreparationList.push({
+ function : toolClass.prepare,
+ data : {
+ toolName
+ }
+ });
+ } else {
+ /**
+ * If Tool hasn't a prepare method, mark it as available
+ */
+ this.toolsAvailable[toolName] = toolClass;
+ }
+ }
+
+ return toolPreparationList;
+ }
+
+ /**
+ * @param {ChainData.data} data - append tool to available list
+ */
+ success(data) {
+ this.toolsAvailable[data.toolName] = this.toolsClasses[data.toolName];
+ }
+
+ /**
+ * @param {ChainData.data} data - append tool to unavailable list
+ */
+ fallback(data) {
+ this.toolsUnavailable[data.toolName] = this.toolsClasses[data.toolName];
+ }
+
+ /**
+ * Return Tool`s instance
+ *
+ * @param {String} tool — tool name
+ * @param {IBlockToolData} data — initial data
+ * @return {IBlockTool}
+ */
+ construct(tool, data) {
+ const plugin = this.toolsClasses[tool];
+
+ /**
+ * Configuration to be passed to the Tool's constructor
+ */
+ const config = this.toolsSettings[tool][this.apiSettings.CONFIG];
+
+ /**
+ * @type {{api: IAPI, config: ({}), data: IBlockToolData}}
+ */
+ const constructorOptions = {
+ api: this.Editor.API.methods,
+ config: config || {},
+ data: data
+ };
+
+ return new plugin(constructorOptions);
+ }
+
+ /**
+ * Return Inline Tool's instance
+ *
+ * @param {IInlineTool} tool
+ * @return {IInlineTool} — instance
+ */
+ constructInline(tool) {
+ /**
+ * @type {{api: IAPI}}
+ */
+ const constructorOptions = {
+ api: this.Editor.API.methods
+ };
+
+ return new tool(constructorOptions);
+ }
+
+ /**
+ * Check if passed Tool is an instance of Initial Block Tool
+ * @param {Tool} tool - Tool to check
+ * @return {Boolean}
+ */
+ isInitial(tool) {
+ return tool instanceof this.available[this.config.initialBlock];
+ }
+
+ /**
+ * Return Tool's config by name
+ * @param {string} toolName
+ * @return {IToolSettings}
+ */
+ getToolSettings(toolName) {
+ return this.toolsSettings[toolName];
+ }
+}
diff --git a/src/components/modules/ui.js b/src/components/modules/ui.js
new file mode 100644
index 000000000..4dcf31014
--- /dev/null
+++ b/src/components/modules/ui.js
@@ -0,0 +1,341 @@
+/**
+ * Module UI
+ *
+ * @type {UI}
+ */
+
+/**
+ * Prebuilded sprite of SVG icons
+ */
+import sprite from '../../../build/sprite.svg';
+
+import Selection from '../selection';
+
+/**
+ * @class
+ *
+ * @classdesc Makes CodeX Editor UI:
+ *
+ *
+ *
+ *
+ *
+ *
+ * @typedef {UI} UI
+ * @property {EditorConfig} config - editor configuration {@link CodexEditor#configuration}
+ * @property {Object} Editor - available editor modules {@link CodexEditor#moduleInstances}
+ * @property {Object} nodes -
+ * @property {Element} nodes.holder - element where we need to append redactor
+ * @property {Element} nodes.wrapper -
+ * @property {Element} nodes.redactor -
+ */
+export default class UI extends Module {
+ /**
+ * @constructor
+ *
+ * @param {EditorConfig} config
+ */
+ constructor({config}) {
+ super({config});
+
+ this.nodes = {
+ holder: null,
+ wrapper: null,
+ redactor: null
+ };
+ }
+
+ /**
+ * Making main interface
+ */
+ async prepare() {
+ await this.make();
+
+ /**
+ * Append SVG sprite
+ */
+ await this.appendSVGSprite();
+
+ /**
+ * Make toolbar
+ */
+ await this.Editor.Toolbar.make();
+
+ /**
+ * Make the Inline toolbar
+ */
+ await this.Editor.InlineToolbar.make();
+
+ /**
+ * Load and append CSS
+ */
+ await this.loadStyles();
+
+ /**
+ * Bind events for the UI elements
+ */
+ await this.bindEvents();
+ }
+
+ /**
+ * CodeX Editor UI CSS class names
+ * @return {{editorWrapper: string, editorZone: string, block: string}}
+ */
+ get CSS() {
+ return {
+ editorWrapper : 'codex-editor',
+ editorZone : 'codex-editor__redactor',
+ };
+ }
+
+ /**
+ * Makes CodeX Editor interface
+ * @return {Promise}
+ */
+ async make() {
+ /**
+ * Element where we need to append CodeX Editor
+ * @type {Element}
+ */
+ this.nodes.holder = document.getElementById(this.config.holderId);
+
+ if (!this.nodes.holder) {
+ throw Error("Holder wasn't found by ID: #" + this.config.holderId);
+ }
+
+ /**
+ * Create and save main UI elements
+ */
+ this.nodes.wrapper = $.make('div', this.CSS.editorWrapper);
+ this.nodes.redactor = $.make('div', this.CSS.editorZone);
+
+ this.nodes.wrapper.appendChild(this.nodes.redactor);
+ this.nodes.holder.appendChild(this.nodes.wrapper);
+ }
+
+ /**
+ * Appends CSS
+ */
+ loadStyles() {
+ /**
+ * Load CSS
+ */
+ let styles = require('../../styles/main.css');
+
+ /**
+ * Make tag
+ */
+ let tag = $.make('style', null, {
+ textContent: styles.toString()
+ });
+
+ /**
+ * Append styles at the top of HEAD tag
+ */
+ $.prepend(document.head, tag);
+ }
+
+ /**
+ * Bind events on the CodeX Editor interface
+ */
+ bindEvents() {
+ this.Editor.Listeners.on(this.nodes.redactor, 'click', event => this.redactorClicked(event), false );
+ this.Editor.Listeners.on(document, 'keydown', event => this.documentKeydown(event), true );
+ this.Editor.Listeners.on(document, 'click', event => this.documentClicked(event), false );
+ }
+
+ /**
+ * All keydowns on document
+ * @param {Event} event
+ */
+ documentKeydown(event) {
+ switch (event.keyCode) {
+ case _.keyCodes.ENTER:
+ this.enterPressed(event);
+ break;
+ default:
+ this.defaultBehaviour(event);
+ break;
+ }
+ }
+
+ /**
+ * Ignore all other document's keydown events
+ * @param {KeyboardEvent} event
+ */
+ defaultBehaviour(event) {
+ const keyDownOnEditor = event.target.closest(`.${this.CSS.editorWrapper}`);
+
+ /**
+ * Ignore keydowns on document
+ * clear pointer and close toolbar
+ */
+ if (!keyDownOnEditor) {
+ /**
+ * Remove all highlights and remove caret
+ */
+ this.Editor.BlockManager.dropPointer();
+
+ /**
+ * Close Toolbar
+ */
+ this.Editor.Toolbar.close();
+ }
+ }
+
+ /**
+ * Enter pressed on document
+ * @param event
+ */
+ enterPressed(event) {
+ let hasPointerToBlock = this.Editor.BlockManager.currentBlockIndex >= 0;
+
+ /**
+ * If Caret is not set anywhere, event target on Enter is always Element that we handle
+ * In our case it is document.body
+ *
+ * So, BlockManager points some Block and Enter press is on Body
+ * We can create a new block
+ */
+ if (hasPointerToBlock && event.target.tagName === 'BODY') {
+ /**
+ * Insert initial typed Block
+ */
+ const newBlock = this.Editor.BlockManager.insert();
+
+ this.Editor.Caret.setToBlock(newBlock);
+
+ /**
+ * And highlight
+ */
+ this.Editor.BlockManager.highlightCurrentNode();
+
+ /**
+ * Move toolbar and show plus button because new Block is empty
+ */
+ this.Editor.Toolbar.move();
+ this.Editor.Toolbar.plusButton.show();
+ }
+ }
+
+ /**
+ * All clicks on document
+ * @param {MouseEvent} event - Click
+ */
+ documentClicked(event) {
+ /**
+ * Close Inline Toolbar when nothing selected
+ * Do not fire check on clicks at the Inline Toolbar buttons
+ */
+ const clickedOnInlineToolbarButton = event.target.closest(`.${this.Editor.InlineToolbar.CSS.inlineToolbar}`);
+ const clickedInsideofEditor = event.target.closest(`.${this.CSS.editorWrapper}`);
+
+ /** Clear highlightings and pointer on BlockManager */
+ if (!clickedInsideofEditor && !Selection.isAtEditor) {
+ this.Editor.BlockManager.dropPointer();
+ this.Editor.Toolbar.close();
+ }
+
+ if (!clickedOnInlineToolbarButton) {
+ this.Editor.InlineToolbar.handleShowingEvent(event);
+ }
+
+ if (Selection.isAtEditor) {
+ this.Editor.BlockManager.setCurrentBlockByChildNode(Selection.anchorNode);
+ }
+ }
+
+ /**
+ * All clicks on the redactor zone
+ *
+ * @param {MouseEvent} event
+ *
+ * @description
+ * 1. Save clicked Block as a current {@link BlockManager#currentNode}
+ * it uses for the following:
+ * - add CSS modifier for the selected Block
+ * - on Enter press, we make a new Block under that
+ *
+ * 2. Move and show the Toolbar
+ *
+ * 3. Set a Caret
+ *
+ * 4. By clicks on the Editor's bottom zone:
+ * - if last Block is empty, set a Caret to this
+ * - otherwise, add a new empty Block and set a Caret to that
+ *
+ * 5. Hide the Inline Toolbar
+ *
+ * @see selectClickedBlock
+ *
+ */
+ redactorClicked(event) {
+ const clickedNode = event.target;
+
+ /**
+ * Select clicked Block as Current
+ */
+ try {
+ /**
+ * Renew Current Block
+ */
+ this.Editor.BlockManager.setCurrentBlockByChildNode(clickedNode);
+
+ /**
+ * Highlight Current Node
+ */
+ this.Editor.BlockManager.highlightCurrentNode();
+ } catch (e) {
+ /**
+ * If clicked outside first-level Blocks, set Caret to the last empty Block
+ */
+ this.Editor.Caret.setToTheLastBlock();
+ }
+
+ /**
+ * Move toolbar and open
+ */
+ this.Editor.Toolbar.open();
+
+ /**
+ * Hide the Plus Button
+ * */
+ this.Editor.Toolbar.plusButton.hide();
+
+ if (!this.Editor.BlockManager.currentBlock) {
+ this.Editor.BlockManager.insert();
+ }
+
+ /**
+ * Show the Plus Button if:
+ * - Block is an initial-block (Text)
+ * - Block is empty
+ */
+ let isInitialBlock = this.Editor.Tools.isInitial(this.Editor.BlockManager.currentBlock.tool),
+ isEmptyBlock = this.Editor.BlockManager.currentBlock.isEmpty;
+
+ if (isInitialBlock && isEmptyBlock) {
+ this.Editor.Toolbar.plusButton.show();
+ }
+ }
+
+ /**
+ * Append prebuilded sprite with SVG icons
+ */
+ appendSVGSprite() {
+ let spriteHolder = $.make('div');
+
+ spriteHolder.hidden = true;
+ spriteHolder.style.display = 'none';
+ spriteHolder.innerHTML = sprite;
+
+ $.append(this.nodes.wrapper, spriteHolder);
+ }
+
+ /**
+ * Clean editor`s UI
+ */
+ destroy() {
+ this.nodes.holder.innerHTML = '';
+ }
+}
diff --git a/src/components/polyfills.ts b/src/components/polyfills.ts
new file mode 100644
index 000000000..9fc6c5603
--- /dev/null
+++ b/src/components/polyfills.ts
@@ -0,0 +1,89 @@
+'use strict';
+
+/**
+ * Extend Element interface to include prefixed and experimental properties
+ */
+interface Element {
+ matchesSelector: (selector: string) => boolean;
+ mozMatchesSelector: (selector: string) => boolean;
+ oMatchesSelector: (selector: string) => boolean;
+
+ prepend: (nodes: Node|Node[]|any) => void;
+}
+
+/**
+ * The Element.matches() method returns true if the element
+ * would be selected by the specified selector string;
+ * otherwise, returns false.
+ *
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/matches#Polyfill}
+ */
+if (!Element.prototype.matches) {
+ Element.prototype.matches = Element.prototype.matchesSelector ||
+ Element.prototype.mozMatchesSelector ||
+ Element.prototype.msMatchesSelector ||
+ Element.prototype.oMatchesSelector ||
+ Element.prototype.webkitMatchesSelector ||
+ function(s) {
+ const matches = (this.document || this.ownerDocument).querySelectorAll(s);
+ let i = matches.length;
+
+ while (--i >= 0 && matches.item(i) !== this) {
+ }
+
+ return i > -1;
+ };
+}
+
+/**
+ * The Element.closest() method returns the closest ancestor
+ * of the current element (or the current element itself) which
+ * matches the selectors given in parameter.
+ * If there isn't such an ancestor, it returns null.
+ *
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill}
+ */
+if (!Element.prototype.closest) {
+ Element.prototype.closest = function(s) {
+ let el = this;
+
+ if (!document.documentElement.contains(el)) {
+ return null;
+ }
+
+ do {
+ if (el.matches(s)) {
+ return el;
+ }
+
+ el = el.parentElement || el.parentNode;
+ } while (el !== null);
+
+ return null;
+ };
+}
+
+/**
+ * The ParentNode.prepend method inserts a set of Node objects
+ * or DOMString objects before the first child of the ParentNode.
+ * DOMString objects are inserted as equivalent Text nodes.
+ *
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/prepend#Polyfill}
+ */
+if (!Element.prototype.prepend) {
+ Element.prototype.prepend = function prepend(nodes: Node|Node[]|any) {
+ const docFrag = document.createDocumentFragment();
+
+ if (!Array.isArray(nodes)) {
+ nodes = [ nodes ];
+ }
+
+ nodes.forEach((node: Node|any) => {
+ const isNode = node instanceof Node;
+
+ docFrag.appendChild(isNode ? node : document.createTextNode(String(node)));
+ });
+
+ this.insertBefore(docFrag, this.firstChild);
+ };
+}
diff --git a/src/components/selection.ts b/src/components/selection.ts
new file mode 100644
index 000000000..809c5535d
--- /dev/null
+++ b/src/components/selection.ts
@@ -0,0 +1,327 @@
+/**
+ * TextRange interface fot IE9-
+ */
+import _ from './utils';
+
+interface TextRange {
+ boundingTop: number;
+ boundingLeft: number;
+ boundingBottom: number;
+ boundingRight: number;
+ boundingHeight: number;
+ boundingWidth: number;
+}
+
+/**
+ * Interface for object returned by document.selection in IE9-
+ */
+interface MSSelection {
+ createRange: () => TextRange;
+ type: string;
+}
+
+/**
+ * Extends Document interface for IE9-
+ */
+interface Document {
+ selection?: MSSelection;
+}
+
+/**
+ * Working with selection
+ * @typedef {Selection} Selection
+ */
+export default class SelectionUtils {
+
+ /**
+ * Editor styles
+ * @return {{editorWrapper: string, editorZone: string}}
+ * @constructor
+ */
+ static get CSS(): {editorWrapper: string, editorZone: string} {
+ return {
+ editorWrapper : 'codex-editor',
+ editorZone : 'codex-editor__redactor',
+ };
+ }
+
+ /**
+ * Returns selected anchor
+ * {@link https://developer.mozilla.org/ru/docs/Web/API/Selection/anchorNode}
+ * @return {Node|null}
+ */
+ static get anchorNode(): Node|null {
+ const selection = window.getSelection();
+
+ return selection ? selection.anchorNode : null;
+ }
+
+ /**
+ * Returns selection offset according to the anchor node
+ * {@link https://developer.mozilla.org/ru/docs/Web/API/Selection/anchorOffset}
+ * @return {Number|null}
+ */
+ static get anchorOffset(): number|null {
+ const selection = window.getSelection();
+
+ return selection ? selection.anchorOffset : null;
+ }
+
+ /**
+ * Is current selection range collapsed
+ * @return {boolean|null}
+ */
+ static get isCollapsed(): boolean|null {
+ const selection = window.getSelection();
+
+ return selection ? selection.isCollapsed : null;
+ }
+
+ /**
+ * Check current selection if it is at Editor's zone
+ * @return {boolean}
+ */
+ static get isAtEditor(): boolean {
+ const selection = SelectionUtils.get();
+
+ /**
+ * Something selected on document
+ */
+ let selectedNode = (selection.anchorNode || selection.focusNode) as HTMLElement;
+
+ if (selectedNode && selectedNode.nodeType === Node.TEXT_NODE) {
+ selectedNode = selectedNode.parentNode as HTMLElement;
+ }
+
+ let editorZone = null;
+ if (selectedNode) {
+ editorZone = selectedNode.closest(`.${SelectionUtils.CSS.editorZone}`);
+ }
+
+ /**
+ * SelectionUtils is not out of Editor because Editor's wrapper was found
+ */
+ return editorZone && editorZone.nodeType === Node.ELEMENT_NODE;
+ }
+
+ /**
+ * Return first range
+ * @return {Range|null}
+ */
+ static get range(): Range {
+ const selection = window.getSelection();
+
+ return selection && selection.rangeCount ? selection.getRangeAt(0) : null;
+ }
+
+ /**
+ * Calculates position and size of selected text
+ * @return {{x, y, width, height, top?, left?, bottom?, right?}}
+ */
+ static get rect(): DOMRect|ClientRect {
+ let sel: Selection|MSSelection = (document as Document).selection,
+ range: TextRange|Range;
+
+ let rect = {
+ x: 0,
+ y: 0,
+ width: 0,
+ height: 0,
+ } as DOMRect;
+
+ if (sel && sel.type !== 'Control') {
+ sel = sel as MSSelection;
+ range = sel.createRange() as TextRange;
+ rect.x = range.boundingLeft;
+ rect.y = range.boundingTop;
+ rect.width = range.boundingWidth;
+ rect.height = range.boundingHeight;
+
+ return rect;
+ }
+
+ if (!window.getSelection) {
+ _.log('Method window.getSelection is not supported', 'warn');
+ return rect;
+ }
+
+ sel = window.getSelection();
+
+ if (!sel.rangeCount) {
+ _.log('Method SelectionUtils.rangeCount() is not supported', 'warn');
+ return rect;
+ }
+
+ range = sel.getRangeAt(0).cloneRange() as Range;
+
+ if (range.getBoundingClientRect) {
+ rect = range.getBoundingClientRect() as DOMRect;
+ }
+ // Fall back to inserting a temporary element
+ if (rect.x === 0 && rect.y === 0) {
+ const span = document.createElement('span');
+
+ if (span.getBoundingClientRect) {
+ // Ensure span has dimensions and position by
+ // adding a zero-width space character
+ span.appendChild( document.createTextNode('\u200b') );
+ range.insertNode(span);
+ rect = span.getBoundingClientRect() as DOMRect;
+
+ const spanParent = span.parentNode;
+
+ spanParent.removeChild(span);
+
+ // Glue any broken text nodes back together
+ spanParent.normalize();
+ }
+ }
+
+ return rect;
+ }
+
+ /**
+ * Returns selected text as String
+ * @returns {string}
+ */
+ static get text(): string {
+ return window.getSelection ? window.getSelection().toString() : '';
+ }
+
+ /**
+ * Returns window SelectionUtils
+ * {@link https://developer.mozilla.org/ru/docs/Web/API/Window/getSelection}
+ * @return {Selection}
+ */
+ public static get(): Selection {
+ return window.getSelection();
+ }
+
+ public instance: Selection = null;
+ public selection: Selection = null;
+
+ /**
+ * This property can store SelectionUtils's range for restoring later
+ * @type {Range|null}
+ */
+ public savedSelectionRange: Range = null;
+
+ /**
+ * Save SelectionUtils's range
+ */
+ public save(): void {
+ this.savedSelectionRange = SelectionUtils.range;
+ }
+
+ /**
+ * Restore saved SelectionUtils's range
+ */
+ public restore(): void {
+ if (!this.savedSelectionRange) {
+ return;
+ }
+
+ const sel = window.getSelection();
+
+ sel.removeAllRanges();
+ sel.addRange(this.savedSelectionRange);
+ }
+
+ /**
+ * Clears saved selection
+ */
+ public clearSaved(): void {
+ this.savedSelectionRange = null;
+ }
+
+ /**
+ * Looks ahead to find passed tag from current selection
+ *
+ * @param {String} tagName - tag to found
+ * @param {String} [className] - tag's class name
+ * @param {Number} [searchDepth] - count of tags that can be included. For better performance.
+ * @return {HTMLElement|null}
+ */
+ public findParentTag(tagName: string, className?: string, searchDepth = 10): HTMLElement|null {
+ const selection = window.getSelection();
+ let parentTag = null;
+
+ /**
+ * If selection is missing or no anchorNode or focusNode were found then return null
+ */
+ if (!selection || !selection.anchorNode || !selection.focusNode) {
+ return null;
+ }
+
+ /**
+ * Define Nodes for start and end of selection
+ */
+ const boundNodes = [
+ /** the Node in which the selection begins */
+ selection.anchorNode as HTMLElement,
+ /** the Node in which the selection ends */
+ selection.focusNode as HTMLElement,
+ ];
+
+ /**
+ * For each selection parent Nodes we try to find target tag [with target class name]
+ * It would be saved in parentTag variable
+ */
+ boundNodes.forEach((parent) => {
+ /** Reset tags limit */
+ let searchDepthIterable = searchDepth;
+
+ while (searchDepthIterable > 0 && parent.parentNode) {
+ /**
+ * Check tag's name
+ */
+ if (parent.tagName === tagName) {
+ /**
+ * Save the result
+ */
+ parentTag = parent;
+
+ /**
+ * Optional additional check for class-name mismatching
+ */
+ if (className && parent.classList && !parent.classList.contains(className)) {
+ parentTag = null;
+ }
+
+ /**
+ * If we have found required tag with class then go out from the cycle
+ */
+ if (parentTag) {
+ break;
+ }
+ }
+
+ /**
+ * Target tag was not found. Go up to the parent and check it
+ */
+ parent = parent.parentNode as HTMLElement;
+ searchDepthIterable--;
+ }
+ });
+
+ /**
+ * Return found tag or null
+ */
+ return parentTag;
+ }
+
+ /**
+ * Expands selection range to the passed parent node
+ *
+ * @param {HTMLElement} element
+ */
+ public expandToTag(element: HTMLElement): void {
+ const selection = window.getSelection();
+
+ selection.removeAllRanges();
+ const range = document.createRange();
+
+ range.selectNodeContents(element);
+ selection.addRange(range);
+ }
+}
diff --git a/src/components/tools/paragraph b/src/components/tools/paragraph
new file mode 160000
index 000000000..67af23696
--- /dev/null
+++ b/src/components/tools/paragraph
@@ -0,0 +1 @@
+Subproject commit 67af23696c591b6dc922b3c6c1b43070293281ea
diff --git a/src/components/utils.ts b/src/components/utils.ts
new file mode 100644
index 000000000..99083e407
--- /dev/null
+++ b/src/components/utils.ts
@@ -0,0 +1,199 @@
+/**
+ * @typedef {Object} ChainData
+ * @property {Object} data - data that will be passed to the success or fallback
+ * @property {Function} function - function's that must be called asynchronically
+ */
+interface ChainData {
+ data: any;
+ function: (...args: any[]) => any;
+}
+
+/**
+ * Codex Editor Util
+ */
+export default class Util {
+ /**
+ * Custom logger
+ *
+ * @param {string} msg - message
+ * @param {string} type - logging type 'log'|'warn'|'error'|'info'
+ * @param {*} args - argument to log with a message
+ */
+ public static log(msg: string, type: string = 'log', args?: any): void {
+
+ if (!args) {
+ if (['time', 'timeEnd'].includes(type)) {
+ msg = `[codex-editor]: ${msg}`;
+ } else {
+ args = msg || 'undefined';
+ msg = '[codex-editor]: %o';
+ }
+ } else {
+ msg = '[codex-editor]: ' + msg;
+ }
+
+ try {
+ if ( 'console' in window && window.console[ type ] ) {
+ if ( args ) { window.console[ type ]( msg, args ); } else { window.console[ type ]( msg ); }
+ }
+ } catch (e) {
+ // do nothing
+ }
+ }
+
+ /**
+ * Returns basic keycodes as constants
+ * @return {{}}
+ */
+ static get keyCodes(): object {
+ return {
+ BACKSPACE: 8,
+ TAB: 9,
+ ENTER: 13,
+ SHIFT: 16,
+ CTRL: 17,
+ ALT: 18,
+ ESC: 27,
+ SPACE: 32,
+ LEFT: 37,
+ UP: 38,
+ DOWN: 40,
+ RIGHT: 39,
+ DELETE: 46,
+ META: 91,
+ };
+ }
+
+ /**
+ * Fires a promise sequence asyncronically
+ *
+ * @param {ChainData[]} chains - list or ChainData's
+ * @param {Function} success - success callback
+ * @param {Function} fallback - callback that fires in case of errors
+ *
+ * @return {Promise}
+ */
+ public static sequence(chains: ChainData[], success = () => {}, fallback = () => {}): Promise {
+ return new Promise((resolve) => {
+ /**
+ * pluck each element from queue
+ * First, send resolved Promise as previous value
+ * Each plugins "prepare" method returns a Promise, that's why
+ * reduce current element will not be able to continue while can't get
+ * a resolved Promise
+ */
+ chains.reduce((previousValue, currentValue, iteration) => {
+ return previousValue
+ .then(() => waitNextBlock(currentValue, success, fallback))
+ .then(() => {
+ // finished
+ if (iteration === chains.length - 1) {
+ resolve();
+ }
+ });
+ }, Promise.resolve());
+ });
+
+ /**
+ * Decorator
+ *
+ * @param {ChainData} chainData
+ *
+ * @param {Function} successCallback
+ * @param {Function} fallbackCallback
+ *
+ * @return {Promise}
+ */
+ function waitNextBlock(
+ chainData: ChainData,
+ successCallback: (data: any) => void,
+ fallbackCallback: (data: any) => void,
+ ): Promise {
+ return new Promise((resolve) => {
+ chainData.function()
+ .then(() => {
+ successCallback(chainData.data || {});
+ })
+ .then(resolve)
+ .catch(() => {
+ fallbackCallback(chainData.data || {});
+
+ // anyway, go ahead even it falls
+ resolve();
+ });
+ });
+ }
+ }
+
+ /**
+ * Make array from array-like collection
+ *
+ * @param {ArrayLike} collection
+ *
+ * @return {Array}
+ */
+ public static array(collection: ArrayLike): any[] {
+ return Array.prototype.slice.call(collection);
+ }
+
+ /**
+ * Check if passed variable is a function
+ * @param {*} fn
+ * @return {boolean}
+ */
+ public static isFunction(fn: any): boolean {
+ return typeof fn === 'function';
+ }
+
+ /**
+ * Check if passed function is a class
+ * @param {function} fn
+ * @return {boolean}
+ */
+ public static isClass(fn: any): boolean {
+ return typeof fn === 'function' && /^\s*class\s+/.test(fn.toString());
+ }
+
+ /**
+ * Checks if object is empty
+ *
+ * @param {Object} object
+ * @return {boolean}
+ */
+ public static isEmpty(object: object): boolean {
+ return Object.keys(object).length === 0 && object.constructor === Object;
+ }
+
+ /**
+ * Check if passed object is a Promise
+ * @param {*} object - object to check
+ * @return {Boolean}
+ */
+ public static isPromise(object: any): boolean {
+ return Promise.resolve(object) === object;
+ }
+
+ /**
+ * Check if passed element is contenteditable
+ * @param {HTMLElement} element
+ * @return {boolean}
+ */
+ public static isContentEditable(element: HTMLElement): boolean {
+ return element.contentEditable === 'true';
+ }
+
+ /**
+ * Delays method execution
+ *
+ * @param {Function} method
+ * @param {Number} timeout
+ */
+ public static delay(method: (...args: any[]) => any, timeout: number) {
+ return function() {
+ const context = this,
+ args = arguments;
+
+ window.setTimeout(() => method.apply(context, args), timeout);
+ };
+ }
+}
diff --git a/codex-editor.css b/src/styles/_legacy.css
similarity index 97%
rename from codex-editor.css
rename to src/styles/_legacy.css
index 1fb54f950..6b72d89e2 100644
--- a/codex-editor.css
+++ b/src/styles/_legacy.css
@@ -1,24 +1,17 @@
-/**
-* CodeX Editor stylesheets
-* @author CodeX Team https://ifmo.su
-*
-* https://github.com/codex-team/codex.editor
-*/
-
-
-@import url('icons.css');
-
-
/**
* Editor wrapper
*/
.codex-editor{
position: relative;
-}
+ border: 1px solid #ccc;
+ padding: 10px;
- .codex-editor .hide {
+ .hide {
display: none;
}
+}
+
+
/**
* Working zone - redactor
@@ -27,6 +20,7 @@
position: relative;
padding-bottom: 120px;
min-height: 350px;
+ border: 1px dotted #ccc;
}
.ce-block__content a {
@@ -69,7 +63,6 @@
*/
.ce-toolbar__plus{
position: absolute;
- background-image: url('fonts/codex_editor/icon-plus.svg');
background-position: center center;
background-repeat: no-repeat;
text-align: center;
@@ -327,7 +320,6 @@
.ce-settings__anchor-hash {
display: inline-block;
- background: url('fonts/codex_editor/icon-hash.svg') no-repeat center center;
background-size: contain;
height: 11px;
width: 10px;
diff --git a/src/styles/animations.css b/src/styles/animations.css
new file mode 100644
index 000000000..0e32012b5
--- /dev/null
+++ b/src/styles/animations.css
@@ -0,0 +1,73 @@
+.wobble {
+ animation-name: wobble;
+ animation-duration: 400ms;
+}
+
+/**
+ * @author Nick Pettit - https://github.com/nickpettit/glide
+ */
+@keyframes wobble {
+ from {
+ transform: translate3d(0, 0, 0);
+ }
+
+ 15% {
+ transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -5deg);
+ }
+
+ 30% {
+ transform: translate3d(2%, 0, 0) rotate3d(0, 0, 1, 3deg);
+ }
+
+ 45% {
+ transform: translate3d(-3%, 0, 0) rotate3d(0, 0, 1, -3deg);
+ }
+
+ 60% {
+ transform: translate3d(2%, 0, 0) rotate3d(0, 0, 1, 2deg);
+ }
+
+ 75% {
+ transform: translate3d(-1%, 0, 0) rotate3d(0, 0, 1, -1deg);
+ }
+
+ to {
+ transform: translate3d(0, 0, 0);
+ }
+}
+
+@keyframes bounceIn {
+ from,
+ 20%,
+ 40%,
+ 60%,
+ 80%,
+ to {
+ animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
+ }
+
+ 0% {
+ transform: scale3d(0.86, 0.86, 0.86);
+ }
+
+ 20% {
+ transform: scale3d(1.1, 1.1, 1.1);
+ }
+
+ 40% {
+ transform: scale3d(0.9, 0.9, 0.9);
+ }
+
+ 60% {
+ transform: scale3d(1.03, 1.03, 1.03);
+ }
+
+ 80% {
+ transform: scale3d(0.97, 0.97, 0.97);
+ }
+
+ to {
+ transform: scale3d(1, 1, 1);
+ }
+}
+
diff --git a/src/styles/block.css b/src/styles/block.css
new file mode 100644
index 000000000..4df2359ce
--- /dev/null
+++ b/src/styles/block.css
@@ -0,0 +1,19 @@
+.ce-block {
+ &:first-of-type {
+ margin-top: 0;
+ }
+
+ &--selected {
+ background-image: linear-gradient(17deg, rgba(243, 248, 255, 0.03) 63.45%, rgba(207, 214, 229, 0.27) 98%);
+ border-radius: 3px;
+ }
+
+ &--stretched &__content {
+ max-width: none;
+ }
+
+ &__content {
+ max-width: var(--content-width);
+ margin: 0 auto;
+ }
+}
diff --git a/src/styles/export.css b/src/styles/export.css
new file mode 100644
index 000000000..25d0b7317
--- /dev/null
+++ b/src/styles/export.css
@@ -0,0 +1,61 @@
+/**
+ * Block Tool wrapper
+ */
+.cdx-block {
+ padding: 0.7em 0;
+}
+
+/**
+ * Input
+ */
+.cdx-input {
+ border: 1px solid var(--color-gray-border);
+ box-shadow: inset 0 1px 2px 0 rgba(35, 44, 72, 0.06);
+ border-radius: 3px;
+ padding: 10px 12px;
+ outline: none;
+ width: 100%;
+ box-sizing: border-box;
+}
+
+/**
+ * Settings
+ */
+.cdx-settings-button {
+ @apply --toolbar-button;
+
+ &--active {
+ color: var(--color-active-icon);
+ }
+}
+
+/**
+ * Loader
+ */
+.cdx-loader {
+ position: relative;
+ border: 1px solid var(--color-gray-border);
+
+ &::before {
+ content: '';
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ width: 18px;
+ height: 18px;
+ margin: -11px 0 0 -11px;
+ border: 2px solid var(--color-gray-border);
+ border-left-color: var(--color-active-icon);
+ border-radius: 50%;
+ animation: cdxRotation 1.2s infinite linear;
+ }
+}
+
+@keyframes cdxRotation {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
+}
diff --git a/src/styles/inline-toolbar.css b/src/styles/inline-toolbar.css
new file mode 100644
index 000000000..2cc0859eb
--- /dev/null
+++ b/src/styles/inline-toolbar.css
@@ -0,0 +1,66 @@
+.ce-inline-toolbar {
+ @apply --overlay-pane;
+ padding: 6px;
+ transform: translateX(-50%);
+ display: none;
+ box-shadow: 0 6px 12px -6px rgba(131, 147, 173, 0.46),
+ 5px -12px 34px -13px rgba(97, 105, 134, 0.6),
+ 0 26px 52px 3px rgba(147, 165, 186, 0.24);
+
+ &--showed {
+ display: block;
+ }
+
+ [hidden] {
+ display: none !important;
+ }
+}
+
+.ce-inline-tool {
+ @apply --toolbar-button;
+ line-height: normal;
+
+ &--last {
+ margin-right: 0 !important;
+ }
+
+ &--link {
+ .icon {
+ margin-top: -2px;
+ }
+
+ .icon--unlink {
+ display: none;
+ }
+ }
+
+ &--unlink {
+ .icon--link {
+ display: none;
+ }
+ .icon--unlink {
+ display: inline-block;
+ }
+ }
+
+ &-input {
+ background-color: var(--bg-light);
+ outline: none;
+ border: 0;
+ border-radius: 3px;
+ margin: 6px 0 0;
+ font-size: 13px;
+ padding: 8px;
+ width: 100%;
+ box-sizing: border-box;
+ display: none;
+
+ &::placeholder {
+ color: var(--grayText);
+ }
+
+ &--showed {
+ display: block;
+ }
+ }
+}
diff --git a/src/styles/main.css b/src/styles/main.css
new file mode 100644
index 000000000..6d2e1da22
--- /dev/null
+++ b/src/styles/main.css
@@ -0,0 +1,9 @@
+@import url('variables.css');
+@import url('ui.css');
+@import url('toolbar.css');
+@import url('toolbox.css');
+@import url('inline-toolbar.css');
+@import url('settings.css');
+@import url('block.css');
+@import url('animations.css');
+@import url('export.css');
diff --git a/src/styles/settings.css b/src/styles/settings.css
new file mode 100644
index 000000000..49de06840
--- /dev/null
+++ b/src/styles/settings.css
@@ -0,0 +1,66 @@
+.ce-settings {
+ @apply --overlay-pane;
+ right: 5px;
+ top: 35px;
+ min-width: 124px;
+
+ &::before{
+ left: auto;
+ right: 12px;
+ }
+
+ display: none;
+
+ &--opened {
+ display: block;
+ }
+
+ &__plugin-zone {
+ &:not(:empty){
+ padding: 6px 6px 0;
+ }
+ }
+
+ &__default-zone {
+ &:not(:empty){
+ padding: 6px;
+ }
+ }
+
+ &__button {
+ @apply --toolbar-button;
+ line-height: 32px;
+
+ &--disabled {
+ cursor: not-allowed !important;
+ opacity: .3;
+ }
+
+ &--selected {
+ color: var(--color-active-icon);
+ }
+
+ &--delete {
+ transition: background-color 300ms ease;
+ will-change: background-color;
+
+ .icon {
+ transition: transform 200ms ease-out;
+ will-change: transform;
+ }
+ }
+
+ &--confirm {
+ background-color: var(--color-confirm);
+ color: #fff;
+
+ &:hover {
+ background-color: color-mod(var(--color-confirm) blackness(+5%)) !important;
+ }
+
+ .icon {
+ transform: rotate(90deg);
+ }
+ }
+ }
+}
diff --git a/src/styles/toolbar.css b/src/styles/toolbar.css
new file mode 100644
index 000000000..953090ce6
--- /dev/null
+++ b/src/styles/toolbar.css
@@ -0,0 +1,57 @@
+.ce-toolbar {
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ /*opacity: 0;*/
+ /*visibility: hidden;*/
+ transition: opacity 100ms ease;
+ will-change: opacity, transform;
+ display: none;
+
+ &--opened {
+ display: block;
+ /*opacity: 1;*/
+ /*visibility: visible;*/
+ }
+
+ &__content {
+ max-width: var(--content-width);
+ margin: 0 auto;
+ position: relative;
+ }
+
+ &__plus {
+ @apply --toolbox-button;
+
+ position: absolute;
+ left: calc(calc(var(--toolbox-buttons-size) + 10px) * -1);
+
+ &--hidden {
+ display: none;
+ }
+ }
+
+ /**
+ * Block actions Zone
+ * -------------------------
+ */
+ &__actions {
+ position: absolute;
+ right: 0;
+ top: 0;
+ padding-right: 16px;
+
+ &-buttons {
+ text-align: right;
+ }
+ }
+
+ &__settings-btn {
+ display: inline-block;
+ width: 24px;
+ height: 24px;
+ color: var(--grayText);
+ cursor: pointer;
+ }
+}
diff --git a/src/styles/toolbox.css b/src/styles/toolbox.css
new file mode 100644
index 000000000..16e292bd4
--- /dev/null
+++ b/src/styles/toolbox.css
@@ -0,0 +1,17 @@
+.ce-toolbox {
+ position: absolute;
+ visibility: hidden;
+ transition: opacity 100ms ease;
+ will-change: opacity;
+ display: flex;
+ flex-direction: row;
+
+ &--opened {
+ opacity: 1;
+ visibility: visible;
+ }
+
+ &__button {
+ @apply --toolbox-button;
+ }
+}
diff --git a/src/styles/ui.css b/src/styles/ui.css
new file mode 100644
index 000000000..9e3c62abf
--- /dev/null
+++ b/src/styles/ui.css
@@ -0,0 +1,42 @@
+/**
+* Editor wrapper
+*/
+.codex-editor {
+ position: relative;
+ box-sizing: border-box;
+
+ .hide {
+ display: none;
+ }
+
+ &__redactor {
+ padding-bottom: 300px;
+ }
+
+ svg {
+ fill: currentColor;
+ vertical-align: middle;
+ max-height: 100%;
+ }
+}
+
+/**
+ * Set color for native selection
+ */
+::selection{
+ background-color: var(--selectionColor);
+}
+
+/**
+ * Add placeholder to content editable elements with data attribute
+ * data-placeholder="Hello world!"
+ */
+[contentEditable=true][data-placeholder]:empty::before{
+ content: attr(data-placeholder);
+ color: var(--grayText);
+ font-weight: normal;
+}
+
+[contentEditable=true][data-placeholder]:empty:focus::before {
+ opacity: 0.3;
+}
diff --git a/src/styles/variables.css b/src/styles/variables.css
new file mode 100644
index 000000000..e4f6da508
--- /dev/null
+++ b/src/styles/variables.css
@@ -0,0 +1,125 @@
+:root {
+ /**
+ * Selection color
+ */
+ --selectionColor: rgba(61,166,239,0.63);
+
+ /**
+ * Toolbar buttons
+ */
+ --bg-light: #eff2f5;
+
+ /**
+ * All gray texts: placeholders, settings
+ */
+ --grayText: #707684;
+
+ /**
+ * Blue icons
+ */
+ --color-active-icon: #388AE5;
+
+ /**
+ * Gray border, loaders
+ */
+ --color-gray-border: #E8E8EB;
+
+ /**
+ * Block content width
+ */
+ --content-width: 650px;
+
+ /**
+ * Toolbar buttons height and width
+ */
+ --toolbar-buttons-size: 34px;
+
+ /**
+ * Toolbar Plus Button and Toolbox buttons height and width
+ */
+ --toolbox-buttons-size: 24px;
+
+ /**
+ * Confirm deletion bg
+ */
+ --color-confirm: #E24A4A;
+
+ --overlay-pane: {
+ position: absolute;
+ background-color: #FFFFFF;
+ box-shadow: 0 8px 23px -6px rgba(21,40,54,0.31), 22px -14px 34px -18px rgba(33,48,73,0.26);
+ border-radius: 4px;
+ z-index: 2;
+
+ &::before {
+ content: '';
+ width: 15px;
+ height: 15px;
+ position: absolute;
+ top: -7px;
+ left: 50%;
+ margin-left: -7px;
+ transform: rotate(-45deg);
+ background-color: #fff;
+ z-index: -1;
+ }
+ };
+
+ /**
+ * Styles for Toolbox Buttons and Plus Button
+ */
+ --toolbox-button: {
+ color: var(--grayText);
+ cursor: pointer;
+ width: var(--toolbox-buttons-size);
+ height: var(--toolbox-buttons-size);
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+
+ &:not(:last-of-type){
+ margin-right: 10px;
+ }
+
+ &:hover,
+ &--active {
+ color: var(--color-active-icon);
+ }
+
+ &--active{
+ animation: bounceIn 0.75s 1;
+ animation-fill-mode: forwards;
+ }
+
+ };
+
+ /**
+ * Styles for Settings Button in Toolbar
+ */
+ --toolbar-button: {
+ display: inline-block;
+ width: 34px;
+ height: 34px;
+ line-height: 34px;
+ text-align: center;
+ border-radius: 3px;
+ cursor: pointer;
+ border: 0;
+ outline: none;
+ background-color: transparent;
+ vertical-align: bottom;
+ color: var(--grayText);
+
+ &:not(:last-of-type){
+ margin-right: 5px;
+ }
+
+ &:hover {
+ background-color: var(--bg-light);
+ }
+
+ &--active {
+ color: var(--color-active-icon);
+ }
+ };
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 000000000..ad52c423a
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "compilerOptions" : {
+ "sourceMap": true,
+ "target": "es2017",
+ "declaration": false,
+ "moduleResolution": "node", // This resolution strategy attempts to mimic the Node.js module resolution mechanism at runtime
+ "lib": ["es2017", "dom"]
+ }
+}
diff --git a/tslint.json b/tslint.json
new file mode 100644
index 000000000..7833928e4
--- /dev/null
+++ b/tslint.json
@@ -0,0 +1,17 @@
+{
+ "extends": "tslint:recommended",
+ "rules": {
+ "indent": [true, "spaces", 2],
+ "interface-name": false,
+ "quotemark": [true, "single"],
+ "no-console": false,
+ "no-empty-interface": false,
+ "one-variable-per-declaration": false,
+ "object-literal-sort-keys": false,
+ "ordered-imports": [true, {
+ "import-sources-order": "any",
+ "named-imports-order": "case-insensitive"
+ }],
+ "no-empty": false
+ }
+}
diff --git a/webpack.config.js b/webpack.config.js
index 315629360..2030a3edc 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -20,79 +20,195 @@ const VERSION = process.env.VERSION || pkg.version;
* Plugins for bundle
* @type {webpack}
*/
-var webpack = require('webpack');
-var ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
+var webpack = require('webpack');
-module.exports = {
-
- entry: {
- "codex-editor": "./codex"
- },
- output: {
- filename: "[name].js",
- library: ["codex","editor"]
- },
-
- watch: true,
-
- watchOptions: {
- aggregateTimeOut: 50
- },
-
- devtool: NODE_ENV == 'development' ? "source-map" : null,
+/**
+ * File system
+ */
+var fs = require('fs');
- resolve : {
- fallback: path.join(__dirname, "node_modules"),
- modulesDirectories : ['./node_modules', './modules'],
- extensions : ['', '.js', '.json']
- },
+/**
+ * Available CodeX Editor modules placed in components/modules folder
+ * They will required automatically.
+ * Folders and files starting with '_' will be skipped
+ * @type {Array}
+ */
+var editorModules = fs.readdirSync('./src/components/modules').filter( name => /.(j|t)s$/.test(name) && name.substring(0,1) !== '_' );
- resolveLoader : {
- modulesDirectories: ['./node_modules'],
- moduleTemplates: ["*-webpack-loader", "*-web-loader", "*-loader", "*"],
- extensions: ['', '.js']
- },
+editorModules.forEach( name => {
+ console.log('Require modules/' + name);
+});
+/**
+ * Options for the Babel
+ */
+var babelLoader = {
+ loader: 'babel-loader',
+ options: {
+ cacheDirectory: true,
+ presets: [
+ "env"
+ ],
plugins: [
+ /**
+ * Dont need to use «.default» after «export default Class Ui {}»
+ * @see {@link https://github.com/59naga/babel-plugin-add-module-exports}
+ */
+ 'add-module-exports',
+ /**
+ * Babel transforms some awesome ES6 features to ES5 with extra code, such as Class, JSX.
+ * This plugin makes all generated extra codes to one module which significantly reduces the bundle code size.
+ *
+ * {@link https://github.com/brianZeng/babel-plugin-transform-helper}
+ * @since 11 dec 2017 - removed due to plugin does not supports class inheritance
+ */
+ // ['babel-plugin-transform-helper', {
+ // helperFilename:'build/__tmp_babel_helpers.js'
+ // }],
+ 'class-display-name',
+ ]
+ }
+};
- /** Pass variables into modules */
- new webpack.DefinePlugin({
- NODE_ENV: JSON.stringify(NODE_ENV),
- VERSION: JSON.stringify(VERSION)
- }),
-
- /** Минифицируем CSS и JS */
- new webpack.optimize.UglifyJsPlugin({
- /** Disable warning messages. Cant disable uglify for 3rd party libs such as html-janitor */
- compress: {
- warnings: false
- }
- }),
- /** Block biuld if errors found */
- new webpack.NoErrorsPlugin(),
- ],
-
- module : {
+module.exports = {
- loaders : [{
- test : /\.js$/,
- exclude: /(node_modules)/,
- loader : 'babel',
- query: {
- presets: [__dirname + '/node_modules/babel-preset-es2015']
- }
- },
- {
- test : /\.js$/,
- loader: 'eslint-loader?fix=true',
- exclude: /(node_modules)/
- },
- {
- test : /\.css$/,
- exclude: /(node_modules)/,
- loader: ExtractTextWebpackPlugin.extract('style-loader', 'css-loader')
- }]
+ entry: {
+ 'codex-editor': ['babel-polyfill', './src/codex']
+ },
+ output: {
+ path: path.resolve(__dirname, 'build'),
+ filename: '[name].js',
+ library: [ 'CodexEditor' ],
+ libraryTarget: 'umd'
+ },
+
+ watch: true,
+ watchOptions: {
+ aggregateTimeout: 50
+ },
+
+ devtool: NODE_ENV == 'development' ? 'source-map' : null,
+
+ /**
+ * Tell webpack what directories should be searched when resolving modules.
+ */
+ resolve : {
+ // fallback: path.join(__dirname, 'node_modules'),
+ modules : [ path.join(__dirname, "src"), "node_modules"],
+ extensions: ['.js', '.ts'],
+ alias: {
+ 'utils': path.resolve(__dirname + '/src/components/', './utils'),
+ 'dom': path.resolve(__dirname + '/src/components/', './dom'),
}
-};
\ No newline at end of file
+ },
+ //
+
+ // resolveLoader : {
+ // modules: [ path.resolve(__dirname, "src"), "node_modules" ],
+ // moduleTemplates: ['*-webpack-loader', '*-web-loader', '*-loader', '*'],
+ // extensions: ['.js']
+ // },
+
+ plugins: [
+
+ /** Pass variables into modules */
+ new webpack.DefinePlugin({
+ NODE_ENV: JSON.stringify(NODE_ENV),
+ VERSION: JSON.stringify(VERSION),
+ editorModules: JSON.stringify(editorModules)
+ }),
+
+ /**
+ * Setting up a dynamic requires that we use to autoload Editor Modules from 'components/modules' dir
+ * {@link https://webpack.js.org/plugins/context-replacement-plugin/}
+ */
+ new webpack.ContextReplacementPlugin(
+ /src\/components\/modules/,
+ false, // newContentRecursive=false because we dont need to include folders
+ new RegExp(
+ '[^_]' + // dont match names started with '_'
+ `(${editorModules.join('|')})` + // module names pattern: (events.js|ui.js|...)
+ '$' // at the end of path
+ )
+ ),
+
+ /**
+ * Automatically load global visible modules
+ * instead of having to import/require them everywhere.
+ */
+ new webpack.ProvidePlugin({
+ '_': 'utils',
+ '$': 'dom',
+ 'Module': './../__module.ts',
+ }),
+
+ /** Минифицируем CSS и JS */
+ // new webpack.optimize.UglifyJsPlugin({
+ /** Disable warning messages. Cant disable uglify for 3rd party libs such as html-janitor */
+ // compress: {
+ // warnings: false
+ // }
+ // }),
+
+ /** Block biuld if errors found */
+ // new webpack.NoErrorsPlugin(),
+
+ ],
+
+ module : {
+ rules : [
+ {
+ test: /\.ts$/,
+ use: [
+ babelLoader,
+ {
+ loader: 'ts-loader'
+ },
+ {
+ loader: 'tslint-loader',
+ }
+ ]
+ },
+ {
+ test : /\.js$/,
+ use: [
+ babelLoader,
+ {
+ loader: 'eslint-loader?fix=true&esModules=true',
+ }
+ ],
+ exclude: [
+ /(node_modules|build)/, // dont need to look in '/build' to prevent analyse __tmp_babel_helper.js
+ /src[\\\/]components[\\\/]tools/
+ ]
+ },
+ {
+ test: /\.css$/,
+ exclude: /node_modules/,
+ use: [
+ {
+ loader: 'css-loader',
+ options: {
+ // minimize: 1,
+ importLoaders: 1
+ }
+ },
+ 'postcss-loader'
+ ]
+ },
+ {
+ test: /\.(svg)$/,
+ use: [
+ {
+ loader: 'raw-loader',
+ }
+ ]
+ }
+ ]
+ },
+ optimization: {
+ minimize: true
+ },
+};
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 000000000..4d196324f
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,6048 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@codexteam/shortcuts@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@codexteam/shortcuts/-/shortcuts-1.0.0.tgz#9d66a7c00c93be05b7940d46d2a82af442e8b46d"
+
+"@csstools/convert-colors@^1.4.0":
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7"
+
+"@mrmlnc/readdir-enhanced@^2.2.1":
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
+ dependencies:
+ call-me-maybe "^1.0.1"
+ glob-to-regexp "^0.3.0"
+
+"@nodelib/fs.stat@^1.0.1":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.0.tgz#50c1e2260ac0ed9439a181de3725a0168d59c48a"
+
+"@webassemblyjs/ast@1.5.13":
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.5.13.tgz#81155a570bd5803a30ec31436bc2c9c0ede38f25"
+ dependencies:
+ "@webassemblyjs/helper-module-context" "1.5.13"
+ "@webassemblyjs/helper-wasm-bytecode" "1.5.13"
+ "@webassemblyjs/wast-parser" "1.5.13"
+ debug "^3.1.0"
+ mamacro "^0.0.3"
+
+"@webassemblyjs/floating-point-hex-parser@1.5.13":
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.5.13.tgz#29ce0baa97411f70e8cce68ce9c0f9d819a4e298"
+
+"@webassemblyjs/helper-api-error@1.5.13":
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.5.13.tgz#e49b051d67ee19a56e29b9aa8bd949b5b4442a59"
+
+"@webassemblyjs/helper-buffer@1.5.13":
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.5.13.tgz#873bb0a1b46449231137c1262ddfd05695195a1e"
+ dependencies:
+ debug "^3.1.0"
+
+"@webassemblyjs/helper-code-frame@1.5.13":
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.5.13.tgz#1bd2181b6a0be14e004f0fe9f5a660d265362b58"
+ dependencies:
+ "@webassemblyjs/wast-printer" "1.5.13"
+
+"@webassemblyjs/helper-fsm@1.5.13":
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.5.13.tgz#cdf3d9d33005d543a5c5e5adaabf679ffa8db924"
+
+"@webassemblyjs/helper-module-context@1.5.13":
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.5.13.tgz#dc29ddfb51ed657655286f94a5d72d8a489147c5"
+ dependencies:
+ debug "^3.1.0"
+ mamacro "^0.0.3"
+
+"@webassemblyjs/helper-wasm-bytecode@1.5.13":
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.5.13.tgz#03245817f0a762382e61733146f5773def15a747"
+
+"@webassemblyjs/helper-wasm-section@1.5.13":
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.5.13.tgz#efc76f44a10d3073b584b43c38a179df173d5c7d"
+ dependencies:
+ "@webassemblyjs/ast" "1.5.13"
+ "@webassemblyjs/helper-buffer" "1.5.13"
+ "@webassemblyjs/helper-wasm-bytecode" "1.5.13"
+ "@webassemblyjs/wasm-gen" "1.5.13"
+ debug "^3.1.0"
+
+"@webassemblyjs/ieee754@1.5.13":
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.5.13.tgz#573e97c8c12e4eebb316ca5fde0203ddd90b0364"
+ dependencies:
+ ieee754 "^1.1.11"
+
+"@webassemblyjs/leb128@1.5.13":
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.5.13.tgz#ab52ebab9cec283c1c1897ac1da833a04a3f4cee"
+ dependencies:
+ long "4.0.0"
+
+"@webassemblyjs/utf8@1.5.13":
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.5.13.tgz#6b53d2cd861cf94fa99c1f12779dde692fbc2469"
+
+"@webassemblyjs/wasm-edit@1.5.13":
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.5.13.tgz#c9cef5664c245cf11b3b3a73110c9155831724a8"
+ dependencies:
+ "@webassemblyjs/ast" "1.5.13"
+ "@webassemblyjs/helper-buffer" "1.5.13"
+ "@webassemblyjs/helper-wasm-bytecode" "1.5.13"
+ "@webassemblyjs/helper-wasm-section" "1.5.13"
+ "@webassemblyjs/wasm-gen" "1.5.13"
+ "@webassemblyjs/wasm-opt" "1.5.13"
+ "@webassemblyjs/wasm-parser" "1.5.13"
+ "@webassemblyjs/wast-printer" "1.5.13"
+ debug "^3.1.0"
+
+"@webassemblyjs/wasm-gen@1.5.13":
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.5.13.tgz#8e6ea113c4b432fa66540189e79b16d7a140700e"
+ dependencies:
+ "@webassemblyjs/ast" "1.5.13"
+ "@webassemblyjs/helper-wasm-bytecode" "1.5.13"
+ "@webassemblyjs/ieee754" "1.5.13"
+ "@webassemblyjs/leb128" "1.5.13"
+ "@webassemblyjs/utf8" "1.5.13"
+
+"@webassemblyjs/wasm-opt@1.5.13":
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.5.13.tgz#147aad7717a7ee4211c36b21a5f4c30dddf33138"
+ dependencies:
+ "@webassemblyjs/ast" "1.5.13"
+ "@webassemblyjs/helper-buffer" "1.5.13"
+ "@webassemblyjs/wasm-gen" "1.5.13"
+ "@webassemblyjs/wasm-parser" "1.5.13"
+ debug "^3.1.0"
+
+"@webassemblyjs/wasm-parser@1.5.13":
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.5.13.tgz#6f46516c5bb23904fbdf58009233c2dd8a54c72f"
+ dependencies:
+ "@webassemblyjs/ast" "1.5.13"
+ "@webassemblyjs/helper-api-error" "1.5.13"
+ "@webassemblyjs/helper-wasm-bytecode" "1.5.13"
+ "@webassemblyjs/ieee754" "1.5.13"
+ "@webassemblyjs/leb128" "1.5.13"
+ "@webassemblyjs/utf8" "1.5.13"
+
+"@webassemblyjs/wast-parser@1.5.13":
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.5.13.tgz#5727a705d397ae6a3ae99d7f5460acf2ec646eea"
+ dependencies:
+ "@webassemblyjs/ast" "1.5.13"
+ "@webassemblyjs/floating-point-hex-parser" "1.5.13"
+ "@webassemblyjs/helper-api-error" "1.5.13"
+ "@webassemblyjs/helper-code-frame" "1.5.13"
+ "@webassemblyjs/helper-fsm" "1.5.13"
+ long "^3.2.0"
+ mamacro "^0.0.3"
+
+"@webassemblyjs/wast-printer@1.5.13":
+ version "1.5.13"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.5.13.tgz#bb34d528c14b4f579e7ec11e793ec50ad7cd7c95"
+ dependencies:
+ "@webassemblyjs/ast" "1.5.13"
+ "@webassemblyjs/wast-parser" "1.5.13"
+ long "^3.2.0"
+
+abbrev@1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
+
+acorn-dynamic-import@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278"
+ dependencies:
+ acorn "^5.0.0"
+
+acorn-jsx@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
+ dependencies:
+ acorn "^3.0.4"
+
+acorn@^3.0.4:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
+
+acorn@^5.0.0, acorn@^5.5.0, acorn@^5.6.2:
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8"
+
+ajv-keywords@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762"
+
+ajv-keywords@^3.0.0, ajv-keywords@^3.1.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a"
+
+ajv@^5.0.0, ajv@^5.2.3, ajv@^5.3.0:
+ version "5.5.2"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
+ dependencies:
+ co "^4.6.0"
+ fast-deep-equal "^1.0.0"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.3.0"
+
+ajv@^6.0.1, ajv@^6.1.0:
+ version "6.5.2"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.2.tgz#678495f9b82f7cca6be248dd92f59bff5e1f4360"
+ dependencies:
+ fast-deep-equal "^2.0.1"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.4.1"
+ uri-js "^4.2.1"
+
+alphanum-sort@^1.0.1, alphanum-sort@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
+
+ansi-escapes@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30"
+
+ansi-regex@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+
+ansi-regex@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
+
+ansi-styles@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+
+ansi-styles@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ dependencies:
+ color-convert "^1.9.0"
+
+any-promise@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-0.1.0.tgz#830b680aa7e56f33451d4b049f3bd8044498ee27"
+
+anymatch@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
+ dependencies:
+ micromatch "^3.1.4"
+ normalize-path "^2.1.1"
+
+aproba@^1.0.3, aproba@^1.1.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
+
+are-we-there-yet@~1.1.2:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
+ dependencies:
+ delegates "^1.0.0"
+ readable-stream "^2.0.6"
+
+argparse@^1.0.7:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+ dependencies:
+ sprintf-js "~1.0.2"
+
+arr-diff@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+ dependencies:
+ arr-flatten "^1.0.1"
+
+arr-diff@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
+
+arr-flatten@^1.0.1, arr-flatten@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
+
+arr-union@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
+
+array-find-index@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
+
+array-iterate@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/array-iterate/-/array-iterate-1.1.2.tgz#f66a57e84426f8097f4197fbb6c051b8e5cdf7d8"
+
+array-union@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
+ dependencies:
+ array-uniq "^1.0.1"
+
+array-uniq@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
+
+array-unique@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+
+array-unique@^0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
+
+arrify@^1.0.0, arrify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+
+asn1.js@^4.0.0:
+ version "4.10.1"
+ resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0"
+ dependencies:
+ bn.js "^4.0.0"
+ inherits "^2.0.1"
+ minimalistic-assert "^1.0.0"
+
+assert@^1.1.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
+ dependencies:
+ util "0.10.3"
+
+assign-symbols@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
+
+async-each@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
+
+async@^1.3.0:
+ version "1.5.2"
+ resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
+
+async@^2.4.1:
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610"
+ dependencies:
+ lodash "^4.17.10"
+
+atob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a"
+
+autoprefixer@^6.3.1:
+ version "6.7.7"
+ resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014"
+ dependencies:
+ browserslist "^1.7.6"
+ caniuse-db "^1.0.30000634"
+ normalize-range "^0.1.2"
+ num2fraction "^1.2.2"
+ postcss "^5.2.16"
+ postcss-value-parser "^3.2.3"
+
+autoprefixer@^7.1.1:
+ version "7.2.6"
+ resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-7.2.6.tgz#256672f86f7c735da849c4f07d008abb056067dc"
+ dependencies:
+ browserslist "^2.11.3"
+ caniuse-lite "^1.0.30000805"
+ normalize-range "^0.1.2"
+ num2fraction "^1.2.2"
+ postcss "^6.0.17"
+ postcss-value-parser "^3.2.3"
+
+autoprefixer@^9.0.0:
+ version "9.1.0"
+ resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.1.0.tgz#566a70d1148046b96b31efa08090f1999ffb6d8c"
+ dependencies:
+ browserslist "^4.0.1"
+ caniuse-lite "^1.0.30000872"
+ normalize-range "^0.1.2"
+ num2fraction "^1.2.2"
+ postcss "^7.0.2"
+ postcss-value-parser "^3.2.3"
+
+babel-code-frame@^6.22.0, babel-code-frame@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
+ dependencies:
+ chalk "^1.1.3"
+ esutils "^2.0.2"
+ js-tokens "^3.0.2"
+
+babel-core@^6.26.0, babel-core@^6.26.3:
+ version "6.26.3"
+ resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207"
+ dependencies:
+ babel-code-frame "^6.26.0"
+ babel-generator "^6.26.0"
+ babel-helpers "^6.24.1"
+ babel-messages "^6.23.0"
+ babel-register "^6.26.0"
+ babel-runtime "^6.26.0"
+ babel-template "^6.26.0"
+ babel-traverse "^6.26.0"
+ babel-types "^6.26.0"
+ babylon "^6.18.0"
+ convert-source-map "^1.5.1"
+ debug "^2.6.9"
+ json5 "^0.5.1"
+ lodash "^4.17.4"
+ minimatch "^3.0.4"
+ path-is-absolute "^1.0.1"
+ private "^0.1.8"
+ slash "^1.0.0"
+ source-map "^0.5.7"
+
+babel-generator@^6.26.0:
+ version "6.26.1"
+ resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90"
+ dependencies:
+ babel-messages "^6.23.0"
+ babel-runtime "^6.26.0"
+ babel-types "^6.26.0"
+ detect-indent "^4.0.0"
+ jsesc "^1.3.0"
+ lodash "^4.17.4"
+ source-map "^0.5.7"
+ trim-right "^1.0.1"
+
+babel-helper-bindify-decorators@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz#14c19e5f142d7b47f19a52431e52b1ccbc40a330"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-helper-builder-binary-assignment-operator-visitor@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664"
+ dependencies:
+ babel-helper-explode-assignable-expression "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-helper-call-delegate@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d"
+ dependencies:
+ babel-helper-hoist-variables "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-helper-define-map@^6.24.1:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f"
+ dependencies:
+ babel-helper-function-name "^6.24.1"
+ babel-runtime "^6.26.0"
+ babel-types "^6.26.0"
+ lodash "^4.17.4"
+
+babel-helper-explode-assignable-expression@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-helper-explode-class@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb"
+ dependencies:
+ babel-helper-bindify-decorators "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-helper-function-name@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9"
+ dependencies:
+ babel-helper-get-function-arity "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-helper-get-function-arity@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-helper-hoist-variables@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-helper-optimise-call-expression@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-helper-regex@^6.24.1:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72"
+ dependencies:
+ babel-runtime "^6.26.0"
+ babel-types "^6.26.0"
+ lodash "^4.17.4"
+
+babel-helper-remap-async-to-generator@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b"
+ dependencies:
+ babel-helper-function-name "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-helper-replace-supers@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a"
+ dependencies:
+ babel-helper-optimise-call-expression "^6.24.1"
+ babel-messages "^6.23.0"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-helpers@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+
+babel-loader@^7.1.5:
+ version "7.1.5"
+ resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.5.tgz#e3ee0cd7394aa557e013b02d3e492bfd07aa6d68"
+ dependencies:
+ find-cache-dir "^1.0.0"
+ loader-utils "^1.0.2"
+ mkdirp "^0.5.1"
+
+babel-messages@^6.23.0:
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-add-module-exports@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-0.2.1.tgz#9ae9a1f4a8dc67f0cdec4f4aeda1e43a5ff65e25"
+
+babel-plugin-check-es2015-constants@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-class-display-name@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-class-display-name/-/babel-plugin-class-display-name-2.1.0.tgz#198ff12b9eabd33e011ee13f2f9898985608b4d1"
+
+babel-plugin-syntax-async-functions@^6.8.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95"
+
+babel-plugin-syntax-async-generators@^6.5.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a"
+
+babel-plugin-syntax-class-constructor-call@^6.18.0:
+ version "6.18.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz#9cb9d39fe43c8600bec8146456ddcbd4e1a76416"
+
+babel-plugin-syntax-class-properties@^6.8.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de"
+
+babel-plugin-syntax-decorators@^6.13.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b"
+
+babel-plugin-syntax-do-expressions@^6.8.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz#5747756139aa26d390d09410b03744ba07e4796d"
+
+babel-plugin-syntax-dynamic-import@^6.18.0:
+ version "6.18.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da"
+
+babel-plugin-syntax-exponentiation-operator@^6.8.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de"
+
+babel-plugin-syntax-export-extensions@^6.8.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721"
+
+babel-plugin-syntax-function-bind@^6.8.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz#48c495f177bdf31a981e732f55adc0bdd2601f46"
+
+babel-plugin-syntax-object-rest-spread@^6.8.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5"
+
+babel-plugin-syntax-trailing-function-commas@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3"
+
+babel-plugin-transform-async-generator-functions@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db"
+ dependencies:
+ babel-helper-remap-async-to-generator "^6.24.1"
+ babel-plugin-syntax-async-generators "^6.5.0"
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761"
+ dependencies:
+ babel-helper-remap-async-to-generator "^6.24.1"
+ babel-plugin-syntax-async-functions "^6.8.0"
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-class-constructor-call@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz#80dc285505ac067dcb8d6c65e2f6f11ab7765ef9"
+ dependencies:
+ babel-plugin-syntax-class-constructor-call "^6.18.0"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+
+babel-plugin-transform-class-properties@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac"
+ dependencies:
+ babel-helper-function-name "^6.24.1"
+ babel-plugin-syntax-class-properties "^6.8.0"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+
+babel-plugin-transform-decorators@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz#788013d8f8c6b5222bdf7b344390dfd77569e24d"
+ dependencies:
+ babel-helper-explode-class "^6.24.1"
+ babel-plugin-syntax-decorators "^6.13.0"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-plugin-transform-do-expressions@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-do-expressions/-/babel-plugin-transform-do-expressions-6.22.0.tgz#28ccaf92812d949c2cd1281f690c8fdc468ae9bb"
+ dependencies:
+ babel-plugin-syntax-do-expressions "^6.8.0"
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-arrow-functions@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-block-scoped-functions@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-block-scoping@^6.23.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f"
+ dependencies:
+ babel-runtime "^6.26.0"
+ babel-template "^6.26.0"
+ babel-traverse "^6.26.0"
+ babel-types "^6.26.0"
+ lodash "^4.17.4"
+
+babel-plugin-transform-es2015-classes@^6.23.0:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db"
+ dependencies:
+ babel-helper-define-map "^6.24.1"
+ babel-helper-function-name "^6.24.1"
+ babel-helper-optimise-call-expression "^6.24.1"
+ babel-helper-replace-supers "^6.24.1"
+ babel-messages "^6.23.0"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-plugin-transform-es2015-computed-properties@^6.22.0:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+
+babel-plugin-transform-es2015-destructuring@^6.23.0:
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-duplicate-keys@^6.22.0:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-plugin-transform-es2015-for-of@^6.23.0:
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-function-name@^6.22.0:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b"
+ dependencies:
+ babel-helper-function-name "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-plugin-transform-es2015-literals@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154"
+ dependencies:
+ babel-plugin-transform-es2015-modules-commonjs "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+
+babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1:
+ version "6.26.2"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3"
+ dependencies:
+ babel-plugin-transform-strict-mode "^6.24.1"
+ babel-runtime "^6.26.0"
+ babel-template "^6.26.0"
+ babel-types "^6.26.0"
+
+babel-plugin-transform-es2015-modules-systemjs@^6.23.0:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23"
+ dependencies:
+ babel-helper-hoist-variables "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+
+babel-plugin-transform-es2015-modules-umd@^6.23.0:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468"
+ dependencies:
+ babel-plugin-transform-es2015-modules-amd "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+
+babel-plugin-transform-es2015-object-super@^6.22.0:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d"
+ dependencies:
+ babel-helper-replace-supers "^6.24.1"
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-parameters@^6.23.0:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b"
+ dependencies:
+ babel-helper-call-delegate "^6.24.1"
+ babel-helper-get-function-arity "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-plugin-transform-es2015-shorthand-properties@^6.22.0:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-plugin-transform-es2015-spread@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-sticky-regex@^6.22.0:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc"
+ dependencies:
+ babel-helper-regex "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-plugin-transform-es2015-template-literals@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-typeof-symbol@^6.23.0:
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372"
+ dependencies:
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-unicode-regex@^6.22.0:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9"
+ dependencies:
+ babel-helper-regex "^6.24.1"
+ babel-runtime "^6.22.0"
+ regexpu-core "^2.0.0"
+
+babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-exponentiation-operator@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e"
+ dependencies:
+ babel-helper-builder-binary-assignment-operator-visitor "^6.24.1"
+ babel-plugin-syntax-exponentiation-operator "^6.8.0"
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-export-extensions@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz#53738b47e75e8218589eea946cbbd39109bbe653"
+ dependencies:
+ babel-plugin-syntax-export-extensions "^6.8.0"
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-function-bind@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-function-bind/-/babel-plugin-transform-function-bind-6.22.0.tgz#c6fb8e96ac296a310b8cf8ea401462407ddf6a97"
+ dependencies:
+ babel-plugin-syntax-function-bind "^6.8.0"
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-object-rest-spread@^6.22.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06"
+ dependencies:
+ babel-plugin-syntax-object-rest-spread "^6.8.0"
+ babel-runtime "^6.26.0"
+
+babel-plugin-transform-regenerator@^6.22.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f"
+ dependencies:
+ regenerator-transform "^0.10.0"
+
+babel-plugin-transform-strict-mode@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
+babel-polyfill@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153"
+ dependencies:
+ babel-runtime "^6.26.0"
+ core-js "^2.5.0"
+ regenerator-runtime "^0.10.5"
+
+babel-preset-env@^1.7.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a"
+ dependencies:
+ babel-plugin-check-es2015-constants "^6.22.0"
+ babel-plugin-syntax-trailing-function-commas "^6.22.0"
+ babel-plugin-transform-async-to-generator "^6.22.0"
+ babel-plugin-transform-es2015-arrow-functions "^6.22.0"
+ babel-plugin-transform-es2015-block-scoped-functions "^6.22.0"
+ babel-plugin-transform-es2015-block-scoping "^6.23.0"
+ babel-plugin-transform-es2015-classes "^6.23.0"
+ babel-plugin-transform-es2015-computed-properties "^6.22.0"
+ babel-plugin-transform-es2015-destructuring "^6.23.0"
+ babel-plugin-transform-es2015-duplicate-keys "^6.22.0"
+ babel-plugin-transform-es2015-for-of "^6.23.0"
+ babel-plugin-transform-es2015-function-name "^6.22.0"
+ babel-plugin-transform-es2015-literals "^6.22.0"
+ babel-plugin-transform-es2015-modules-amd "^6.22.0"
+ babel-plugin-transform-es2015-modules-commonjs "^6.23.0"
+ babel-plugin-transform-es2015-modules-systemjs "^6.23.0"
+ babel-plugin-transform-es2015-modules-umd "^6.23.0"
+ babel-plugin-transform-es2015-object-super "^6.22.0"
+ babel-plugin-transform-es2015-parameters "^6.23.0"
+ babel-plugin-transform-es2015-shorthand-properties "^6.22.0"
+ babel-plugin-transform-es2015-spread "^6.22.0"
+ babel-plugin-transform-es2015-sticky-regex "^6.22.0"
+ babel-plugin-transform-es2015-template-literals "^6.22.0"
+ babel-plugin-transform-es2015-typeof-symbol "^6.23.0"
+ babel-plugin-transform-es2015-unicode-regex "^6.22.0"
+ babel-plugin-transform-exponentiation-operator "^6.22.0"
+ babel-plugin-transform-regenerator "^6.22.0"
+ browserslist "^3.2.6"
+ invariant "^2.2.2"
+ semver "^5.3.0"
+
+babel-preset-stage-0@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-stage-0/-/babel-preset-stage-0-6.24.1.tgz#5642d15042f91384d7e5af8bc88b1db95b039e6a"
+ dependencies:
+ babel-plugin-transform-do-expressions "^6.22.0"
+ babel-plugin-transform-function-bind "^6.22.0"
+ babel-preset-stage-1 "^6.24.1"
+
+babel-preset-stage-1@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz#7692cd7dcd6849907e6ae4a0a85589cfb9e2bfb0"
+ dependencies:
+ babel-plugin-transform-class-constructor-call "^6.24.1"
+ babel-plugin-transform-export-extensions "^6.22.0"
+ babel-preset-stage-2 "^6.24.1"
+
+babel-preset-stage-2@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz#d9e2960fb3d71187f0e64eec62bc07767219bdc1"
+ dependencies:
+ babel-plugin-syntax-dynamic-import "^6.18.0"
+ babel-plugin-transform-class-properties "^6.24.1"
+ babel-plugin-transform-decorators "^6.24.1"
+ babel-preset-stage-3 "^6.24.1"
+
+babel-preset-stage-3@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz#836ada0a9e7a7fa37cb138fb9326f87934a48395"
+ dependencies:
+ babel-plugin-syntax-trailing-function-commas "^6.22.0"
+ babel-plugin-transform-async-generator-functions "^6.24.1"
+ babel-plugin-transform-async-to-generator "^6.24.1"
+ babel-plugin-transform-exponentiation-operator "^6.24.1"
+ babel-plugin-transform-object-rest-spread "^6.22.0"
+
+babel-register@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071"
+ dependencies:
+ babel-core "^6.26.0"
+ babel-runtime "^6.26.0"
+ core-js "^2.5.0"
+ home-or-tmp "^2.0.0"
+ lodash "^4.17.4"
+ mkdirp "^0.5.1"
+ source-map-support "^0.4.15"
+
+babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
+ dependencies:
+ core-js "^2.4.0"
+ regenerator-runtime "^0.11.0"
+
+babel-template@^6.24.1, babel-template@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02"
+ dependencies:
+ babel-runtime "^6.26.0"
+ babel-traverse "^6.26.0"
+ babel-types "^6.26.0"
+ babylon "^6.18.0"
+ lodash "^4.17.4"
+
+babel-traverse@^6.24.1, babel-traverse@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee"
+ dependencies:
+ babel-code-frame "^6.26.0"
+ babel-messages "^6.23.0"
+ babel-runtime "^6.26.0"
+ babel-types "^6.26.0"
+ babylon "^6.18.0"
+ debug "^2.6.8"
+ globals "^9.18.0"
+ invariant "^2.2.2"
+ lodash "^4.17.4"
+
+babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497"
+ dependencies:
+ babel-runtime "^6.26.0"
+ esutils "^2.0.2"
+ lodash "^4.17.4"
+ to-fast-properties "^1.0.3"
+
+babylon@^6.18.0:
+ version "6.18.0"
+ resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
+
+bail@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.3.tgz#63cfb9ddbac829b02a3128cd53224be78e6c21a3"
+
+balanced-match@0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.1.0.tgz#b504bd05869b39259dd0c5efc35d843176dccc4a"
+
+balanced-match@^0.4.2:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
+
+balanced-match@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+
+base64-js@^1.0.2:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
+
+base@^0.11.1:
+ version "0.11.2"
+ resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
+ dependencies:
+ cache-base "^1.0.1"
+ class-utils "^0.3.5"
+ component-emitter "^1.2.1"
+ define-property "^1.0.0"
+ isobject "^3.0.1"
+ mixin-deep "^1.2.0"
+ pascalcase "^0.1.1"
+
+big.js@^3.1.3:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
+
+binary-extensions@^1.0.0:
+ version "1.11.0"
+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205"
+
+bluebird@^3.5.1:
+ version "3.5.1"
+ resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9"
+
+bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
+ version "4.11.8"
+ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
+
+boolbase@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+braces@^1.8.2:
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+ dependencies:
+ expand-range "^1.8.1"
+ preserve "^0.2.0"
+ repeat-element "^1.1.2"
+
+braces@^2.3.0, braces@^2.3.1:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
+ dependencies:
+ arr-flatten "^1.1.0"
+ array-unique "^0.3.2"
+ extend-shallow "^2.0.1"
+ fill-range "^4.0.0"
+ isobject "^3.0.1"
+ repeat-element "^1.1.2"
+ snapdragon "^0.8.1"
+ snapdragon-node "^2.0.1"
+ split-string "^3.0.2"
+ to-regex "^3.0.1"
+
+brorand@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
+
+browserify-aes@^1.0.0, browserify-aes@^1.0.4:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48"
+ dependencies:
+ buffer-xor "^1.0.3"
+ cipher-base "^1.0.0"
+ create-hash "^1.1.0"
+ evp_bytestokey "^1.0.3"
+ inherits "^2.0.1"
+ safe-buffer "^5.0.1"
+
+browserify-cipher@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0"
+ dependencies:
+ browserify-aes "^1.0.4"
+ browserify-des "^1.0.0"
+ evp_bytestokey "^1.0.0"
+
+browserify-des@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c"
+ dependencies:
+ cipher-base "^1.0.1"
+ des.js "^1.0.0"
+ inherits "^2.0.1"
+ safe-buffer "^5.1.2"
+
+browserify-rsa@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524"
+ dependencies:
+ bn.js "^4.1.0"
+ randombytes "^2.0.1"
+
+browserify-sign@^4.0.0:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298"
+ dependencies:
+ bn.js "^4.1.1"
+ browserify-rsa "^4.0.0"
+ create-hash "^1.1.0"
+ create-hmac "^1.1.2"
+ elliptic "^6.0.0"
+ inherits "^2.0.1"
+ parse-asn1 "^5.0.0"
+
+browserify-zlib@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f"
+ dependencies:
+ pako "~1.0.5"
+
+browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6:
+ version "1.7.7"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9"
+ dependencies:
+ caniuse-db "^1.0.30000639"
+ electron-to-chromium "^1.2.7"
+
+browserslist@^2.0.0, browserslist@^2.11.3:
+ version "2.11.3"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.11.3.tgz#fe36167aed1bbcde4827ebfe71347a2cc70b99b2"
+ dependencies:
+ caniuse-lite "^1.0.30000792"
+ electron-to-chromium "^1.3.30"
+
+browserslist@^3.2.6:
+ version "3.2.8"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6"
+ dependencies:
+ caniuse-lite "^1.0.30000844"
+ electron-to-chromium "^1.3.47"
+
+browserslist@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.0.1.tgz#61c05ce2a5843c7d96166408bc23d58b5416e818"
+ dependencies:
+ caniuse-lite "^1.0.30000865"
+ electron-to-chromium "^1.3.52"
+ node-releases "^1.0.0-alpha.10"
+
+buffer-from@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
+
+buffer-xor@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
+
+buffer@^4.3.0:
+ version "4.9.1"
+ resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
+ dependencies:
+ base64-js "^1.0.2"
+ ieee754 "^1.1.4"
+ isarray "^1.0.0"
+
+builtin-modules@^1.0.0, builtin-modules@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
+
+builtin-status-codes@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
+
+cacache@^10.0.4:
+ version "10.0.4"
+ resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460"
+ dependencies:
+ bluebird "^3.5.1"
+ chownr "^1.0.1"
+ glob "^7.1.2"
+ graceful-fs "^4.1.11"
+ lru-cache "^4.1.1"
+ mississippi "^2.0.0"
+ mkdirp "^0.5.1"
+ move-concurrently "^1.0.1"
+ promise-inflight "^1.0.1"
+ rimraf "^2.6.2"
+ ssri "^5.2.4"
+ unique-filename "^1.1.0"
+ y18n "^4.0.0"
+
+cache-base@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
+ dependencies:
+ collection-visit "^1.0.0"
+ component-emitter "^1.2.1"
+ get-value "^2.0.6"
+ has-value "^1.0.0"
+ isobject "^3.0.1"
+ set-value "^2.0.0"
+ to-object-path "^0.3.0"
+ union-value "^1.0.0"
+ unset-value "^1.0.0"
+
+call-me-maybe@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
+
+caller-path@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f"
+ dependencies:
+ callsites "^0.2.0"
+
+callsites@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca"
+
+camelcase-keys@^4.0.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-4.2.0.tgz#a2aa5fb1af688758259c32c141426d78923b9b77"
+ dependencies:
+ camelcase "^4.1.0"
+ map-obj "^2.0.0"
+ quick-lru "^1.0.0"
+
+camelcase@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
+
+caniuse-api@^1.5.2:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c"
+ dependencies:
+ browserslist "^1.3.6"
+ caniuse-db "^1.0.30000529"
+ lodash.memoize "^4.1.2"
+ lodash.uniq "^4.5.0"
+
+caniuse-api@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-2.0.0.tgz#b1ddb5a5966b16f48dc4998444d4bbc6c7d9d834"
+ dependencies:
+ browserslist "^2.0.0"
+ caniuse-lite "^1.0.0"
+ lodash.memoize "^4.1.2"
+ lodash.uniq "^4.5.0"
+
+caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
+ version "1.0.30000874"
+ resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000874.tgz#49edc0262efdc6c49d4d962bb16d1f0c790fa44e"
+
+caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000792, caniuse-lite@^1.0.30000805, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000865, caniuse-lite@^1.0.30000872:
+ version "1.0.30000874"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000874.tgz#a641b1f1c420d58d9b132920ef6ba87bbdcd2223"
+
+ccount@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.0.3.tgz#f1cec43f332e2ea5a569fd46f9f5bde4e6102aff"
+
+chalk@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+ dependencies:
+ ansi-styles "^2.2.1"
+ escape-string-regexp "^1.0.2"
+ has-ansi "^2.0.0"
+ strip-ansi "^3.0.0"
+ supports-color "^2.0.0"
+
+chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
+character-entities-html4@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.2.tgz#c44fdde3ce66b52e8d321d6c1bf46101f0150610"
+
+character-entities-legacy@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.2.tgz#7c6defb81648498222c9855309953d05f4d63a9c"
+
+character-entities@^1.0.0:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.2.tgz#58c8f371c0774ef0ba9b2aca5f00d8f100e6e363"
+
+character-reference-invalid@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.2.tgz#21e421ad3d84055952dab4a43a04e73cd425d3ed"
+
+chardet@^0.4.0:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2"
+
+chardet@^0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.5.0.tgz#fe3ac73c00c3d865ffcc02a0682e2c20b6a06029"
+
+cheerio@^0.19.0:
+ version "0.19.0"
+ resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.19.0.tgz#772e7015f2ee29965096d71ea4175b75ab354925"
+ dependencies:
+ css-select "~1.0.0"
+ dom-serializer "~0.1.0"
+ entities "~1.1.1"
+ htmlparser2 "~3.8.1"
+ lodash "^3.2.0"
+
+chokidar@^2.0.2:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26"
+ dependencies:
+ anymatch "^2.0.0"
+ async-each "^1.0.0"
+ braces "^2.3.0"
+ glob-parent "^3.1.0"
+ inherits "^2.0.1"
+ is-binary-path "^1.0.0"
+ is-glob "^4.0.0"
+ lodash.debounce "^4.0.8"
+ normalize-path "^2.1.1"
+ path-is-absolute "^1.0.0"
+ readdirp "^2.0.0"
+ upath "^1.0.5"
+ optionalDependencies:
+ fsevents "^1.2.2"
+
+chownr@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181"
+
+chrome-trace-event@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz#45a91bd2c20c9411f0963b5aaeb9a1b95e09cc48"
+ dependencies:
+ tslib "^1.9.0"
+
+cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
+ dependencies:
+ inherits "^2.0.1"
+ safe-buffer "^5.0.1"
+
+circular-json@^0.3.1:
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66"
+
+clap@^1.0.9:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51"
+ dependencies:
+ chalk "^1.1.3"
+
+class-utils@^0.3.5:
+ version "0.3.6"
+ resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
+ dependencies:
+ arr-union "^3.1.0"
+ define-property "^0.2.5"
+ isobject "^3.0.0"
+ static-extend "^0.1.1"
+
+cli-cursor@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
+ dependencies:
+ restore-cursor "^2.0.0"
+
+cli-width@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
+
+cliui@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49"
+ dependencies:
+ string-width "^2.1.1"
+ strip-ansi "^4.0.0"
+ wrap-ansi "^2.0.0"
+
+clone-regexp@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/clone-regexp/-/clone-regexp-1.0.1.tgz#051805cd33173375d82118fc0918606da39fd60f"
+ dependencies:
+ is-regexp "^1.0.0"
+ is-supported-regexp-flag "^1.0.0"
+
+clone@^1.0.2:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
+
+co@^4.6.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+
+coa@~1.0.1:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.4.tgz#a9ef153660d6a86a8bdec0289a5c684d217432fd"
+ dependencies:
+ q "^1.1.2"
+
+code-point-at@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+
+collapse-white-space@^1.0.2:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.4.tgz#ce05cf49e54c3277ae573036a26851ba430a0091"
+
+collection-visit@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
+ dependencies:
+ map-visit "^1.0.0"
+ object-visit "^1.0.0"
+
+color-convert@^1.3.0, color-convert@^1.8.2, color-convert@^1.9.0, color-convert@^1.9.1:
+ version "1.9.2"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147"
+ dependencies:
+ color-name "1.1.1"
+
+color-name@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689"
+
+color-name@^1.0.0:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+
+color-string@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991"
+ dependencies:
+ color-name "^1.0.0"
+
+color-string@^1.4.0, color-string@^1.5.2:
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc"
+ dependencies:
+ color-name "^1.0.0"
+ simple-swizzle "^0.2.2"
+
+color@^0.11.0:
+ version "0.11.4"
+ resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764"
+ dependencies:
+ clone "^1.0.2"
+ color-convert "^1.3.0"
+ color-string "^0.3.0"
+
+color@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/color/-/color-1.0.3.tgz#e48e832d85f14ef694fb468811c2d5cfe729b55d"
+ dependencies:
+ color-convert "^1.8.2"
+ color-string "^1.4.0"
+
+color@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/color/-/color-2.0.1.tgz#e4ed78a3c4603d0891eba5430b04b86314f4c839"
+ dependencies:
+ color-convert "^1.9.1"
+ color-string "^1.5.2"
+
+colormin@^1.0.5:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133"
+ dependencies:
+ color "^0.11.0"
+ css-color-names "0.0.4"
+ has "^1.0.1"
+
+colors@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
+
+commander@^2.12.1, commander@^2.8.1:
+ version "2.17.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.0.tgz#9d07b25e2a6f198b76d8b756a0e8a9604a6a1a60"
+
+commander@~2.13.0:
+ version "2.13.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c"
+
+commondir@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
+
+component-emitter@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+
+concat-stream@^1.5.0, concat-stream@^1.6.0:
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
+ dependencies:
+ buffer-from "^1.0.0"
+ inherits "^2.0.3"
+ readable-stream "^2.2.2"
+ typedarray "^0.0.6"
+
+console-browserify@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
+ dependencies:
+ date-now "^0.1.4"
+
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+
+constants-browserify@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
+
+convert-source-map@^1.5.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5"
+
+copy-concurrently@^1.0.0:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0"
+ dependencies:
+ aproba "^1.1.1"
+ fs-write-stream-atomic "^1.0.8"
+ iferr "^0.1.5"
+ mkdirp "^0.5.1"
+ rimraf "^2.5.4"
+ run-queue "^1.0.0"
+
+copy-descriptor@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
+
+core-js@^2.4.0, core-js@^2.5.0:
+ version "2.5.7"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e"
+
+core-util-is@~1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+
+cosmiconfig@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-4.0.0.tgz#760391549580bbd2df1e562bc177b13c290972dc"
+ dependencies:
+ is-directory "^0.3.1"
+ js-yaml "^3.9.0"
+ parse-json "^4.0.0"
+ require-from-string "^2.0.1"
+
+cosmiconfig@^5.0.0:
+ version "5.0.5"
+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.0.5.tgz#a809e3c2306891ce17ab70359dc8bdf661fe2cd0"
+ dependencies:
+ is-directory "^0.3.1"
+ js-yaml "^3.9.0"
+ parse-json "^4.0.0"
+
+create-ecdh@^4.0.0:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff"
+ dependencies:
+ bn.js "^4.1.0"
+ elliptic "^6.0.0"
+
+create-hash@^1.1.0, create-hash@^1.1.2:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
+ dependencies:
+ cipher-base "^1.0.1"
+ inherits "^2.0.1"
+ md5.js "^1.3.4"
+ ripemd160 "^2.0.1"
+ sha.js "^2.4.0"
+
+create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff"
+ dependencies:
+ cipher-base "^1.0.3"
+ create-hash "^1.1.0"
+ inherits "^2.0.1"
+ ripemd160 "^2.0.0"
+ safe-buffer "^5.0.1"
+ sha.js "^2.4.8"
+
+cross-spawn@^5.0.1, cross-spawn@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
+ dependencies:
+ lru-cache "^4.0.1"
+ shebang-command "^1.2.0"
+ which "^1.2.9"
+
+cross-spawn@^6.0.5:
+ version "6.0.5"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
+ dependencies:
+ nice-try "^1.0.4"
+ path-key "^2.0.1"
+ semver "^5.5.0"
+ shebang-command "^1.2.0"
+ which "^1.2.9"
+
+crypto-browserify@^3.11.0:
+ version "3.12.0"
+ resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
+ dependencies:
+ browserify-cipher "^1.0.0"
+ browserify-sign "^4.0.0"
+ create-ecdh "^4.0.0"
+ create-hash "^1.1.0"
+ create-hmac "^1.1.0"
+ diffie-hellman "^5.0.0"
+ inherits "^2.0.1"
+ pbkdf2 "^3.0.3"
+ public-encrypt "^4.0.0"
+ randombytes "^2.0.0"
+ randomfill "^1.0.3"
+
+css-color-function@~1.3.3:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/css-color-function/-/css-color-function-1.3.3.tgz#8ed24c2c0205073339fafa004bc8c141fccb282e"
+ dependencies:
+ balanced-match "0.1.0"
+ color "^0.11.0"
+ debug "^3.1.0"
+ rgb "~0.1.0"
+
+css-color-names@0.0.4:
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
+
+css-loader@^0.28.11:
+ version "0.28.11"
+ resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.11.tgz#c3f9864a700be2711bb5a2462b2389b1a392dab7"
+ dependencies:
+ babel-code-frame "^6.26.0"
+ css-selector-tokenizer "^0.7.0"
+ cssnano "^3.10.0"
+ icss-utils "^2.1.0"
+ loader-utils "^1.0.2"
+ lodash.camelcase "^4.3.0"
+ object-assign "^4.1.1"
+ postcss "^5.0.6"
+ postcss-modules-extract-imports "^1.2.0"
+ postcss-modules-local-by-default "^1.2.0"
+ postcss-modules-scope "^1.1.0"
+ postcss-modules-values "^1.3.0"
+ postcss-value-parser "^3.3.0"
+ source-list-map "^2.0.0"
+
+css-select@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.0.0.tgz#b1121ca51848dd264e2244d058cee254deeb44b0"
+ dependencies:
+ boolbase "~1.0.0"
+ css-what "1.0"
+ domutils "1.4"
+ nth-check "~1.0.0"
+
+css-selector-tokenizer@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86"
+ dependencies:
+ cssesc "^0.1.0"
+ fastparse "^1.1.1"
+ regexpu-core "^1.0.0"
+
+css-unit-converter@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/css-unit-converter/-/css-unit-converter-1.1.1.tgz#d9b9281adcfd8ced935bdbaba83786897f64e996"
+
+css-what@1.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/css-what/-/css-what-1.0.0.tgz#d7cc2df45180666f99d2b14462639469e00f736c"
+
+cssesc@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
+
+cssnano@^3.10.0:
+ version "3.10.0"
+ resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38"
+ dependencies:
+ autoprefixer "^6.3.1"
+ decamelize "^1.1.2"
+ defined "^1.0.0"
+ has "^1.0.1"
+ object-assign "^4.0.1"
+ postcss "^5.0.14"
+ postcss-calc "^5.2.0"
+ postcss-colormin "^2.1.8"
+ postcss-convert-values "^2.3.4"
+ postcss-discard-comments "^2.0.4"
+ postcss-discard-duplicates "^2.0.1"
+ postcss-discard-empty "^2.0.1"
+ postcss-discard-overridden "^0.1.1"
+ postcss-discard-unused "^2.2.1"
+ postcss-filter-plugins "^2.0.0"
+ postcss-merge-idents "^2.1.5"
+ postcss-merge-longhand "^2.0.1"
+ postcss-merge-rules "^2.0.3"
+ postcss-minify-font-values "^1.0.2"
+ postcss-minify-gradients "^1.0.1"
+ postcss-minify-params "^1.0.4"
+ postcss-minify-selectors "^2.0.4"
+ postcss-normalize-charset "^1.1.0"
+ postcss-normalize-url "^3.0.7"
+ postcss-ordered-values "^2.1.0"
+ postcss-reduce-idents "^2.2.2"
+ postcss-reduce-initial "^1.0.0"
+ postcss-reduce-transforms "^1.0.3"
+ postcss-svgo "^2.1.1"
+ postcss-unique-selectors "^2.0.2"
+ postcss-value-parser "^3.2.3"
+ postcss-zindex "^2.0.1"
+
+csso@~2.3.1:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/csso/-/csso-2.3.2.tgz#ddd52c587033f49e94b71fc55569f252e8ff5f85"
+ dependencies:
+ clap "^1.0.9"
+ source-map "^0.5.3"
+
+currently-unhandled@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
+ dependencies:
+ array-find-index "^1.0.1"
+
+cyclist@~0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640"
+
+date-now@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
+
+debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ dependencies:
+ ms "2.0.0"
+
+debug@^3.0.0, debug@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
+ dependencies:
+ ms "2.0.0"
+
+decamelize-keys@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9"
+ dependencies:
+ decamelize "^1.1.0"
+ map-obj "^1.0.0"
+
+decamelize@^1.1.0, decamelize@^1.1.2:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+
+decamelize@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7"
+ dependencies:
+ xregexp "4.0.0"
+
+decode-uri-component@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
+
+deep-extend@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
+
+deep-is@~0.1.3:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+
+define-property@^0.2.5:
+ version "0.2.5"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
+ dependencies:
+ is-descriptor "^0.1.0"
+
+define-property@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
+ dependencies:
+ is-descriptor "^1.0.0"
+
+define-property@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
+ dependencies:
+ is-descriptor "^1.0.2"
+ isobject "^3.0.1"
+
+defined@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
+
+del@^2.0.2:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8"
+ dependencies:
+ globby "^5.0.0"
+ is-path-cwd "^1.0.0"
+ is-path-in-cwd "^1.0.0"
+ object-assign "^4.0.1"
+ pify "^2.0.0"
+ pinkie-promise "^2.0.0"
+ rimraf "^2.2.8"
+
+delegates@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+
+des.js@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc"
+ dependencies:
+ inherits "^2.0.1"
+ minimalistic-assert "^1.0.0"
+
+detect-indent@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
+ dependencies:
+ repeating "^2.0.0"
+
+detect-libc@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
+
+diff@^3.2.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
+
+diffie-hellman@^5.0.0:
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
+ dependencies:
+ bn.js "^4.1.0"
+ miller-rabin "^4.0.0"
+ randombytes "^2.0.0"
+
+dir-glob@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034"
+ dependencies:
+ arrify "^1.0.1"
+ path-type "^3.0.0"
+
+doctrine@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
+ dependencies:
+ esutils "^2.0.2"
+
+dom-serializer@0, dom-serializer@~0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
+ dependencies:
+ domelementtype "~1.1.1"
+ entities "~1.1.1"
+
+domain-browser@^1.1.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
+
+domelementtype@1, domelementtype@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2"
+
+domelementtype@~1.1.1:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b"
+
+domhandler@2.3:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.3.0.tgz#2de59a0822d5027fabff6f032c2b25a2a8abe738"
+ dependencies:
+ domelementtype "1"
+
+domhandler@^2.3.0:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803"
+ dependencies:
+ domelementtype "1"
+
+domutils@1.4:
+ version "1.4.3"
+ resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.4.3.tgz#0865513796c6b306031850e175516baf80b72a6f"
+ dependencies:
+ domelementtype "1"
+
+domutils@1.5:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
+ dependencies:
+ dom-serializer "0"
+ domelementtype "1"
+
+domutils@^1.5.1:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
+ dependencies:
+ dom-serializer "0"
+ domelementtype "1"
+
+dot-prop@^4.1.1:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
+ dependencies:
+ is-obj "^1.0.0"
+
+duplexify@^3.4.2, duplexify@^3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.6.0.tgz#592903f5d80b38d037220541264d69a198fb3410"
+ dependencies:
+ end-of-stream "^1.0.0"
+ inherits "^2.0.1"
+ readable-stream "^2.0.0"
+ stream-shift "^1.0.0"
+
+electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.30, electron-to-chromium@^1.3.47, electron-to-chromium@^1.3.52:
+ version "1.3.55"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.55.tgz#f150e10b20b77d9d41afcca312efe0c3b1a7fdce"
+
+elliptic@^6.0.0:
+ version "6.4.0"
+ resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df"
+ dependencies:
+ bn.js "^4.4.0"
+ brorand "^1.0.1"
+ hash.js "^1.0.0"
+ hmac-drbg "^1.0.0"
+ inherits "^2.0.1"
+ minimalistic-assert "^1.0.0"
+ minimalistic-crypto-utils "^1.0.0"
+
+emojis-list@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
+
+end-of-stream@^1.0.0, end-of-stream@^1.1.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
+ dependencies:
+ once "^1.4.0"
+
+enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f"
+ dependencies:
+ graceful-fs "^4.1.2"
+ memory-fs "^0.4.0"
+ tapable "^1.0.0"
+
+entities@1.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-1.0.0.tgz#b2987aa3821347fcde642b24fdfc9e4fb712bf26"
+
+entities@^1.1.1, entities@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
+
+errno@^0.1.3, errno@~0.1.7:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
+ dependencies:
+ prr "~1.0.1"
+
+error-ex@^1.3.1:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
+ dependencies:
+ is-arrayish "^0.2.1"
+
+es6-promise@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-2.3.0.tgz#96edb9f2fdb01995822b263dd8aadab6748181bc"
+
+escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+
+eslint-loader@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-2.1.0.tgz#61334c548aeb0b8e20ec3a552fb7a88c47261c6a"
+ dependencies:
+ loader-fs-cache "^1.0.0"
+ loader-utils "^1.0.2"
+ object-assign "^4.0.1"
+ object-hash "^1.1.4"
+ rimraf "^2.6.1"
+
+eslint-scope@^3.7.1:
+ version "3.7.3"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.3.tgz#bb507200d3d17f60247636160b4826284b108535"
+ dependencies:
+ esrecurse "^4.1.0"
+ estraverse "^4.1.1"
+
+eslint-scope@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172"
+ dependencies:
+ esrecurse "^4.1.0"
+ estraverse "^4.1.1"
+
+eslint-visitor-keys@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d"
+
+eslint@^4.19.1:
+ version "4.19.1"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300"
+ dependencies:
+ ajv "^5.3.0"
+ babel-code-frame "^6.22.0"
+ chalk "^2.1.0"
+ concat-stream "^1.6.0"
+ cross-spawn "^5.1.0"
+ debug "^3.1.0"
+ doctrine "^2.1.0"
+ eslint-scope "^3.7.1"
+ eslint-visitor-keys "^1.0.0"
+ espree "^3.5.4"
+ esquery "^1.0.0"
+ esutils "^2.0.2"
+ file-entry-cache "^2.0.0"
+ functional-red-black-tree "^1.0.1"
+ glob "^7.1.2"
+ globals "^11.0.1"
+ ignore "^3.3.3"
+ imurmurhash "^0.1.4"
+ inquirer "^3.0.6"
+ is-resolvable "^1.0.0"
+ js-yaml "^3.9.1"
+ json-stable-stringify-without-jsonify "^1.0.1"
+ levn "^0.3.0"
+ lodash "^4.17.4"
+ minimatch "^3.0.2"
+ mkdirp "^0.5.1"
+ natural-compare "^1.4.0"
+ optionator "^0.8.2"
+ path-is-inside "^1.0.2"
+ pluralize "^7.0.0"
+ progress "^2.0.0"
+ regexpp "^1.0.1"
+ require-uncached "^1.0.3"
+ semver "^5.3.0"
+ strip-ansi "^4.0.0"
+ strip-json-comments "~2.0.1"
+ table "4.0.2"
+ text-table "~0.2.0"
+
+espree@^3.5.4:
+ version "3.5.4"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7"
+ dependencies:
+ acorn "^5.5.0"
+ acorn-jsx "^3.0.0"
+
+esprima@^2.6.0:
+ version "2.7.3"
+ resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
+
+esprima@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
+
+esquery@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708"
+ dependencies:
+ estraverse "^4.0.0"
+
+esrecurse@^4.1.0:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
+ dependencies:
+ estraverse "^4.1.0"
+
+estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
+
+esutils@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
+
+events@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
+
+evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02"
+ dependencies:
+ md5.js "^1.3.4"
+ safe-buffer "^5.1.1"
+
+execa@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
+ dependencies:
+ cross-spawn "^5.0.1"
+ get-stream "^3.0.0"
+ is-stream "^1.1.0"
+ npm-run-path "^2.0.0"
+ p-finally "^1.0.0"
+ signal-exit "^3.0.0"
+ strip-eof "^1.0.0"
+
+execall@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/execall/-/execall-1.0.0.tgz#73d0904e395b3cab0658b08d09ec25307f29bb73"
+ dependencies:
+ clone-regexp "^1.0.0"
+
+expand-brackets@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+ dependencies:
+ is-posix-bracket "^0.1.0"
+
+expand-brackets@^2.1.4:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
+ dependencies:
+ debug "^2.3.3"
+ define-property "^0.2.5"
+ extend-shallow "^2.0.1"
+ posix-character-classes "^0.1.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+expand-range@^1.8.1:
+ version "1.8.2"
+ resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+ dependencies:
+ fill-range "^2.1.0"
+
+extend-shallow@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
+ dependencies:
+ is-extendable "^0.1.0"
+
+extend-shallow@^3.0.0, extend-shallow@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
+ dependencies:
+ assign-symbols "^1.0.0"
+ is-extendable "^1.0.1"
+
+extend@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
+
+external-editor@^2.0.4:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5"
+ dependencies:
+ chardet "^0.4.0"
+ iconv-lite "^0.4.17"
+ tmp "^0.0.33"
+
+external-editor@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.0.tgz#dc35c48c6f98a30ca27a20e9687d7f3c77704bb6"
+ dependencies:
+ chardet "^0.5.0"
+ iconv-lite "^0.4.22"
+ tmp "^0.0.33"
+
+extglob@^0.3.1:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+ dependencies:
+ is-extglob "^1.0.0"
+
+extglob@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
+ dependencies:
+ array-unique "^0.3.2"
+ define-property "^1.0.0"
+ expand-brackets "^2.1.4"
+ extend-shallow "^2.0.1"
+ fragment-cache "^0.2.1"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+extract-text-webpack-plugin@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.2.tgz#5f043eaa02f9750a9258b78c0a6e0dc1408fb2f7"
+ dependencies:
+ async "^2.4.1"
+ loader-utils "^1.1.0"
+ schema-utils "^0.3.0"
+ webpack-sources "^1.0.1"
+
+fast-deep-equal@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
+
+fast-deep-equal@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
+
+fast-glob@^2.0.2:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.2.tgz#71723338ac9b4e0e2fff1d6748a2a13d5ed352bf"
+ dependencies:
+ "@mrmlnc/readdir-enhanced" "^2.2.1"
+ "@nodelib/fs.stat" "^1.0.1"
+ glob-parent "^3.1.0"
+ is-glob "^4.0.0"
+ merge2 "^1.2.1"
+ micromatch "^3.1.10"
+
+fast-json-stable-stringify@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
+
+fast-levenshtein@~2.0.4:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+
+fastparse@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8"
+
+figures@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
+ dependencies:
+ escape-string-regexp "^1.0.5"
+
+file-entry-cache@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361"
+ dependencies:
+ flat-cache "^1.2.1"
+ object-assign "^4.0.1"
+
+filename-regex@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
+
+fill-range@^2.1.0:
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565"
+ dependencies:
+ is-number "^2.1.0"
+ isobject "^2.0.0"
+ randomatic "^3.0.0"
+ repeat-element "^1.1.2"
+ repeat-string "^1.5.2"
+
+fill-range@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
+ dependencies:
+ extend-shallow "^2.0.1"
+ is-number "^3.0.0"
+ repeat-string "^1.6.1"
+ to-regex-range "^2.1.0"
+
+find-cache-dir@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9"
+ dependencies:
+ commondir "^1.0.1"
+ mkdirp "^0.5.1"
+ pkg-dir "^1.0.0"
+
+find-cache-dir@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f"
+ dependencies:
+ commondir "^1.0.1"
+ make-dir "^1.0.0"
+ pkg-dir "^2.0.0"
+
+find-up@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+ dependencies:
+ path-exists "^2.0.0"
+ pinkie-promise "^2.0.0"
+
+find-up@^2.0.0, find-up@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
+ dependencies:
+ locate-path "^2.0.0"
+
+find-up@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
+ dependencies:
+ locate-path "^3.0.0"
+
+flat-cache@^1.2.1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481"
+ dependencies:
+ circular-json "^0.3.1"
+ del "^2.0.2"
+ graceful-fs "^4.1.2"
+ write "^0.2.1"
+
+flatten@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
+
+flush-write-stream@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd"
+ dependencies:
+ inherits "^2.0.1"
+ readable-stream "^2.0.4"
+
+for-in@^1.0.1, for-in@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+
+for-own@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
+ dependencies:
+ for-in "^1.0.1"
+
+fragment-cache@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
+ dependencies:
+ map-cache "^0.2.2"
+
+from2@^2.1.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af"
+ dependencies:
+ inherits "^2.0.1"
+ readable-stream "^2.0.0"
+
+fs-minipass@^1.2.5:
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d"
+ dependencies:
+ minipass "^2.2.1"
+
+fs-write-stream-atomic@^1.0.8:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9"
+ dependencies:
+ graceful-fs "^4.1.2"
+ iferr "^0.1.5"
+ imurmurhash "^0.1.4"
+ readable-stream "1 || 2"
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+
+fsevents@^1.2.2:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426"
+ dependencies:
+ nan "^2.9.2"
+ node-pre-gyp "^0.10.0"
+
+function-bind@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+
+functional-red-black-tree@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
+
+gauge@~2.7.3:
+ version "2.7.4"
+ resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
+ dependencies:
+ aproba "^1.0.3"
+ console-control-strings "^1.0.0"
+ has-unicode "^2.0.0"
+ object-assign "^4.1.0"
+ signal-exit "^3.0.0"
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+ wide-align "^1.1.0"
+
+get-caller-file@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
+
+get-stdin@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
+
+get-stream@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
+
+get-value@^2.0.3, get-value@^2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
+
+glob-base@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+ dependencies:
+ glob-parent "^2.0.0"
+ is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+ dependencies:
+ is-glob "^2.0.0"
+
+glob-parent@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
+ dependencies:
+ is-glob "^3.1.0"
+ path-dirname "^1.0.0"
+
+glob-to-regexp@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
+
+glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2:
+ version "7.1.2"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+global-modules-path@^2.1.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/global-modules-path/-/global-modules-path-2.3.0.tgz#b0e2bac6beac39745f7db5c59d26a36a0b94f7dc"
+
+globals@^11.0.1:
+ version "11.7.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673"
+
+globals@^9.18.0:
+ version "9.18.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
+
+globby@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d"
+ dependencies:
+ array-union "^1.0.1"
+ arrify "^1.0.0"
+ glob "^7.0.3"
+ object-assign "^4.0.1"
+ pify "^2.0.0"
+ pinkie-promise "^2.0.0"
+
+globby@^8.0.0:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.1.tgz#b5ad48b8aa80b35b814fc1281ecc851f1d2b5b50"
+ dependencies:
+ array-union "^1.0.1"
+ dir-glob "^2.0.0"
+ fast-glob "^2.0.2"
+ glob "^7.1.2"
+ ignore "^3.3.5"
+ pify "^3.0.0"
+ slash "^1.0.0"
+
+globjoin@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43"
+
+gonzales-pe@4.2.3, gonzales-pe@^4.0.3:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.2.3.tgz#41091703625433285e0aee3aa47829fc1fbeb6f2"
+ dependencies:
+ minimist "1.1.x"
+
+graceful-fs@^4.1.11, graceful-fs@^4.1.2:
+ version "4.1.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+
+has-ansi@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+ dependencies:
+ ansi-regex "^2.0.0"
+
+has-flag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
+
+has-flag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+
+has-unicode@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+
+has-value@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
+ dependencies:
+ get-value "^2.0.3"
+ has-values "^0.1.4"
+ isobject "^2.0.0"
+
+has-value@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
+ dependencies:
+ get-value "^2.0.6"
+ has-values "^1.0.0"
+ isobject "^3.0.0"
+
+has-values@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
+
+has-values@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
+ dependencies:
+ is-number "^3.0.0"
+ kind-of "^4.0.0"
+
+has@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+ dependencies:
+ function-bind "^1.1.1"
+
+hash-base@^3.0.0:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918"
+ dependencies:
+ inherits "^2.0.1"
+ safe-buffer "^5.0.1"
+
+hash.js@^1.0.0, hash.js@^1.0.3:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.5.tgz#e38ab4b85dfb1e0c40fe9265c0e9b54854c23812"
+ dependencies:
+ inherits "^2.0.3"
+ minimalistic-assert "^1.0.1"
+
+hmac-drbg@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
+ dependencies:
+ hash.js "^1.0.3"
+ minimalistic-assert "^1.0.0"
+ minimalistic-crypto-utils "^1.0.1"
+
+home-or-tmp@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
+ dependencies:
+ os-homedir "^1.0.0"
+ os-tmpdir "^1.0.1"
+
+hosted-git-info@^2.1.4:
+ version "2.7.1"
+ resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
+
+html-comment-regex@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e"
+
+html-janitor@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/html-janitor/-/html-janitor-2.0.2.tgz#3f4551d23d1be8554e273f9eada2b617c2b3ab70"
+
+html-tags@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-2.0.0.tgz#10b30a386085f43cede353cc8fa7cb0deeea668b"
+
+htmlparser2@^3.9.2:
+ version "3.9.2"
+ resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338"
+ dependencies:
+ domelementtype "^1.3.0"
+ domhandler "^2.3.0"
+ domutils "^1.5.1"
+ entities "^1.1.1"
+ inherits "^2.0.1"
+ readable-stream "^2.0.2"
+
+htmlparser2@~3.8.1:
+ version "3.8.3"
+ resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.8.3.tgz#996c28b191516a8be86501a7d79757e5c70c1068"
+ dependencies:
+ domelementtype "1"
+ domhandler "2.3"
+ domutils "1.5"
+ entities "1.0"
+ readable-stream "1.1"
+
+https-browserify@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
+
+iconv-lite@^0.4.17, iconv-lite@^0.4.22, iconv-lite@^0.4.4:
+ version "0.4.23"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
+
+icss-replace-symbols@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
+
+icss-utils@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-2.1.0.tgz#83f0a0ec378bf3246178b6c2ad9136f135b1c962"
+ dependencies:
+ postcss "^6.0.1"
+
+ieee754@^1.1.11, ieee754@^1.1.4:
+ version "1.1.12"
+ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b"
+
+iferr@^0.1.5:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501"
+
+ignore-walk@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8"
+ dependencies:
+ minimatch "^3.0.4"
+
+ignore@^3.3.3, ignore@^3.3.5:
+ version "3.3.10"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
+
+ignore@^4.0.0:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.3.tgz#e2d58c9654d75b542529fa28d80ac95b29e4f467"
+
+import-cwd@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"
+ dependencies:
+ import-from "^2.1.0"
+
+import-from@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1"
+ dependencies:
+ resolve-from "^3.0.0"
+
+import-lazy@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-3.1.0.tgz#891279202c8a2280fdbd6674dbd8da1a1dfc67cc"
+
+import-local@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc"
+ dependencies:
+ pkg-dir "^2.0.0"
+ resolve-cwd "^2.0.0"
+
+imurmurhash@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+
+indent-string@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289"
+
+indexes-of@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
+
+indexof@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+
+inherits@2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
+
+ini@~1.3.0:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
+
+inquirer@^3.0.6:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9"
+ dependencies:
+ ansi-escapes "^3.0.0"
+ chalk "^2.0.0"
+ cli-cursor "^2.1.0"
+ cli-width "^2.0.0"
+ external-editor "^2.0.4"
+ figures "^2.0.0"
+ lodash "^4.3.0"
+ mute-stream "0.0.7"
+ run-async "^2.2.0"
+ rx-lite "^4.0.8"
+ rx-lite-aggregates "^4.0.8"
+ string-width "^2.1.0"
+ strip-ansi "^4.0.0"
+ through "^2.3.6"
+
+inquirer@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.0.0.tgz#e8c20303ddc15bbfc2c12a6213710ccd9e1413d8"
+ dependencies:
+ ansi-escapes "^3.0.0"
+ chalk "^2.0.0"
+ cli-cursor "^2.1.0"
+ cli-width "^2.0.0"
+ external-editor "^3.0.0"
+ figures "^2.0.0"
+ lodash "^4.3.0"
+ mute-stream "0.0.7"
+ run-async "^2.2.0"
+ rxjs "^6.1.0"
+ string-width "^2.1.0"
+ strip-ansi "^4.0.0"
+ through "^2.3.6"
+
+interpret@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
+
+invariant@^2.2.2:
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
+ dependencies:
+ loose-envify "^1.0.0"
+
+invert-kv@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+
+is-absolute-url@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6"
+
+is-accessor-descriptor@^0.1.6:
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
+ dependencies:
+ kind-of "^3.0.2"
+
+is-accessor-descriptor@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
+ dependencies:
+ kind-of "^6.0.0"
+
+is-alphabetical@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.2.tgz#1fa6e49213cb7885b75d15862fb3f3d96c884f41"
+
+is-alphanumeric@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz#4a9cef71daf4c001c1d81d63d140cf53fd6889f4"
+
+is-alphanumerical@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.2.tgz#1138e9ae5040158dc6ff76b820acd6b7a181fd40"
+ dependencies:
+ is-alphabetical "^1.0.0"
+ is-decimal "^1.0.0"
+
+is-arrayish@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+
+is-arrayish@^0.3.1:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
+
+is-binary-path@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
+ dependencies:
+ binary-extensions "^1.0.0"
+
+is-buffer@^1.1.4, is-buffer@^1.1.5:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
+
+is-builtin-module@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe"
+ dependencies:
+ builtin-modules "^1.0.0"
+
+is-data-descriptor@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
+ dependencies:
+ kind-of "^3.0.2"
+
+is-data-descriptor@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
+ dependencies:
+ kind-of "^6.0.0"
+
+is-decimal@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.2.tgz#894662d6a8709d307f3a276ca4339c8fa5dff0ff"
+
+is-descriptor@^0.1.0:
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
+ dependencies:
+ is-accessor-descriptor "^0.1.6"
+ is-data-descriptor "^0.1.4"
+ kind-of "^5.0.0"
+
+is-descriptor@^1.0.0, is-descriptor@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
+ dependencies:
+ is-accessor-descriptor "^1.0.0"
+ is-data-descriptor "^1.0.0"
+ kind-of "^6.0.2"
+
+is-directory@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
+
+is-dotfile@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1"
+
+is-equal-shallow@^0.1.3:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+ dependencies:
+ is-primitive "^2.0.0"
+
+is-extendable@^0.1.0, is-extendable@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+
+is-extendable@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
+ dependencies:
+ is-plain-object "^2.0.4"
+
+is-extglob@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+
+is-extglob@^2.1.0, is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+
+is-finite@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+ dependencies:
+ number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+ dependencies:
+ number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
+
+is-glob@^2.0.0, is-glob@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+ dependencies:
+ is-extglob "^1.0.0"
+
+is-glob@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
+ dependencies:
+ is-extglob "^2.1.0"
+
+is-glob@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0"
+ dependencies:
+ is-extglob "^2.1.1"
+
+is-hexadecimal@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.2.tgz#b6e710d7d07bb66b98cb8cece5c9b4921deeb835"
+
+is-number@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+ dependencies:
+ kind-of "^3.0.2"
+
+is-number@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
+ dependencies:
+ kind-of "^3.0.2"
+
+is-number@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
+
+is-obj@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
+
+is-path-cwd@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
+
+is-path-in-cwd@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52"
+ dependencies:
+ is-path-inside "^1.0.0"
+
+is-path-inside@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036"
+ dependencies:
+ path-is-inside "^1.0.1"
+
+is-plain-obj@^1.0.0, is-plain-obj@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
+
+is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
+ dependencies:
+ isobject "^3.0.1"
+
+is-posix-bracket@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+
+is-primitive@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+
+is-promise@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
+
+is-regexp@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
+
+is-resolvable@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88"
+
+is-stream@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+
+is-supported-regexp-flag@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-supported-regexp-flag/-/is-supported-regexp-flag-1.0.1.tgz#21ee16518d2c1dd3edd3e9a0d57e50207ac364ca"
+
+is-svg@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9"
+ dependencies:
+ html-comment-regex "^1.1.0"
+
+is-whitespace-character@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.2.tgz#ede53b4c6f6fb3874533751ec9280d01928d03ed"
+
+is-windows@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
+
+is-word-character@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-word-character/-/is-word-character-1.0.2.tgz#46a5dac3f2a1840898b91e576cd40d493f3ae553"
+
+isarray@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
+
+isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+
+isexe@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+
+isnumeric@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/isnumeric/-/isnumeric-0.2.0.tgz#a2347ba360de19e33d0ffd590fddf7755cbf2e64"
+
+isobject@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+ dependencies:
+ isarray "1.0.0"
+
+isobject@^3.0.0, isobject@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
+
+js-base64@^2.1.9:
+ version "2.4.8"
+ resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.8.tgz#57a9b130888f956834aa40c5b165ba59c758f033"
+
+"js-tokens@^3.0.0 || ^4.0.0":
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+
+js-tokens@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
+
+js-yaml@^3.7.0, js-yaml@^3.9.0, js-yaml@^3.9.1:
+ version "3.12.0"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
+ dependencies:
+ argparse "^1.0.7"
+ esprima "^4.0.0"
+
+js-yaml@~3.7.0:
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80"
+ dependencies:
+ argparse "^1.0.7"
+ esprima "^2.6.0"
+
+jsesc@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
+
+jsesc@~0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
+
+json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
+
+json-schema-traverse@^0.3.0:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
+
+json-schema-traverse@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+
+json-stable-stringify-without-jsonify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
+
+json5@^0.5.0, json5@^0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
+
+kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
+ dependencies:
+ is-buffer "^1.1.5"
+
+kind-of@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
+ dependencies:
+ is-buffer "^1.1.5"
+
+kind-of@^5.0.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
+
+kind-of@^6.0.0, kind-of@^6.0.2:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
+
+known-css-properties@^0.6.0:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.6.1.tgz#31b5123ad03d8d1a3f36bd4155459c981173478b"
+
+lcid@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
+ dependencies:
+ invert-kv "^1.0.0"
+
+levn@^0.3.0, levn@~0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+ dependencies:
+ prelude-ls "~1.1.2"
+ type-check "~0.3.2"
+
+load-json-file@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
+ dependencies:
+ graceful-fs "^4.1.2"
+ parse-json "^4.0.0"
+ pify "^3.0.0"
+ strip-bom "^3.0.0"
+
+loader-fs-cache@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/loader-fs-cache/-/loader-fs-cache-1.0.1.tgz#56e0bf08bd9708b26a765b68509840c8dec9fdbc"
+ dependencies:
+ find-cache-dir "^0.1.1"
+ mkdirp "0.5.1"
+
+loader-runner@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2"
+
+loader-utils@^1.0.2, loader-utils@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd"
+ dependencies:
+ big.js "^3.1.3"
+ emojis-list "^2.0.0"
+ json5 "^0.5.0"
+
+locate-path@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
+ dependencies:
+ p-locate "^2.0.0"
+ path-exists "^3.0.0"
+
+locate-path@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
+ dependencies:
+ p-locate "^3.0.0"
+ path-exists "^3.0.0"
+
+lodash._reinterpolate@~3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
+
+lodash.camelcase@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
+
+lodash.debounce@^4.0.8:
+ version "4.0.8"
+ resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
+
+lodash.memoize@^4.1.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
+
+lodash.template@^4.2.4:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0"
+ dependencies:
+ lodash._reinterpolate "~3.0.0"
+ lodash.templatesettings "^4.0.0"
+
+lodash.templatesettings@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316"
+ dependencies:
+ lodash._reinterpolate "~3.0.0"
+
+lodash.uniq@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
+
+lodash@^3.2.0:
+ version "3.10.1"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
+
+lodash@^4.17.10, lodash@^4.17.4, lodash@^4.3.0:
+ version "4.17.10"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
+
+log-symbols@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
+ dependencies:
+ chalk "^2.0.1"
+
+long@4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
+
+long@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b"
+
+longest-streak@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.2.tgz#2421b6ba939a443bb9ffebf596585a50b4c38e2e"
+
+loose-envify@^1.0.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+ dependencies:
+ js-tokens "^3.0.0 || ^4.0.0"
+
+loud-rejection@^1.0.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
+ dependencies:
+ currently-unhandled "^0.4.1"
+ signal-exit "^3.0.0"
+
+lru-cache@^4.0.1, lru-cache@^4.1.1:
+ version "4.1.3"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c"
+ dependencies:
+ pseudomap "^1.0.2"
+ yallist "^2.1.2"
+
+make-dir@^1.0.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
+ dependencies:
+ pify "^3.0.0"
+
+mamacro@^0.0.3:
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4"
+
+map-cache@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
+
+map-obj@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
+
+map-obj@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9"
+
+map-visit@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
+ dependencies:
+ object-visit "^1.0.0"
+
+markdown-escapes@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.2.tgz#e639cbde7b99c841c0bacc8a07982873b46d2122"
+
+markdown-table@^1.1.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-1.1.2.tgz#c78db948fa879903a41bce522e3b96f801c63786"
+
+math-expression-evaluator@^1.2.14:
+ version "1.2.17"
+ resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac"
+
+math-random@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac"
+
+mathml-tag-names@^2.0.1:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.0.tgz#490b70e062ee24636536e3d9481e333733d00f2c"
+
+md5.js@^1.3.4:
+ version "1.3.4"
+ resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d"
+ dependencies:
+ hash-base "^3.0.0"
+ inherits "^2.0.1"
+
+mdast-util-compact@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/mdast-util-compact/-/mdast-util-compact-1.0.1.tgz#cdb5f84e2b6a2d3114df33bd05d9cb32e3c4083a"
+ dependencies:
+ unist-util-modify-children "^1.0.0"
+ unist-util-visit "^1.1.0"
+
+mem@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76"
+ dependencies:
+ mimic-fn "^1.0.0"
+
+memory-fs@^0.4.0, memory-fs@~0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
+ dependencies:
+ errno "^0.1.3"
+ readable-stream "^2.0.1"
+
+meow@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4"
+ dependencies:
+ camelcase-keys "^4.0.0"
+ decamelize-keys "^1.0.0"
+ loud-rejection "^1.0.0"
+ minimist-options "^3.0.1"
+ normalize-package-data "^2.3.4"
+ read-pkg-up "^3.0.0"
+ redent "^2.0.0"
+ trim-newlines "^2.0.0"
+ yargs-parser "^10.0.0"
+
+merge2@^1.2.1:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.2.tgz#03212e3da8d86c4d8523cebd6318193414f94e34"
+
+micromatch@^2.3.11:
+ version "2.3.11"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+ dependencies:
+ arr-diff "^2.0.0"
+ array-unique "^0.2.1"
+ braces "^1.8.2"
+ expand-brackets "^0.1.4"
+ extglob "^0.3.1"
+ filename-regex "^2.0.0"
+ is-extglob "^1.0.0"
+ is-glob "^2.0.1"
+ kind-of "^3.0.2"
+ normalize-path "^2.0.1"
+ object.omit "^2.0.0"
+ parse-glob "^3.0.4"
+ regex-cache "^0.4.2"
+
+micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8:
+ version "3.1.10"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
+ dependencies:
+ arr-diff "^4.0.0"
+ array-unique "^0.3.2"
+ braces "^2.3.1"
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ extglob "^2.0.4"
+ fragment-cache "^0.2.1"
+ kind-of "^6.0.2"
+ nanomatch "^1.2.9"
+ object.pick "^1.3.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.2"
+
+miller-rabin@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
+ dependencies:
+ bn.js "^4.0.0"
+ brorand "^1.0.1"
+
+mimic-fn@^1.0.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
+
+minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
+
+minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
+
+minimatch@^3.0.2, minimatch@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+ dependencies:
+ brace-expansion "^1.1.7"
+
+minimist-options@^3.0.1:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-3.0.2.tgz#fba4c8191339e13ecf4d61beb03f070103f3d954"
+ dependencies:
+ arrify "^1.0.1"
+ is-plain-obj "^1.1.0"
+
+minimist@0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+
+minimist@1.1.x:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8"
+
+minimist@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+
+minipass@^2.2.1, minipass@^2.3.3:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233"
+ dependencies:
+ safe-buffer "^5.1.2"
+ yallist "^3.0.0"
+
+minizlib@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb"
+ dependencies:
+ minipass "^2.2.1"
+
+mississippi@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f"
+ dependencies:
+ concat-stream "^1.5.0"
+ duplexify "^3.4.2"
+ end-of-stream "^1.1.0"
+ flush-write-stream "^1.0.0"
+ from2 "^2.1.0"
+ parallel-transform "^1.1.0"
+ pump "^2.0.1"
+ pumpify "^1.3.3"
+ stream-each "^1.1.0"
+ through2 "^2.0.0"
+
+mixin-deep@^1.2.0:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe"
+ dependencies:
+ for-in "^1.0.2"
+ is-extendable "^1.0.1"
+
+mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+ dependencies:
+ minimist "0.0.8"
+
+move-concurrently@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
+ dependencies:
+ aproba "^1.1.1"
+ copy-concurrently "^1.0.0"
+ fs-write-stream-atomic "^1.0.8"
+ mkdirp "^0.5.1"
+ rimraf "^2.5.4"
+ run-queue "^1.0.3"
+
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+
+mute-stream@0.0.7:
+ version "0.0.7"
+ resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
+
+nan@^2.9.2:
+ version "2.10.0"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f"
+
+nanomatch@^1.2.9:
+ version "1.2.13"
+ resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
+ dependencies:
+ arr-diff "^4.0.0"
+ array-unique "^0.3.2"
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ fragment-cache "^0.2.1"
+ is-windows "^1.0.2"
+ kind-of "^6.0.2"
+ object.pick "^1.3.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+natural-compare@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+
+needle@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d"
+ dependencies:
+ debug "^2.1.2"
+ iconv-lite "^0.4.4"
+ sax "^1.2.4"
+
+neo-async@^2.5.0:
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.1.tgz#acb909e327b1e87ec9ef15f41b8a269512ad41ee"
+
+nice-try@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4"
+
+node-libs-browser@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df"
+ dependencies:
+ assert "^1.1.1"
+ browserify-zlib "^0.2.0"
+ buffer "^4.3.0"
+ console-browserify "^1.1.0"
+ constants-browserify "^1.0.0"
+ crypto-browserify "^3.11.0"
+ domain-browser "^1.1.1"
+ events "^1.0.0"
+ https-browserify "^1.0.0"
+ os-browserify "^0.3.0"
+ path-browserify "0.0.0"
+ process "^0.11.10"
+ punycode "^1.2.4"
+ querystring-es3 "^0.2.0"
+ readable-stream "^2.3.3"
+ stream-browserify "^2.0.1"
+ stream-http "^2.7.2"
+ string_decoder "^1.0.0"
+ timers-browserify "^2.0.4"
+ tty-browserify "0.0.0"
+ url "^0.11.0"
+ util "^0.10.3"
+ vm-browserify "0.0.4"
+
+node-pre-gyp@^0.10.0:
+ version "0.10.3"
+ resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc"
+ dependencies:
+ detect-libc "^1.0.2"
+ mkdirp "^0.5.1"
+ needle "^2.2.1"
+ nopt "^4.0.1"
+ npm-packlist "^1.1.6"
+ npmlog "^4.0.2"
+ rc "^1.2.7"
+ rimraf "^2.6.1"
+ semver "^5.3.0"
+ tar "^4"
+
+node-releases@^1.0.0-alpha.10:
+ version "1.0.0-alpha.10"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.0.0-alpha.10.tgz#61c8d5f9b5b2e05d84eba941d05b6f5202f68a2a"
+ dependencies:
+ semver "^5.3.0"
+
+nopt@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
+ dependencies:
+ abbrev "1"
+ osenv "^0.1.4"
+
+normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f"
+ dependencies:
+ hosted-git-info "^2.1.4"
+ is-builtin-module "^1.0.0"
+ semver "2 || 3 || 4 || 5"
+ validate-npm-package-license "^3.0.1"
+
+normalize-path@^2.0.1, normalize-path@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+ dependencies:
+ remove-trailing-separator "^1.0.1"
+
+normalize-range@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
+
+normalize-selector@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/normalize-selector/-/normalize-selector-0.2.0.tgz#d0b145eb691189c63a78d201dc4fdb1293ef0c03"
+
+normalize-url@^1.4.0:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c"
+ dependencies:
+ object-assign "^4.0.1"
+ prepend-http "^1.0.0"
+ query-string "^4.1.0"
+ sort-keys "^1.0.0"
+
+npm-bundled@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308"
+
+npm-packlist@^1.1.6:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de"
+ dependencies:
+ ignore-walk "^3.0.1"
+ npm-bundled "^1.0.1"
+
+npm-run-path@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
+ dependencies:
+ path-key "^2.0.0"
+
+npmlog@^4.0.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
+ dependencies:
+ are-we-there-yet "~1.1.2"
+ console-control-strings "~1.1.0"
+ gauge "~2.7.3"
+ set-blocking "~2.0.0"
+
+nth-check@~1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4"
+ dependencies:
+ boolbase "~1.0.0"
+
+num2fraction@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
+
+number-is-nan@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+
+object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+
+object-copy@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
+ dependencies:
+ copy-descriptor "^0.1.0"
+ define-property "^0.2.5"
+ kind-of "^3.0.3"
+
+object-hash@^1.1.4:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.0.tgz#76d9ba6ff113cf8efc0d996102851fe6723963e2"
+
+object-visit@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
+ dependencies:
+ isobject "^3.0.0"
+
+object.omit@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+ dependencies:
+ for-own "^0.1.4"
+ is-extendable "^0.1.1"
+
+object.pick@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
+ dependencies:
+ isobject "^3.0.1"
+
+once@^1.3.0, once@^1.3.1, once@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ dependencies:
+ wrappy "1"
+
+onecolor@^3.0.4:
+ version "3.0.5"
+ resolved "https://registry.yarnpkg.com/onecolor/-/onecolor-3.0.5.tgz#36eff32201379efdf1180fb445e51a8e2425f9f6"
+
+onetime@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
+ dependencies:
+ mimic-fn "^1.0.0"
+
+optionator@^0.8.2:
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
+ dependencies:
+ deep-is "~0.1.3"
+ fast-levenshtein "~2.0.4"
+ levn "~0.3.0"
+ prelude-ls "~1.1.2"
+ type-check "~0.3.2"
+ wordwrap "~1.0.0"
+
+os-browserify@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
+
+os-homedir@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+
+os-locale@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2"
+ dependencies:
+ execa "^0.7.0"
+ lcid "^1.0.0"
+ mem "^1.1.0"
+
+os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+
+osenv@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
+ dependencies:
+ os-homedir "^1.0.0"
+ os-tmpdir "^1.0.0"
+
+p-finally@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
+
+p-limit@^1.1.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
+ dependencies:
+ p-try "^1.0.0"
+
+p-limit@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec"
+ dependencies:
+ p-try "^2.0.0"
+
+p-locate@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
+ dependencies:
+ p-limit "^1.1.0"
+
+p-locate@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
+ dependencies:
+ p-limit "^2.0.0"
+
+p-try@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
+
+p-try@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1"
+
+pako@~1.0.5:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258"
+
+parallel-transform@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06"
+ dependencies:
+ cyclist "~0.2.2"
+ inherits "^2.0.3"
+ readable-stream "^2.1.5"
+
+parse-asn1@^5.0.0:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8"
+ dependencies:
+ asn1.js "^4.0.0"
+ browserify-aes "^1.0.0"
+ create-hash "^1.1.0"
+ evp_bytestokey "^1.0.0"
+ pbkdf2 "^3.0.3"
+
+parse-entities@^1.0.2, parse-entities@^1.1.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.1.2.tgz#9eaf719b29dc3bd62246b4332009072e01527777"
+ dependencies:
+ character-entities "^1.0.0"
+ character-entities-legacy "^1.0.0"
+ character-reference-invalid "^1.0.0"
+ is-alphanumerical "^1.0.0"
+ is-decimal "^1.0.0"
+ is-hexadecimal "^1.0.0"
+
+parse-glob@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+ dependencies:
+ glob-base "^0.3.0"
+ is-dotfile "^1.0.0"
+ is-extglob "^1.0.0"
+ is-glob "^2.0.0"
+
+parse-json@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
+ dependencies:
+ error-ex "^1.3.1"
+ json-parse-better-errors "^1.0.1"
+
+pascalcase@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
+
+path-browserify@0.0.0:
+ version "0.0.0"
+ resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
+
+path-dirname@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
+
+path-exists@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+ dependencies:
+ pinkie-promise "^2.0.0"
+
+path-exists@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+
+path-is-absolute@^1.0.0, path-is-absolute@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+
+path-is-inside@^1.0.1, path-is-inside@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
+
+path-key@^2.0.0, path-key@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
+
+path-parse@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
+
+path-type@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
+ dependencies:
+ pify "^3.0.0"
+
+path@^0.12.7:
+ version "0.12.7"
+ resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f"
+ dependencies:
+ process "^0.11.1"
+ util "^0.10.3"
+
+pbkdf2@^3.0.3:
+ version "3.0.16"
+ resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.16.tgz#7404208ec6b01b62d85bf83853a8064f8d9c2a5c"
+ dependencies:
+ create-hash "^1.1.2"
+ create-hmac "^1.1.4"
+ ripemd160 "^2.0.1"
+ safe-buffer "^5.0.1"
+ sha.js "^2.4.8"
+
+pify@^2.0.0, pify@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+
+pify@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
+
+pinkie-promise@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+ dependencies:
+ pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+
+pixrem@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/pixrem/-/pixrem-4.0.1.tgz#2da4a1de6ec4423c5fc3794e930b81d4490ec686"
+ dependencies:
+ browserslist "^2.0.0"
+ postcss "^6.0.0"
+ reduce-css-calc "^1.2.7"
+
+pkg-dir@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4"
+ dependencies:
+ find-up "^1.0.0"
+
+pkg-dir@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
+ dependencies:
+ find-up "^2.1.0"
+
+pleeease-filters@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/pleeease-filters/-/pleeease-filters-4.0.0.tgz#6632b2fb05648d2758d865384fbced79e1ccaec7"
+ dependencies:
+ onecolor "^3.0.4"
+ postcss "^6.0.1"
+
+pluralize@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777"
+
+posix-character-classes@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
+
+postcss-apply@^0.10.0:
+ version "0.10.0"
+ resolved "https://registry.yarnpkg.com/postcss-apply/-/postcss-apply-0.10.0.tgz#50cc982b7a58a335f9be96a277fc2d8792e760dc"
+ dependencies:
+ babel-runtime "^6.26.0"
+ balanced-match "^1.0.0"
+ postcss "^6.0.21"
+
+postcss-apply@^0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/postcss-apply/-/postcss-apply-0.8.0.tgz#14e544bbb5cb6f1c1e048857965d79ae066b1343"
+ dependencies:
+ babel-runtime "^6.23.0"
+ balanced-match "^0.4.2"
+ postcss "^6.0.0"
+
+postcss-attribute-case-insensitive@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-2.0.0.tgz#94dc422c8f90997f16bd33a3654bbbec084963b4"
+ dependencies:
+ postcss "^6.0.0"
+ postcss-selector-parser "^2.2.3"
+
+postcss-calc@^5.2.0:
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e"
+ dependencies:
+ postcss "^5.0.2"
+ postcss-message-helpers "^2.0.0"
+ reduce-css-calc "^1.2.6"
+
+postcss-calc@^6.0.0:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-6.0.1.tgz#3d24171bbf6e7629d422a436ebfe6dd9511f4330"
+ dependencies:
+ css-unit-converter "^1.1.1"
+ postcss "^6.0.0"
+ postcss-selector-parser "^2.2.2"
+ reduce-css-calc "^2.0.0"
+
+postcss-color-function@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/postcss-color-function/-/postcss-color-function-4.0.1.tgz#402b3f2cebc3f6947e618fb6be3654fbecef6444"
+ dependencies:
+ css-color-function "~1.3.3"
+ postcss "^6.0.1"
+ postcss-message-helpers "^2.0.0"
+ postcss-value-parser "^3.3.0"
+
+postcss-color-gray@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-color-gray/-/postcss-color-gray-4.1.0.tgz#e5581ed57eaa826fb652ca11b1e2b7b136a9f9df"
+ dependencies:
+ color "^2.0.1"
+ postcss "^6.0.14"
+ postcss-message-helpers "^2.0.0"
+ reduce-function-call "^1.0.2"
+
+postcss-color-hex-alpha@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-3.0.0.tgz#1e53e6c8acb237955e8fd08b7ecdb1b8b8309f95"
+ dependencies:
+ color "^1.0.3"
+ postcss "^6.0.1"
+ postcss-message-helpers "^2.0.0"
+
+postcss-color-hsl@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-color-hsl/-/postcss-color-hsl-2.0.0.tgz#12703666fa310430e3f30a454dac1386317d5844"
+ dependencies:
+ postcss "^6.0.1"
+ postcss-value-parser "^3.3.0"
+ units-css "^0.4.0"
+
+postcss-color-hwb@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-color-hwb/-/postcss-color-hwb-3.0.0.tgz#3402b19ef4d8497540c1fb5072be9863ca95571e"
+ dependencies:
+ color "^1.0.3"
+ postcss "^6.0.1"
+ postcss-message-helpers "^2.0.0"
+ reduce-function-call "^1.0.2"
+
+postcss-color-mod-function@^2.4.3:
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/postcss-color-mod-function/-/postcss-color-mod-function-2.4.3.tgz#14a97f5b17a5f19396e9dea7ffcb5be732592baf"
+ dependencies:
+ "@csstools/convert-colors" "^1.4.0"
+ postcss "^6.0.23"
+ postcss-values-parser "^1.5.0"
+
+postcss-color-rebeccapurple@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-3.1.0.tgz#ce1269ecc2d0d8bf92aab44bd884e633124c33ec"
+ dependencies:
+ postcss "^6.0.22"
+ postcss-values-parser "^1.5.0"
+
+postcss-color-rgb@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-color-rgb/-/postcss-color-rgb-2.0.0.tgz#14539c8a7131494b482e0dd1cc265ff6514b5263"
+ dependencies:
+ postcss "^6.0.1"
+ postcss-value-parser "^3.3.0"
+
+postcss-color-rgba-fallback@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-color-rgba-fallback/-/postcss-color-rgba-fallback-3.0.0.tgz#37d5c9353a07a09270912a82606bb42a0d702c04"
+ dependencies:
+ postcss "^6.0.6"
+ postcss-value-parser "^3.3.0"
+ rgb-hex "^2.1.0"
+
+postcss-colormin@^2.1.8:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.2.tgz#6631417d5f0e909a3d7ec26b24c8a8d1e4f96e4b"
+ dependencies:
+ colormin "^1.0.5"
+ postcss "^5.0.13"
+ postcss-value-parser "^3.2.3"
+
+postcss-convert-values@^2.3.4:
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz#bbd8593c5c1fd2e3d1c322bb925dcae8dae4d62d"
+ dependencies:
+ postcss "^5.0.11"
+ postcss-value-parser "^3.1.2"
+
+postcss-cssnext@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-cssnext/-/postcss-cssnext-3.1.0.tgz#927dc29341a938254cde38ea60a923b9dfedead9"
+ dependencies:
+ autoprefixer "^7.1.1"
+ caniuse-api "^2.0.0"
+ chalk "^2.0.1"
+ pixrem "^4.0.0"
+ pleeease-filters "^4.0.0"
+ postcss "^6.0.5"
+ postcss-apply "^0.8.0"
+ postcss-attribute-case-insensitive "^2.0.0"
+ postcss-calc "^6.0.0"
+ postcss-color-function "^4.0.0"
+ postcss-color-gray "^4.0.0"
+ postcss-color-hex-alpha "^3.0.0"
+ postcss-color-hsl "^2.0.0"
+ postcss-color-hwb "^3.0.0"
+ postcss-color-rebeccapurple "^3.0.0"
+ postcss-color-rgb "^2.0.0"
+ postcss-color-rgba-fallback "^3.0.0"
+ postcss-custom-media "^6.0.0"
+ postcss-custom-properties "^6.1.0"
+ postcss-custom-selectors "^4.0.1"
+ postcss-font-family-system-ui "^3.0.0"
+ postcss-font-variant "^3.0.0"
+ postcss-image-set-polyfill "^0.3.5"
+ postcss-initial "^2.0.0"
+ postcss-media-minmax "^3.0.0"
+ postcss-nesting "^4.0.1"
+ postcss-pseudo-class-any-link "^4.0.0"
+ postcss-pseudoelements "^5.0.0"
+ postcss-replace-overflow-wrap "^2.0.0"
+ postcss-selector-matches "^3.0.1"
+ postcss-selector-not "^3.0.1"
+
+postcss-custom-media@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-6.0.0.tgz#be532784110ecb295044fb5395a18006eb21a737"
+ dependencies:
+ postcss "^6.0.1"
+
+postcss-custom-properties@^6.1.0:
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-6.3.1.tgz#5c52abde313d7ec9368c4abf67d27a656cba8b39"
+ dependencies:
+ balanced-match "^1.0.0"
+ postcss "^6.0.18"
+
+postcss-custom-properties@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-7.0.0.tgz#24dc4fbe6d6ed550ea4fd3b11204660e9ffa3b33"
+ dependencies:
+ balanced-match "^1.0.0"
+ postcss "^6.0.18"
+
+postcss-custom-selectors@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-4.0.1.tgz#781382f94c52e727ef5ca4776ea2adf49a611382"
+ dependencies:
+ postcss "^6.0.1"
+ postcss-selector-matches "^3.0.0"
+
+postcss-discard-comments@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d"
+ dependencies:
+ postcss "^5.0.14"
+
+postcss-discard-duplicates@^2.0.1:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz#b9abf27b88ac188158a5eb12abcae20263b91932"
+ dependencies:
+ postcss "^5.0.4"
+
+postcss-discard-empty@^2.0.1:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5"
+ dependencies:
+ postcss "^5.0.14"
+
+postcss-discard-overridden@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58"
+ dependencies:
+ postcss "^5.0.16"
+
+postcss-discard-unused@^2.2.1:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433"
+ dependencies:
+ postcss "^5.0.14"
+ uniqs "^2.0.0"
+
+postcss-filter-plugins@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz#82245fdf82337041645e477114d8e593aa18b8ec"
+ dependencies:
+ postcss "^5.0.4"
+
+postcss-font-family-system-ui@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-font-family-system-ui/-/postcss-font-family-system-ui-3.0.0.tgz#675fe7a9e029669f05f8dba2e44c2225ede80623"
+ dependencies:
+ postcss "^6.0"
+
+postcss-font-variant@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-3.0.0.tgz#08ccc88f6050ba82ed8ef2cc76c0c6a6b41f183e"
+ dependencies:
+ postcss "^6.0.1"
+
+postcss-html@^0.31.0:
+ version "0.31.0"
+ resolved "https://registry.yarnpkg.com/postcss-html/-/postcss-html-0.31.0.tgz#ea6ae2e95df60a03032e9ab5aba72143d8ca0325"
+ dependencies:
+ htmlparser2 "^3.9.2"
+
+postcss-image-set-polyfill@^0.3.5:
+ version "0.3.5"
+ resolved "https://registry.yarnpkg.com/postcss-image-set-polyfill/-/postcss-image-set-polyfill-0.3.5.tgz#0f193413700cf1f82bd39066ef016d65a4a18181"
+ dependencies:
+ postcss "^6.0.1"
+ postcss-media-query-parser "^0.2.3"
+
+postcss-initial@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-2.0.0.tgz#72715f7336e0bb79351d99ee65c4a253a8441ba4"
+ dependencies:
+ lodash.template "^4.2.4"
+ postcss "^6.0.1"
+
+postcss-less@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-less/-/postcss-less-2.0.0.tgz#5d190b8e057ca446d60fe2e2587ad791c9029fb8"
+ dependencies:
+ postcss "^5.2.16"
+
+postcss-load-config@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.0.0.tgz#f1312ddbf5912cd747177083c5ef7a19d62ee484"
+ dependencies:
+ cosmiconfig "^4.0.0"
+ import-cwd "^2.0.0"
+
+postcss-loader@^2.1.6:
+ version "2.1.6"
+ resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-2.1.6.tgz#1d7dd7b17c6ba234b9bed5af13e0bea40a42d740"
+ dependencies:
+ loader-utils "^1.1.0"
+ postcss "^6.0.0"
+ postcss-load-config "^2.0.0"
+ schema-utils "^0.4.0"
+
+postcss-markdown@^0.31.0:
+ version "0.31.0"
+ resolved "https://registry.yarnpkg.com/postcss-markdown/-/postcss-markdown-0.31.0.tgz#e4c699ad34b14a29ad5d47132bb1b3100b60ef75"
+ dependencies:
+ remark "^9.0.0"
+ unist-util-find-all-after "^1.0.2"
+
+postcss-media-minmax@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-3.0.0.tgz#675256037a43ef40bc4f0760bfd06d4dc69d48d2"
+ dependencies:
+ postcss "^6.0.1"
+
+postcss-media-query-parser@^0.2.3:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244"
+
+postcss-merge-idents@^2.1.5:
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270"
+ dependencies:
+ has "^1.0.1"
+ postcss "^5.0.10"
+ postcss-value-parser "^3.1.1"
+
+postcss-merge-longhand@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz#23d90cd127b0a77994915332739034a1a4f3d658"
+ dependencies:
+ postcss "^5.0.4"
+
+postcss-merge-rules@^2.0.3:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz#d1df5dfaa7b1acc3be553f0e9e10e87c61b5f721"
+ dependencies:
+ browserslist "^1.5.2"
+ caniuse-api "^1.5.2"
+ postcss "^5.0.4"
+ postcss-selector-parser "^2.2.2"
+ vendors "^1.0.0"
+
+postcss-message-helpers@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e"
+
+postcss-minify-font-values@^1.0.2:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69"
+ dependencies:
+ object-assign "^4.0.1"
+ postcss "^5.0.4"
+ postcss-value-parser "^3.0.2"
+
+postcss-minify-gradients@^1.0.1:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1"
+ dependencies:
+ postcss "^5.0.12"
+ postcss-value-parser "^3.3.0"
+
+postcss-minify-params@^1.0.4:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz#ad2ce071373b943b3d930a3fa59a358c28d6f1f3"
+ dependencies:
+ alphanum-sort "^1.0.1"
+ postcss "^5.0.2"
+ postcss-value-parser "^3.0.2"
+ uniqs "^2.0.0"
+
+postcss-minify-selectors@^2.0.4:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz#b2c6a98c0072cf91b932d1a496508114311735bf"
+ dependencies:
+ alphanum-sort "^1.0.2"
+ has "^1.0.1"
+ postcss "^5.0.14"
+ postcss-selector-parser "^2.0.0"
+
+postcss-modules-extract-imports@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85"
+ dependencies:
+ postcss "^6.0.1"
+
+postcss-modules-local-by-default@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069"
+ dependencies:
+ css-selector-tokenizer "^0.7.0"
+ postcss "^6.0.1"
+
+postcss-modules-scope@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90"
+ dependencies:
+ css-selector-tokenizer "^0.7.0"
+ postcss "^6.0.1"
+
+postcss-modules-values@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20"
+ dependencies:
+ icss-replace-symbols "^1.1.0"
+ postcss "^6.0.1"
+
+postcss-nested-ancestors@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-nested-ancestors/-/postcss-nested-ancestors-2.0.0.tgz#957ef27fb9e37cb082786d95b5e310d4b47470fe"
+ dependencies:
+ escape-string-regexp "^1.0.5"
+ postcss "^6.0.0"
+ postcss-resolve-nested-selector "^0.1.1"
+
+postcss-nested@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-3.0.0.tgz#cde40bd07a078565f3df72e2dc2665871c724852"
+ dependencies:
+ postcss "^6.0.14"
+ postcss-selector-parser "^3.1.1"
+
+postcss-nesting@^4.0.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-4.2.1.tgz#0483bce338b3f0828ced90ff530b29b98b00300d"
+ dependencies:
+ postcss "^6.0.11"
+
+postcss-nesting@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-6.0.0.tgz#4c45276a065765ec063efe1e4daf75c131518991"
+ dependencies:
+ postcss "^6.0.22"
+
+postcss-normalize-charset@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1"
+ dependencies:
+ postcss "^5.0.5"
+
+postcss-normalize-url@^3.0.7:
+ version "3.0.8"
+ resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz#108f74b3f2fcdaf891a2ffa3ea4592279fc78222"
+ dependencies:
+ is-absolute-url "^2.0.0"
+ normalize-url "^1.4.0"
+ postcss "^5.0.14"
+ postcss-value-parser "^3.2.3"
+
+postcss-ordered-values@^2.1.0:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d"
+ dependencies:
+ postcss "^5.0.4"
+ postcss-value-parser "^3.0.1"
+
+postcss-pseudo-class-any-link@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-4.0.0.tgz#9152a0613d3450720513e8892854bae42d0ee68e"
+ dependencies:
+ postcss "^6.0.1"
+ postcss-selector-parser "^2.2.3"
+
+postcss-pseudoelements@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-pseudoelements/-/postcss-pseudoelements-5.0.0.tgz#eef194e8d524645ca520a949e95e518e812402cb"
+ dependencies:
+ postcss "^6.0.0"
+
+postcss-reduce-idents@^2.2.2:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz#c2c6d20cc958284f6abfbe63f7609bf409059ad3"
+ dependencies:
+ postcss "^5.0.4"
+ postcss-value-parser "^3.0.2"
+
+postcss-reduce-initial@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz#68f80695f045d08263a879ad240df8dd64f644ea"
+ dependencies:
+ postcss "^5.0.4"
+
+postcss-reduce-transforms@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1"
+ dependencies:
+ has "^1.0.1"
+ postcss "^5.0.8"
+ postcss-value-parser "^3.0.1"
+
+postcss-replace-overflow-wrap@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-2.0.0.tgz#794db6faa54f8db100854392a93af45768b4e25b"
+ dependencies:
+ postcss "^6.0.1"
+
+postcss-reporter@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-reporter/-/postcss-reporter-5.0.0.tgz#a14177fd1342829d291653f2786efd67110332c3"
+ dependencies:
+ chalk "^2.0.1"
+ lodash "^4.17.4"
+ log-symbols "^2.0.0"
+ postcss "^6.0.8"
+
+postcss-resolve-nested-selector@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz#29ccbc7c37dedfac304e9fff0bf1596b3f6a0e4e"
+
+postcss-safe-parser@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz#8756d9e4c36fdce2c72b091bbc8ca176ab1fcdea"
+ dependencies:
+ postcss "^7.0.0"
+
+postcss-sass@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/postcss-sass/-/postcss-sass-0.2.0.tgz#e55516441e9526ba4b380a730d3a02e9eaa78c7a"
+ dependencies:
+ gonzales-pe "^4.0.3"
+ postcss "^6.0.6"
+
+postcss-sass@^0.3.0:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/postcss-sass/-/postcss-sass-0.3.2.tgz#17f3074cecb28128b156f1a4407c6ad075d7e00c"
+ dependencies:
+ gonzales-pe "4.2.3"
+ postcss "6.0.22"
+
+postcss-scss@^1.0.2:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-1.0.6.tgz#ab903f3bb20161bc177896462293a53d4bff5f7a"
+ dependencies:
+ postcss "^6.0.23"
+
+postcss-scss@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-2.0.0.tgz#248b0a28af77ea7b32b1011aba0f738bda27dea1"
+ dependencies:
+ postcss "^7.0.0"
+
+postcss-selector-matches@^3.0.0, postcss-selector-matches@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/postcss-selector-matches/-/postcss-selector-matches-3.0.1.tgz#e5634011e13950881861bbdd58c2d0111ffc96ab"
+ dependencies:
+ balanced-match "^0.4.2"
+ postcss "^6.0.1"
+
+postcss-selector-not@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-3.0.1.tgz#2e4db2f0965336c01e7cec7db6c60dff767335d9"
+ dependencies:
+ balanced-match "^0.4.2"
+ postcss "^6.0.1"
+
+postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2, postcss-selector-parser@^2.2.3:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90"
+ dependencies:
+ flatten "^1.0.2"
+ indexes-of "^1.0.1"
+ uniq "^1.0.1"
+
+postcss-selector-parser@^3.1.0, postcss-selector-parser@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz#4f875f4afb0c96573d5cf4d74011aee250a7e865"
+ dependencies:
+ dot-prop "^4.1.1"
+ indexes-of "^1.0.1"
+ uniq "^1.0.1"
+
+postcss-smart-import@^0.7.6:
+ version "0.7.6"
+ resolved "https://registry.yarnpkg.com/postcss-smart-import/-/postcss-smart-import-0.7.6.tgz#259deb84aa28f138458218ecc0e9a84c61ada6a4"
+ dependencies:
+ babel-runtime "^6.26.0"
+ lodash "^4.17.4"
+ object-assign "^4.1.1"
+ postcss "^6.0.14"
+ postcss-sass "^0.2.0"
+ postcss-scss "^1.0.2"
+ postcss-value-parser "^3.3.0"
+ promise-each "^2.2.0"
+ read-cache "^1.0.0"
+ resolve "^1.5.0"
+ sugarss "^1.0.1"
+
+postcss-styled@^0.31.0:
+ version "0.31.0"
+ resolved "https://registry.yarnpkg.com/postcss-styled/-/postcss-styled-0.31.0.tgz#ab532a2b3c469dfcca306a7623c4d4a98bb077d5"
+
+postcss-svgo@^2.1.1:
+ version "2.1.6"
+ resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.6.tgz#b6df18aa613b666e133f08adb5219c2684ac108d"
+ dependencies:
+ is-svg "^2.0.0"
+ postcss "^5.0.14"
+ postcss-value-parser "^3.2.3"
+ svgo "^0.7.0"
+
+postcss-syntax@^0.31.0:
+ version "0.31.0"
+ resolved "https://registry.yarnpkg.com/postcss-syntax/-/postcss-syntax-0.31.0.tgz#13d955c705d339595d10a19efa4a1bee82dfb78f"
+
+postcss-unique-selectors@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d"
+ dependencies:
+ alphanum-sort "^1.0.1"
+ postcss "^5.0.4"
+ uniqs "^2.0.0"
+
+postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15"
+
+postcss-values-parser@^1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/postcss-values-parser/-/postcss-values-parser-1.5.0.tgz#5d9fa63e2bcb0179ce48f3235303765eb89f3047"
+ dependencies:
+ flatten "^1.0.2"
+ indexes-of "^1.0.1"
+ uniq "^1.0.1"
+
+postcss-zindex@^2.0.1:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22"
+ dependencies:
+ has "^1.0.1"
+ postcss "^5.0.4"
+ uniqs "^2.0.0"
+
+postcss@6.0.22:
+ version "6.0.22"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.22.tgz#e23b78314905c3b90cbd61702121e7a78848f2a3"
+ dependencies:
+ chalk "^2.4.1"
+ source-map "^0.6.1"
+ supports-color "^5.4.0"
+
+postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.16:
+ version "5.2.18"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5"
+ dependencies:
+ chalk "^1.1.3"
+ js-base64 "^2.1.9"
+ source-map "^0.5.6"
+ supports-color "^3.2.3"
+
+postcss@^6.0, postcss@^6.0.0, postcss@^6.0.1, postcss@^6.0.11, postcss@^6.0.14, postcss@^6.0.17, postcss@^6.0.18, postcss@^6.0.21, postcss@^6.0.22, postcss@^6.0.23, postcss@^6.0.5, postcss@^6.0.6, postcss@^6.0.8:
+ version "6.0.23"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324"
+ dependencies:
+ chalk "^2.4.1"
+ source-map "^0.6.1"
+ supports-color "^5.4.0"
+
+postcss@^7.0.0, postcss@^7.0.2:
+ version "7.0.2"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.2.tgz#7b5a109de356804e27f95a960bef0e4d5bc9bb18"
+ dependencies:
+ chalk "^2.4.1"
+ source-map "^0.6.1"
+ supports-color "^5.4.0"
+
+prelude-ls@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+
+prepend-http@^1.0.0:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
+
+preserve@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+
+private@^0.1.6, private@^0.1.8:
+ version "0.1.8"
+ resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
+
+process-nextick-args@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
+
+process@^0.11.1, process@^0.11.10:
+ version "0.11.10"
+ resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
+
+progress@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f"
+
+promise-each@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/promise-each/-/promise-each-2.2.0.tgz#3353174eff2694481037e04e01f77aa0fb6d1b60"
+ dependencies:
+ any-promise "^0.1.0"
+
+promise-inflight@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
+
+prr@~1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
+
+pseudomap@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
+
+public-encrypt@^4.0.0:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.2.tgz#46eb9107206bf73489f8b85b69d91334c6610994"
+ dependencies:
+ bn.js "^4.1.0"
+ browserify-rsa "^4.0.0"
+ create-hash "^1.1.0"
+ parse-asn1 "^5.0.0"
+ randombytes "^2.0.1"
+
+pump@^2.0.0, pump@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
+ dependencies:
+ end-of-stream "^1.1.0"
+ once "^1.3.1"
+
+pumpify@^1.3.3:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce"
+ dependencies:
+ duplexify "^3.6.0"
+ inherits "^2.0.3"
+ pump "^2.0.0"
+
+punycode@1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
+
+punycode@^1.2.4:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+
+punycode@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+
+q@^1.1.2:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
+
+query-string@^4.1.0:
+ version "4.3.4"
+ resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"
+ dependencies:
+ object-assign "^4.1.0"
+ strict-uri-encode "^1.0.0"
+
+querystring-es3@^0.2.0:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
+
+querystring@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+
+quick-lru@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8"
+
+randomatic@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.0.0.tgz#d35490030eb4f7578de292ce6dfb04a91a128923"
+ dependencies:
+ is-number "^4.0.0"
+ kind-of "^6.0.0"
+ math-random "^1.0.1"
+
+randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80"
+ dependencies:
+ safe-buffer "^5.1.0"
+
+randomfill@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458"
+ dependencies:
+ randombytes "^2.0.5"
+ safe-buffer "^5.1.0"
+
+raw-loader@^0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa"
+
+rc@^1.2.7:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
+ dependencies:
+ deep-extend "^0.6.0"
+ ini "~1.3.0"
+ minimist "^1.2.0"
+ strip-json-comments "~2.0.1"
+
+read-cache@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
+ dependencies:
+ pify "^2.3.0"
+
+read-pkg-up@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07"
+ dependencies:
+ find-up "^2.0.0"
+ read-pkg "^3.0.0"
+
+read-pkg@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389"
+ dependencies:
+ load-json-file "^4.0.0"
+ normalize-package-data "^2.3.2"
+ path-type "^3.0.0"
+
+"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6:
+ version "2.3.6"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.3"
+ isarray "~1.0.0"
+ process-nextick-args "~2.0.0"
+ safe-buffer "~5.1.1"
+ string_decoder "~1.1.1"
+ util-deprecate "~1.0.1"
+
+readable-stream@1.1:
+ version "1.1.13"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.13.tgz#f6eef764f514c89e2b9e23146a75ba106756d23e"
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.1"
+ isarray "0.0.1"
+ string_decoder "~0.10.x"
+
+readdirp@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
+ dependencies:
+ graceful-fs "^4.1.2"
+ minimatch "^3.0.2"
+ readable-stream "^2.0.2"
+ set-immediate-shim "^1.0.1"
+
+redent@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa"
+ dependencies:
+ indent-string "^3.0.0"
+ strip-indent "^2.0.0"
+
+reduce-css-calc@^1.2.6, reduce-css-calc@^1.2.7:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716"
+ dependencies:
+ balanced-match "^0.4.2"
+ math-expression-evaluator "^1.2.14"
+ reduce-function-call "^1.0.1"
+
+reduce-css-calc@^2.0.0:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-2.1.4.tgz#c20e9cda8445ad73d4ff4bea960c6f8353791708"
+ dependencies:
+ css-unit-converter "^1.1.1"
+ postcss-value-parser "^3.3.0"
+
+reduce-function-call@^1.0.1, reduce-function-call@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.2.tgz#5a200bf92e0e37751752fe45b0ab330fd4b6be99"
+ dependencies:
+ balanced-match "^0.4.2"
+
+regenerate@^1.2.1:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
+
+regenerator-runtime@^0.10.5:
+ version "0.10.5"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658"
+
+regenerator-runtime@^0.11.0:
+ version "0.11.1"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
+
+regenerator-transform@^0.10.0:
+ version "0.10.1"
+ resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd"
+ dependencies:
+ babel-runtime "^6.18.0"
+ babel-types "^6.19.0"
+ private "^0.1.6"
+
+regex-cache@^0.4.2:
+ version "0.4.4"
+ resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd"
+ dependencies:
+ is-equal-shallow "^0.1.3"
+
+regex-not@^1.0.0, regex-not@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
+ dependencies:
+ extend-shallow "^3.0.2"
+ safe-regex "^1.1.0"
+
+regexpp@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab"
+
+regexpu-core@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b"
+ dependencies:
+ regenerate "^1.2.1"
+ regjsgen "^0.2.0"
+ regjsparser "^0.1.4"
+
+regexpu-core@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240"
+ dependencies:
+ regenerate "^1.2.1"
+ regjsgen "^0.2.0"
+ regjsparser "^0.1.4"
+
+regjsgen@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7"
+
+regjsparser@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c"
+ dependencies:
+ jsesc "~0.5.0"
+
+remark-parse@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-5.0.0.tgz#4c077f9e499044d1d5c13f80d7a98cf7b9285d95"
+ dependencies:
+ collapse-white-space "^1.0.2"
+ is-alphabetical "^1.0.0"
+ is-decimal "^1.0.0"
+ is-whitespace-character "^1.0.0"
+ is-word-character "^1.0.0"
+ markdown-escapes "^1.0.0"
+ parse-entities "^1.1.0"
+ repeat-string "^1.5.4"
+ state-toggle "^1.0.0"
+ trim "0.0.1"
+ trim-trailing-lines "^1.0.0"
+ unherit "^1.0.4"
+ unist-util-remove-position "^1.0.0"
+ vfile-location "^2.0.0"
+ xtend "^4.0.1"
+
+remark-stringify@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-5.0.0.tgz#336d3a4d4a6a3390d933eeba62e8de4bd280afba"
+ dependencies:
+ ccount "^1.0.0"
+ is-alphanumeric "^1.0.0"
+ is-decimal "^1.0.0"
+ is-whitespace-character "^1.0.0"
+ longest-streak "^2.0.1"
+ markdown-escapes "^1.0.0"
+ markdown-table "^1.1.0"
+ mdast-util-compact "^1.0.0"
+ parse-entities "^1.0.2"
+ repeat-string "^1.5.4"
+ state-toggle "^1.0.0"
+ stringify-entities "^1.0.1"
+ unherit "^1.0.4"
+ xtend "^4.0.1"
+
+remark@^9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/remark/-/remark-9.0.0.tgz#c5cfa8ec535c73a67c4b0f12bfdbd3a67d8b2f60"
+ dependencies:
+ remark-parse "^5.0.0"
+ remark-stringify "^5.0.0"
+ unified "^6.0.0"
+
+remove-trailing-separator@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
+
+repeat-element@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
+
+repeat-string@^1.5.2, repeat-string@^1.5.4, repeat-string@^1.6.1:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+
+repeating@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+ dependencies:
+ is-finite "^1.0.0"
+
+replace-ext@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb"
+
+require-directory@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+
+require-from-string@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
+
+require-main-filename@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
+
+require-uncached@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3"
+ dependencies:
+ caller-path "^0.1.0"
+ resolve-from "^1.0.0"
+
+resolve-cwd@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
+ dependencies:
+ resolve-from "^3.0.0"
+
+resolve-from@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
+
+resolve-from@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
+
+resolve-from@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+
+resolve-url@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
+
+resolve@^1.3.2, resolve@^1.5.0:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26"
+ dependencies:
+ path-parse "^1.0.5"
+
+restore-cursor@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
+ dependencies:
+ onetime "^2.0.0"
+ signal-exit "^3.0.2"
+
+ret@~0.1.10:
+ version "0.1.15"
+ resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
+
+rgb-hex@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/rgb-hex/-/rgb-hex-2.1.0.tgz#c773c5fe2268a25578d92539a82a7a5ce53beda6"
+
+rgb@~0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/rgb/-/rgb-0.1.0.tgz#be27b291e8feffeac1bd99729721bfa40fc037b5"
+
+rimraf@^2.2.8, rimraf@^2.4.4, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
+ dependencies:
+ glob "^7.0.5"
+
+ripemd160@^2.0.0, ripemd160@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
+ dependencies:
+ hash-base "^3.0.0"
+ inherits "^2.0.1"
+
+run-async@^2.2.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
+ dependencies:
+ is-promise "^2.1.0"
+
+run-queue@^1.0.0, run-queue@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47"
+ dependencies:
+ aproba "^1.1.1"
+
+rx-lite-aggregates@^4.0.8:
+ version "4.0.8"
+ resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be"
+ dependencies:
+ rx-lite "*"
+
+rx-lite@*, rx-lite@^4.0.8:
+ version "4.0.8"
+ resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444"
+
+rxjs@^6.1.0:
+ version "6.2.2"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.2.2.tgz#eb75fa3c186ff5289907d06483a77884586e1cf9"
+ dependencies:
+ tslib "^1.9.0"
+
+safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+
+safe-regex@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
+ dependencies:
+ ret "~0.1.10"
+
+"safer-buffer@>= 2.1.2 < 3":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+
+sax@^1.2.4, sax@~1.2.1:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
+
+schema-utils@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf"
+ dependencies:
+ ajv "^5.0.0"
+
+schema-utils@^0.4.0, schema-utils@^0.4.4, schema-utils@^0.4.5:
+ version "0.4.5"
+ resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.5.tgz#21836f0608aac17b78f9e3e24daff14a5ca13a3e"
+ dependencies:
+ ajv "^6.1.0"
+ ajv-keywords "^3.1.0"
+
+"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.3.0, semver@^5.5.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
+
+serialize-javascript@^1.4.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.5.0.tgz#1aa336162c88a890ddad5384baebc93a655161fe"
+
+set-blocking@^2.0.0, set-blocking@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+
+set-immediate-shim@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
+
+set-value@^0.4.3:
+ version "0.4.3"
+ resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1"
+ dependencies:
+ extend-shallow "^2.0.1"
+ is-extendable "^0.1.1"
+ is-plain-object "^2.0.1"
+ to-object-path "^0.3.0"
+
+set-value@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274"
+ dependencies:
+ extend-shallow "^2.0.1"
+ is-extendable "^0.1.1"
+ is-plain-object "^2.0.3"
+ split-string "^3.0.1"
+
+setimmediate@^1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+
+sha.js@^2.4.0, sha.js@^2.4.8:
+ version "2.4.11"
+ resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
+ dependencies:
+ inherits "^2.0.1"
+ safe-buffer "^5.0.1"
+
+shebang-command@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
+ dependencies:
+ shebang-regex "^1.0.0"
+
+shebang-regex@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
+
+signal-exit@^3.0.0, signal-exit@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+
+simple-swizzle@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
+ dependencies:
+ is-arrayish "^0.3.1"
+
+slash@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
+
+slice-ansi@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d"
+ dependencies:
+ is-fullwidth-code-point "^2.0.0"
+
+snapdragon-node@^2.0.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
+ dependencies:
+ define-property "^1.0.0"
+ isobject "^3.0.0"
+ snapdragon-util "^3.0.1"
+
+snapdragon-util@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
+ dependencies:
+ kind-of "^3.2.0"
+
+snapdragon@^0.8.1:
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
+ dependencies:
+ base "^0.11.1"
+ debug "^2.2.0"
+ define-property "^0.2.5"
+ extend-shallow "^2.0.1"
+ map-cache "^0.2.2"
+ source-map "^0.5.6"
+ source-map-resolve "^0.5.0"
+ use "^3.1.0"
+
+sort-keys@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
+ dependencies:
+ is-plain-obj "^1.0.0"
+
+source-list-map@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085"
+
+source-map-resolve@^0.5.0:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259"
+ dependencies:
+ atob "^2.1.1"
+ decode-uri-component "^0.2.0"
+ resolve-url "^0.2.1"
+ source-map-url "^0.4.0"
+ urix "^0.1.0"
+
+source-map-support@^0.4.15:
+ version "0.4.18"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f"
+ dependencies:
+ source-map "^0.5.6"
+
+source-map-url@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
+
+source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7:
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+
+source-map@^0.6.1, source-map@~0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+
+spdx-correct@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82"
+ dependencies:
+ spdx-expression-parse "^3.0.0"
+ spdx-license-ids "^3.0.0"
+
+spdx-exceptions@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9"
+
+spdx-expression-parse@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0"
+ dependencies:
+ spdx-exceptions "^2.1.0"
+ spdx-license-ids "^3.0.0"
+
+spdx-license-ids@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87"
+
+specificity@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/specificity/-/specificity-0.4.0.tgz#301b1ab5455987c37d6d94f8c956ef9d9fb48c1d"
+
+split-string@^3.0.1, split-string@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
+ dependencies:
+ extend-shallow "^3.0.0"
+
+sprintf-js@~1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+
+ssri@^5.2.4:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06"
+ dependencies:
+ safe-buffer "^5.1.1"
+
+state-toggle@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.1.tgz#c3cb0974f40a6a0f8e905b96789eb41afa1cde3a"
+
+static-extend@^0.1.1:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
+ dependencies:
+ define-property "^0.2.5"
+ object-copy "^0.1.0"
+
+stream-browserify@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
+ dependencies:
+ inherits "~2.0.1"
+ readable-stream "^2.0.2"
+
+stream-each@^1.1.0:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae"
+ dependencies:
+ end-of-stream "^1.1.0"
+ stream-shift "^1.0.0"
+
+stream-http@^2.7.2:
+ version "2.8.3"
+ resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc"
+ dependencies:
+ builtin-status-codes "^3.0.0"
+ inherits "^2.0.1"
+ readable-stream "^2.3.6"
+ to-arraybuffer "^1.0.0"
+ xtend "^4.0.0"
+
+stream-shift@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952"
+
+strict-uri-encode@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
+
+string-width@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+ dependencies:
+ code-point-at "^1.0.0"
+ is-fullwidth-code-point "^1.0.0"
+ strip-ansi "^3.0.0"
+
+"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
+ dependencies:
+ is-fullwidth-code-point "^2.0.0"
+ strip-ansi "^4.0.0"
+
+string_decoder@^1.0.0, string_decoder@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
+ dependencies:
+ safe-buffer "~5.1.0"
+
+string_decoder@~0.10.x:
+ version "0.10.31"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+
+stringify-entities@^1.0.1:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-1.3.2.tgz#a98417e5471fd227b3e45d3db1861c11caf668f7"
+ dependencies:
+ character-entities-html4 "^1.0.0"
+ character-entities-legacy "^1.0.0"
+ is-alphanumerical "^1.0.0"
+ is-hexadecimal "^1.0.0"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+ dependencies:
+ ansi-regex "^2.0.0"
+
+strip-ansi@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
+ dependencies:
+ ansi-regex "^3.0.0"
+
+strip-bom@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+
+strip-eof@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
+
+strip-indent@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68"
+
+strip-json-comments@~2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+
+style-search@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902"
+
+stylelint@^9.3.0:
+ version "9.4.0"
+ resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-9.4.0.tgz#2f2b82ae9db53a06735ae0724f41b134fdb84a10"
+ dependencies:
+ autoprefixer "^9.0.0"
+ balanced-match "^1.0.0"
+ chalk "^2.4.1"
+ cosmiconfig "^5.0.0"
+ debug "^3.0.0"
+ execall "^1.0.0"
+ file-entry-cache "^2.0.0"
+ get-stdin "^6.0.0"
+ globby "^8.0.0"
+ globjoin "^0.1.4"
+ html-tags "^2.0.0"
+ ignore "^4.0.0"
+ import-lazy "^3.1.0"
+ imurmurhash "^0.1.4"
+ known-css-properties "^0.6.0"
+ lodash "^4.17.4"
+ log-symbols "^2.0.0"
+ mathml-tag-names "^2.0.1"
+ meow "^5.0.0"
+ micromatch "^2.3.11"
+ normalize-selector "^0.2.0"
+ pify "^3.0.0"
+ postcss "^7.0.0"
+ postcss-html "^0.31.0"
+ postcss-less "^2.0.0"
+ postcss-markdown "^0.31.0"
+ postcss-media-query-parser "^0.2.3"
+ postcss-reporter "^5.0.0"
+ postcss-resolve-nested-selector "^0.1.1"
+ postcss-safe-parser "^4.0.0"
+ postcss-sass "^0.3.0"
+ postcss-scss "^2.0.0"
+ postcss-selector-parser "^3.1.0"
+ postcss-styled "^0.31.0"
+ postcss-syntax "^0.31.0"
+ postcss-value-parser "^3.3.0"
+ resolve-from "^4.0.0"
+ signal-exit "^3.0.2"
+ specificity "^0.4.0"
+ string-width "^2.1.0"
+ style-search "^0.1.0"
+ sugarss "^1.0.0"
+ svg-tags "^1.0.0"
+ table "^4.0.1"
+
+sugarss@^1.0.0, sugarss@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-1.0.1.tgz#be826d9003e0f247735f92365dc3fd7f1bae9e44"
+ dependencies:
+ postcss "^6.0.14"
+
+supports-color@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+
+supports-color@^3.2.3:
+ version "3.2.3"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
+ dependencies:
+ has-flag "^1.0.0"
+
+supports-color@^5.3.0, supports-color@^5.4.0:
+ version "5.4.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54"
+ dependencies:
+ has-flag "^3.0.0"
+
+svg-sprite-generator@0.0.7:
+ version "0.0.7"
+ resolved "https://registry.yarnpkg.com/svg-sprite-generator/-/svg-sprite-generator-0.0.7.tgz#159777ce3e83e800f255cedd311da761492163e9"
+ dependencies:
+ async "^1.3.0"
+ cheerio "^0.19.0"
+ commander "^2.8.1"
+ es6-promise "^2.3.0"
+
+svg-tags@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764"
+
+svgo@^0.7.0:
+ version "0.7.2"
+ resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5"
+ dependencies:
+ coa "~1.0.1"
+ colors "~1.1.2"
+ csso "~2.3.1"
+ js-yaml "~3.7.0"
+ mkdirp "~0.5.1"
+ sax "~1.2.1"
+ whet.extend "~0.9.9"
+
+table@4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36"
+ dependencies:
+ ajv "^5.2.3"
+ ajv-keywords "^2.1.0"
+ chalk "^2.1.0"
+ lodash "^4.17.4"
+ slice-ansi "1.0.0"
+ string-width "^2.1.1"
+
+table@^4.0.1:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc"
+ dependencies:
+ ajv "^6.0.1"
+ ajv-keywords "^3.0.0"
+ chalk "^2.1.0"
+ lodash "^4.17.4"
+ slice-ansi "1.0.0"
+ string-width "^2.1.1"
+
+tapable@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2"
+
+tar@^4:
+ version "4.4.6"
+ resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.6.tgz#63110f09c00b4e60ac8bcfe1bf3c8660235fbc9b"
+ dependencies:
+ chownr "^1.0.1"
+ fs-minipass "^1.2.5"
+ minipass "^2.3.3"
+ minizlib "^1.1.0"
+ mkdirp "^0.5.0"
+ safe-buffer "^5.1.2"
+ yallist "^3.0.2"
+
+text-table@~0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+
+through2@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"
+ dependencies:
+ readable-stream "^2.1.5"
+ xtend "~4.0.1"
+
+through@^2.3.6:
+ version "2.3.8"
+ resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
+
+timers-browserify@^2.0.4:
+ version "2.0.10"
+ resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae"
+ dependencies:
+ setimmediate "^1.0.4"
+
+tmp@^0.0.33:
+ version "0.0.33"
+ resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
+ dependencies:
+ os-tmpdir "~1.0.2"
+
+to-arraybuffer@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
+
+to-fast-properties@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
+
+to-object-path@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
+ dependencies:
+ kind-of "^3.0.2"
+
+to-regex-range@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
+ dependencies:
+ is-number "^3.0.0"
+ repeat-string "^1.6.1"
+
+to-regex@^3.0.1, to-regex@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
+ dependencies:
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ regex-not "^1.0.2"
+ safe-regex "^1.1.0"
+
+trim-newlines@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-2.0.0.tgz#b403d0b91be50c331dfc4b82eeceb22c3de16d20"
+
+trim-right@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
+
+trim-trailing-lines@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-1.1.1.tgz#e0ec0810fd3c3f1730516b45f49083caaf2774d9"
+
+trim@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd"
+
+trough@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.2.tgz#7f1663ec55c480139e2de5e486c6aef6cc24a535"
+
+ts-loader@^4.4.2:
+ version "4.4.2"
+ resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-4.4.2.tgz#778d4464b24436873c78f7f9e914d88194c2a248"
+ dependencies:
+ chalk "^2.3.0"
+ enhanced-resolve "^4.0.0"
+ loader-utils "^1.0.2"
+ micromatch "^3.1.4"
+ semver "^5.0.1"
+
+tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0:
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
+
+tslint-loader@^3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/tslint-loader/-/tslint-loader-3.6.0.tgz#12ed4d5ef57d68be25cd12692fb2108b66469d76"
+ dependencies:
+ loader-utils "^1.0.2"
+ mkdirp "^0.5.1"
+ object-assign "^4.1.1"
+ rimraf "^2.4.4"
+ semver "^5.3.0"
+
+tslint@^5.11.0:
+ version "5.11.0"
+ resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.11.0.tgz#98f30c02eae3cde7006201e4c33cb08b48581eed"
+ dependencies:
+ babel-code-frame "^6.22.0"
+ builtin-modules "^1.1.1"
+ chalk "^2.3.0"
+ commander "^2.12.1"
+ diff "^3.2.0"
+ glob "^7.1.1"
+ js-yaml "^3.7.0"
+ minimatch "^3.0.4"
+ resolve "^1.3.2"
+ semver "^5.3.0"
+ tslib "^1.8.0"
+ tsutils "^2.27.2"
+
+tsutils@^2.27.2:
+ version "2.29.0"
+ resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99"
+ dependencies:
+ tslib "^1.8.1"
+
+tty-browserify@0.0.0:
+ version "0.0.0"
+ resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
+
+type-check@~0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+ dependencies:
+ prelude-ls "~1.1.2"
+
+typedarray@^0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
+
+typescript@^2.9.2:
+ version "2.9.2"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c"
+
+uglify-es@^3.3.4:
+ version "3.3.9"
+ resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677"
+ dependencies:
+ commander "~2.13.0"
+ source-map "~0.6.1"
+
+uglifyjs-webpack-plugin@^1.2.4:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.7.tgz#57638dd99c853a1ebfe9d97b42160a8a507f9d00"
+ dependencies:
+ cacache "^10.0.4"
+ find-cache-dir "^1.0.0"
+ schema-utils "^0.4.5"
+ serialize-javascript "^1.4.0"
+ source-map "^0.6.1"
+ uglify-es "^3.3.4"
+ webpack-sources "^1.1.0"
+ worker-farm "^1.5.2"
+
+unherit@^1.0.4:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.1.tgz#132748da3e88eab767e08fabfbb89c5e9d28628c"
+ dependencies:
+ inherits "^2.0.1"
+ xtend "^4.0.1"
+
+unified@^6.0.0:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/unified/-/unified-6.2.0.tgz#7fbd630f719126d67d40c644b7e3f617035f6dba"
+ dependencies:
+ bail "^1.0.0"
+ extend "^3.0.0"
+ is-plain-obj "^1.1.0"
+ trough "^1.0.0"
+ vfile "^2.0.0"
+ x-is-string "^0.1.0"
+
+union-value@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4"
+ dependencies:
+ arr-union "^3.1.0"
+ get-value "^2.0.6"
+ is-extendable "^0.1.1"
+ set-value "^0.4.3"
+
+uniq@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
+
+uniqs@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02"
+
+unique-filename@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3"
+ dependencies:
+ unique-slug "^2.0.0"
+
+unique-slug@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab"
+ dependencies:
+ imurmurhash "^0.1.4"
+
+unist-util-find-all-after@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/unist-util-find-all-after/-/unist-util-find-all-after-1.0.2.tgz#9be49cfbae5ca1566b27536670a92836bf2f8d6d"
+ dependencies:
+ unist-util-is "^2.0.0"
+
+unist-util-is@^2.0.0, unist-util-is@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-2.1.2.tgz#1193fa8f2bfbbb82150633f3a8d2eb9a1c1d55db"
+
+unist-util-modify-children@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/unist-util-modify-children/-/unist-util-modify-children-1.1.2.tgz#c7f1b91712554ee59c47a05b551ed3e052a4e2d1"
+ dependencies:
+ array-iterate "^1.0.0"
+
+unist-util-remove-position@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-1.1.2.tgz#86b5dad104d0bbfbeb1db5f5c92f3570575c12cb"
+ dependencies:
+ unist-util-visit "^1.1.0"
+
+unist-util-stringify-position@^1.0.0, unist-util-stringify-position@^1.1.1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz#3f37fcf351279dcbca7480ab5889bb8a832ee1c6"
+
+unist-util-visit-parents@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-2.0.1.tgz#63fffc8929027bee04bfef7d2cce474f71cb6217"
+ dependencies:
+ unist-util-is "^2.1.2"
+
+unist-util-visit@^1.1.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.4.0.tgz#1cb763647186dc26f5e1df5db6bd1e48b3cc2fb1"
+ dependencies:
+ unist-util-visit-parents "^2.0.0"
+
+units-css@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/units-css/-/units-css-0.4.0.tgz#d6228653a51983d7c16ff28f8b9dc3b1ffed3a07"
+ dependencies:
+ isnumeric "^0.2.0"
+ viewport-dimensions "^0.2.0"
+
+unset-value@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
+ dependencies:
+ has-value "^0.3.1"
+ isobject "^3.0.0"
+
+upath@^1.0.5:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd"
+
+uri-js@^4.2.1:
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
+ dependencies:
+ punycode "^2.1.0"
+
+urix@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
+
+url@^0.11.0:
+ version "0.11.0"
+ resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
+ dependencies:
+ punycode "1.3.2"
+ querystring "0.2.0"
+
+use@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
+
+util-deprecate@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+
+util@0.10.3:
+ version "0.10.3"
+ resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
+ dependencies:
+ inherits "2.0.1"
+
+util@^0.10.3:
+ version "0.10.4"
+ resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901"
+ dependencies:
+ inherits "2.0.3"
+
+v8-compile-cache@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.0.tgz#526492e35fc616864284700b7043e01baee09f0a"
+
+validate-npm-package-license@^3.0.1:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338"
+ dependencies:
+ spdx-correct "^3.0.0"
+ spdx-expression-parse "^3.0.0"
+
+vendors@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.2.tgz#7fcb5eef9f5623b156bcea89ec37d63676f21801"
+
+vfile-location@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-2.0.3.tgz#083ba80e50968e8d420be49dd1ea9a992131df77"
+
+vfile-message@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-1.0.1.tgz#51a2ccd8a6b97a7980bb34efb9ebde9632e93677"
+ dependencies:
+ unist-util-stringify-position "^1.1.1"
+
+vfile@^2.0.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/vfile/-/vfile-2.3.0.tgz#e62d8e72b20e83c324bc6c67278ee272488bf84a"
+ dependencies:
+ is-buffer "^1.1.4"
+ replace-ext "1.0.0"
+ unist-util-stringify-position "^1.0.0"
+ vfile-message "^1.0.0"
+
+viewport-dimensions@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/viewport-dimensions/-/viewport-dimensions-0.2.0.tgz#de740747db5387fd1725f5175e91bac76afdf36c"
+
+vm-browserify@0.0.4:
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73"
+ dependencies:
+ indexof "0.0.1"
+
+watchpack@^1.5.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00"
+ dependencies:
+ chokidar "^2.0.2"
+ graceful-fs "^4.1.2"
+ neo-async "^2.5.0"
+
+webpack-cli@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.1.0.tgz#d71a83687dcfeb758fdceeb0fe042f96bcf62994"
+ dependencies:
+ chalk "^2.4.1"
+ cross-spawn "^6.0.5"
+ enhanced-resolve "^4.0.0"
+ global-modules-path "^2.1.0"
+ import-local "^1.0.0"
+ inquirer "^6.0.0"
+ interpret "^1.1.0"
+ loader-utils "^1.1.0"
+ supports-color "^5.4.0"
+ v8-compile-cache "^2.0.0"
+ yargs "^12.0.1"
+
+webpack-sources@^1.0.1, webpack-sources@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54"
+ dependencies:
+ source-list-map "^2.0.0"
+ source-map "~0.6.1"
+
+webpack@^4.16.2:
+ version "4.16.4"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.16.4.tgz#6b020f76483bc66339164c296d89978aa100d37a"
+ dependencies:
+ "@webassemblyjs/ast" "1.5.13"
+ "@webassemblyjs/helper-module-context" "1.5.13"
+ "@webassemblyjs/wasm-edit" "1.5.13"
+ "@webassemblyjs/wasm-opt" "1.5.13"
+ "@webassemblyjs/wasm-parser" "1.5.13"
+ acorn "^5.6.2"
+ acorn-dynamic-import "^3.0.0"
+ ajv "^6.1.0"
+ ajv-keywords "^3.1.0"
+ chrome-trace-event "^1.0.0"
+ enhanced-resolve "^4.1.0"
+ eslint-scope "^4.0.0"
+ json-parse-better-errors "^1.0.2"
+ loader-runner "^2.3.0"
+ loader-utils "^1.1.0"
+ memory-fs "~0.4.1"
+ micromatch "^3.1.8"
+ mkdirp "~0.5.0"
+ neo-async "^2.5.0"
+ node-libs-browser "^2.0.0"
+ schema-utils "^0.4.4"
+ tapable "^1.0.0"
+ uglifyjs-webpack-plugin "^1.2.4"
+ watchpack "^1.5.0"
+ webpack-sources "^1.0.1"
+
+whet.extend@~0.9.9:
+ version "0.9.9"
+ resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1"
+
+which-module@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
+
+which@^1.2.9:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
+ dependencies:
+ isexe "^2.0.0"
+
+wide-align@^1.1.0:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
+ dependencies:
+ string-width "^1.0.2 || 2"
+
+wordwrap@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+
+worker-farm@^1.5.2:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0"
+ dependencies:
+ errno "~0.1.7"
+
+wrap-ansi@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
+ dependencies:
+ string-width "^1.0.1"
+ strip-ansi "^3.0.1"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+
+write@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757"
+ dependencies:
+ mkdirp "^0.5.1"
+
+x-is-string@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82"
+
+xregexp@4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020"
+
+xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+
+"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
+
+yallist@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
+
+yallist@^3.0.0, yallist@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9"
+
+yargs-parser@^10.0.0, yargs-parser@^10.1.0:
+ version "10.1.0"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8"
+ dependencies:
+ camelcase "^4.1.0"
+
+yargs@^12.0.1:
+ version "12.0.1"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.1.tgz#6432e56123bb4e7c3562115401e98374060261c2"
+ dependencies:
+ cliui "^4.0.0"
+ decamelize "^2.0.0"
+ find-up "^3.0.0"
+ get-caller-file "^1.0.1"
+ os-locale "^2.0.0"
+ require-directory "^2.1.1"
+ require-main-filename "^1.0.1"
+ set-blocking "^2.0.0"
+ string-width "^2.0.0"
+ which-module "^2.0.0"
+ y18n "^3.2.1 || ^4.0.0"
+ yargs-parser "^10.1.0"