├── .github
└── workflows
│ └── build.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── copyright-header.txt
├── example
├── editor_contents.js
├── example.css
├── example.js
└── index.html
├── package-lock.json
├── package.json
├── rollup.config.js
├── scripts
├── build-css.js
└── enhance-types.js
├── src
├── css
│ └── ace-collab-ext.css
└── ts
│ ├── AceCursorMarker.ts
│ ├── AceMultiCursorManager.ts
│ ├── AceMultiSelectionManager.ts
│ ├── AceRadarView.ts
│ ├── AceRadarViewIndicator.ts
│ ├── AceRangeUtil.ts
│ ├── AceSelectionMarker.ts
│ ├── AceViewportUtil.ts
│ ├── IndexRange.ts
│ ├── RowRange.ts
│ └── index.ts
├── tsconfig.json
└── tslint.json
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: Build
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 | pull_request:
10 | branches: [ master ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | strategy:
18 | matrix:
19 | node-version: [14.x]
20 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
21 |
22 | steps:
23 | - uses: actions/checkout@v2
24 | - name: Use Node.js ${{ matrix.node-version }}
25 | uses: actions/setup-node@v2
26 | with:
27 | node-version: ${{ matrix.node-version }}
28 | cache: 'npm'
29 | - run: npm ci
30 | - run: npm run dist
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | node_modules
3 | dist
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | ## [v0.6.0](https://github.com/convergencelabs/ace-collab-ext/tree/0.6.0) (2021-07-10)
4 |
5 | **Enhancements:**
6 | - Moved from webpack to rollup.
7 | - Removed gulp in favor of a straight node build.
8 | - Migrated from Travis CI to GitHub Actions.
9 |
10 |
11 | ## [v0.5.0](https://github.com/convergencelabs/ace-collab-ext/tree/0.5.0) (2020-03-14)
12 |
13 | **Enhancements:**
14 | - Moves from the `@convergence` to `@convergencelabs` scope.
15 |
16 | **Fixes:**
17 | - [\#15](https://github.com/convergencelabs/ace-collab-ext/issues/15) Fixed bad module import in the AceRadarView.
18 |
19 | ## [v0.4.0](https://github.com/convergencelabs/ace-collab-ext/tree/0.4.0) (2019-03-15)
20 |
21 | **Enhancements:**
22 | - [\#7](https://github.com/convergencelabs/ace-collab-ext/issues/7) Migrate from `brace` to `ace-builds`.
23 |
24 |
25 | ## [v0.3.0](https://github.com/convergencelabs/ace-collab-ext/tree/0.3.0) (2019-01-23)
26 |
27 | **Enhancements:**
28 | - [\#5](https://github.com/convergencelabs/ace-collab-ext/issues/5) Add cursor user tooltips.
29 | - [\#6](https://github.com/convergencelabs/ace-collab-ext/issues/6) Update to work with Ace > 1.4.0.
30 |
31 |
32 | ## [v0.2.3](https://github.com/convergencelabs/ace-collab-ext/tree/0.2.3) (2018-11-13)
33 |
34 | **Fixes:**
35 |
36 | - [\#4](https://github.com/convergencelabs/ace-collab-ext/pull/4) Improved selection when line wrapping is enabled.
37 |
38 |
39 | ## [v0.2.2](https://github.com/convergencelabs/ace-collab-ext/tree/0.2.2) (2018-05-01)
40 |
41 | **Enhancements:**
42 |
43 | - Added the RadarView.clearView method.
44 |
45 |
46 | ## [v0.2.1](https://github.com/convergencelabs/ace-collab-ext/tree/0.2.1) (2018-05-01)
47 |
48 | **Enhancements:**
49 |
50 | - Improved typings to better support UMD imports.
51 | - Updated the Multi Cursor Manager to accept Positions in addition to Indices
52 |
53 |
54 | ## [v0.2.0](https://github.com/convergencelabs/ace-collab-ext/tree/0.2.0) (2018-05-01)
55 |
56 | **Enhancements:**
57 |
58 | - [\#2](https://github.com/convergencelabs/ace-collab-ext/issues/2) The library now contains typescript definitions.
59 | - [\#3](https://github.com/convergencelabs/ace-collab-ext/issues/3) The common js build is no longer webpacked.
60 |
61 |
62 | ## [v0.1.1](https://github.com/convergencelabs/ace-collab-ext/tree/0.1.1) (2017-01-10)
63 |
64 | **Enhancements:**
65 |
66 | - [\#1](https://github.com/convergencelabs/ace-collab-ext/issues/1) The AceMultiCursorManager and AceMultiSelectionManager constructors now take an Ace EditSession instance instead of the Ace Editor instance so they can be initialized with a session before the editor is constructed.
67 |
68 |
69 | ## [v0.1.0](https://github.com/convergencelabs/ace-collab-ext/tree/0.1.0) (2016-12-27)
70 |
71 | - Initial release.
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016 Convergence Labs, Inc.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7 | of the Software, and to permit persons to whom the Software is furnished to do
8 | so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
17 | AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
18 | THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Ace Collaborative Extensions
2 | [](https://github.com/convergencelabs/ace-collab-ext/actions/workflows/build.yml)
3 |
4 | Enhances the [Ace Editor](https://github.com/ajaxorg/ace) by adding the ability to render cues about what remote users are doing in the system.
5 |
6 | ## Installation
7 |
8 | Install package with NPM and add it to your development dependencies:
9 |
10 | For versions >= 0.5.0 (current):
11 | ```npm install --save-dev @convergencelabs/ace-collab-ext```
12 |
13 | For versions <= 0.4.0 (previous):
14 | ```npm install --save-dev @convergence/ace-collab-ext```
15 |
16 | ## Demo
17 | Go [here](https://examples.convergence.io/examples/ace/) to see a live demo of multiple cursors, multiple selections, and remote scrollbars (Visit on multiple browsers, or even better, point a friend to it too). This uses [Convergence](https://convergence.io) to handle the synchronization of data and user actions.
18 |
19 | ## Usage
20 |
21 | ### CSS
22 | Be sure to include one of CSS files located in the css directory of the node modules:
23 |
24 | * `css/ace-collab-ext.css`
25 | * `css/ace-collab-ext.min.css`
26 |
27 | How to do this will depend on how you are packaging and distributing your application. For example if you are bundling your css / sass / less you might be able to use an `@import` statement or you might `require` it. If you are hotlinking, you might need to at a `` tag to your document.
28 |
29 | If you forget to include the styles, its likely that the remote cursors / selections will either not show up, or they will not properly move.
30 |
31 | ### Multi Cursor Manager
32 | The multi cursor manager allows you to easily render the cursors of other users
33 | working in the same document. The cursor position can be represented as either
34 | a single linear index or as a 2-dimensional position in the form of
35 | ```{row: 0, column: 10}```.
36 |
37 | ```javascript
38 | const editor = ace.edit("editor");
39 | const curMgr = new AceCollabExt.AceMultiCursorManager(editor.getSession());
40 |
41 | // Add a new remote cursor with an id of "uid1", and a color of orange.
42 | curMgr.addCursor("uid1", "User 1", "orange", {row: 0, column: 10});
43 |
44 | // Set cursor for "uid1" to index 10.
45 | curMgr.setCursor("uid1", 10);
46 |
47 | // Clear the remote cursor for "uid1" without removing it.
48 | curMgr.clearCursor("uid1");
49 |
50 | // Remove the remote cursor for "uid1".
51 | curMgr.removeCursor("uid1");
52 | ```
53 |
54 | ### Multi Selection Manager
55 | The multi selection manager allows you to easily render the selection of other
56 | users working in the same document. Selection is represented by an array of
57 | AceRanges. A single range is common for normal selection, but multiple ranges
58 | are needed to support block selection.
59 |
60 | ```javascript
61 | const AceRange = ace.require("ace/range");
62 |
63 | const editor = ace.edit("editor");
64 | const selMgr = new AceCollabExt.AceMultiSelectionManager(editor.getSession());
65 |
66 | // A two-line block selection
67 | const initialRanges = [
68 | new AceRange(0, 0, 0, 10),
69 | new AceRange(1, 0, 1, 10),
70 | ];
71 |
72 | // Add a new remote view indicator with an id of "uid1", and a color of orange.
73 | selMgr.addSelection("uid1", "User 1", "orange", initialRanges);
74 |
75 | // Set the selection to a new range.
76 | selMgr.setSelection("uid1", new AceRange(10, 0, 11, 10));
77 |
78 | // Nullify the selection without removing the marker.
79 | selMgr.clearSelection("uid1");
80 |
81 | // Remove the remote view indicator for "uid1".
82 | selMgr.removeSelection("uid1");
83 | ```
84 |
85 | ### Radar View
86 | A radar view indicates where in a document another user is looking and allows
87 | you to easily go to the location in the document.
88 |
89 | ```javascript
90 | const editor = ace.edit("editor");
91 | const radarView = new AceCollabExt.RadarView("radarView", editor);
92 |
93 | // Add a new remote view indicator with an id of "uid1", and a color of orange.
94 | radarView.addView("uid1", "user1", "orange", 0, 20, 0);
95 |
96 | // Set the viewport range of the indicator to span rows 10 through 40.
97 | radarView.setViewRows("uid1", 10, 40);
98 |
99 | // Set the row location of the cursor to line 10.
100 | radarView.setCursorRow("uid1", 10);
101 |
102 | // Remove the remote view indicator for "uid1".
103 | radarView.removeView("uid1");
104 | ```
105 |
--------------------------------------------------------------------------------
/copyright-header.txt:
--------------------------------------------------------------------------------
1 | © 2016-2021 Convergence Labs, Inc.
2 | @version <%= pkg.version %>
3 | @license MIT
--------------------------------------------------------------------------------
/example/editor_contents.js:
--------------------------------------------------------------------------------
1 | var editorContents = `var observableProto;
2 |
3 | /**
4 | * Represents a push-style collection.
5 | */
6 | var Observable = Rx.Observable = (function () {
7 |
8 | function makeSubscribe(self, subscribe) {
9 | return function (o) {
10 | var oldOnError = o.onError;
11 | o.onError = function (e) {
12 | makeStackTraceLong(e, self);
13 | oldOnError.call(o, e);
14 | };
15 |
16 | return subscribe.call(self, o);
17 | };
18 | }
19 |
20 | function Observable() {
21 | if (Rx.config.longStackSupport && hasStacks) {
22 | var oldSubscribe = this._subscribe;
23 | var e = tryCatch(thrower)(new Error()).e;
24 | this.stack = e.stack.substring(e.stack.indexOf('\\n') + 1);
25 | this._subscribe = makeSubscribe(this, oldSubscribe);
26 | }
27 | }
28 |
29 | observableProto = Observable.prototype;
30 |
31 | /**
32 | * Determines whether the given object is an Observable
33 | * @param {Any} An object to determine whether it is an Observable
34 | * @returns {Boolean} true if an Observable, else false.
35 | */
36 | Observable.isObservable = function (o) {
37 | return o && isFunction(o.subscribe);
38 | };
39 |
40 | /**
41 | * Subscribes an o to the observable sequence.
42 | * @param {Mixed} [oOrOnNext] The object that is to receive notifications or an action to invoke for each element in the observable sequence.
43 | * @param {Function} [onError] Action to invoke upon exceptional termination of the observable sequence.
44 | * @param {Function} [onCompleted] Action to invoke upon graceful termination of the observable sequence.
45 | * @returns {Diposable} A disposable handling the subscriptions and unsubscriptions.
46 | */
47 | observableProto.subscribe = observableProto.forEach = function (oOrOnNext, onError, onCompleted) {
48 | return this._subscribe(typeof oOrOnNext === 'object' ?
49 | oOrOnNext :
50 | observerCreate(oOrOnNext, onError, onCompleted));
51 | };
52 |
53 | /**
54 | * Subscribes to the next value in the sequence with an optional "this" argument.
55 | * @param {Function} onNext The function to invoke on each element in the observable sequence.
56 | * @param {Any} [thisArg] Object to use as this when executing callback.
57 | * @returns {Disposable} A disposable handling the subscriptions and unsubscriptions.
58 | */
59 | observableProto.subscribeOnNext = function (onNext, thisArg) {
60 | return this._subscribe(observerCreate(typeof thisArg !== 'undefined' ? function(x) { onNext.call(thisArg, x); } : onNext));
61 | };
62 |
63 | /**
64 | * Subscribes to an exceptional condition in the sequence with an optional "this" argument.
65 | * @param {Function} onError The function to invoke upon exceptional termination of the observable sequence.
66 | * @param {Any} [thisArg] Object to use as this when executing callback.
67 | * @returns {Disposable} A disposable handling the subscriptions and unsubscriptions.
68 | */
69 | observableProto.subscribeOnError = function (onError, thisArg) {
70 | return this._subscribe(observerCreate(null, typeof thisArg !== 'undefined' ? function(e) { onError.call(thisArg, e); } : onError));
71 | };
72 |
73 | /**
74 | * Subscribes to the next value in the sequence with an optional "this" argument.
75 | * @param {Function} onCompleted The function to invoke upon graceful termination of the observable sequence.
76 | * @param {Any} [thisArg] Object to use as this when executing callback.
77 | * @returns {Disposable} A disposable handling the subscriptions and unsubscriptions.
78 | */
79 | observableProto.subscribeOnCompleted = function (onCompleted, thisArg) {
80 | return this._subscribe(observerCreate(null, null, typeof thisArg !== 'undefined' ? function() { onCompleted.call(thisArg); } : onCompleted));
81 | };
82 |
83 | return Observable;
84 | })();`;
--------------------------------------------------------------------------------
/example/example.css:
--------------------------------------------------------------------------------
1 | .body {
2 | margin: 0;
3 | }
4 |
5 | .main-container {
6 | position: absolute;
7 | top: 0;
8 | bottom: 0;
9 | left: 0;
10 | right: 0;
11 | display: flex;
12 | flex-direction: column;
13 | padding: 5px;
14 | }
15 |
16 | .title {
17 | font-family: "Helvetica Neue", sans-serif;
18 | font-size: 18px;
19 | font-weight: bold;
20 | margin-bottom: 10px;
21 | }
22 |
23 | .editors {
24 | display: flex;
25 | flex-direction: row;
26 | flex: 1;
27 | }
28 |
29 | .editor-column {
30 | display: flex;
31 | flex-direction: column;
32 | flex: 1;
33 | }
34 |
35 | .editor-label {
36 | text-align: center;
37 | font-family: "Helvetica Neue", sans-serif;
38 | font-size: 14px;
39 | font-weight: bold;
40 | margin-bottom: 10px;
41 | }
42 |
43 | .editor {
44 | display: inline-block;
45 | margin-left: 10px;
46 | flex: 1;
47 | }
48 |
49 | .wrapped-editor {
50 | flex: 1;
51 | display: flex;
52 | }
53 |
54 | #target-radar-view {
55 | display: inline-block;
56 | min-width: 20px;
57 | background: #2F3129;
58 | }
59 |
60 |
--------------------------------------------------------------------------------
/example/example.js:
--------------------------------------------------------------------------------
1 | const sourceUser = {
2 | id: "source",
3 | label: "Source User",
4 | color: "orange"
5 | };
6 |
7 | const sourceEditor = initEditor("source-editor");
8 | const sourceSession = sourceEditor.getSession();
9 |
10 | const targetEditor = initEditor("target-editor");
11 | targetEditor.setReadOnly(true);
12 |
13 | const targetCursorManager = new AceCollabExt.AceMultiCursorManager(targetEditor.getSession());
14 | targetCursorManager.addCursor(sourceUser.id, sourceUser.label, sourceUser.color, 0);
15 |
16 | const targetSelectionManager = new AceCollabExt.AceMultiSelectionManager(targetEditor.getSession());
17 | targetSelectionManager.addSelection(sourceUser.id, sourceUser.label, sourceUser.color, []);
18 |
19 | const radarView = new AceCollabExt.AceRadarView("target-radar-view", targetEditor);
20 |
21 |
22 | setTimeout(function() {
23 | radarView.addView("fake1", "fake1", "RoyalBlue", {start: 60, end: 75}, 50);
24 | radarView.addView("fake2", "fake2", "lightgreen", {start: 10, end: 50}, 30);
25 |
26 | const initialIndices = AceCollabExt.AceViewportUtil.getVisibleIndexRange(sourceEditor);
27 | const initialRows = AceCollabExt.AceViewportUtil.indicesToRows(sourceEditor, initialIndices.start, initialIndices.end);
28 | radarView.addView(sourceUser.id, sourceUser.label, sourceUser.color, initialRows, 0);
29 | }, 0);
30 |
31 | sourceSession.getDocument().on("change", function(e) {
32 | targetEditor.getSession().getDocument().applyDeltas([e]);
33 | });
34 |
35 | sourceSession.on("changeScrollTop", function (scrollTop) {
36 | setTimeout(function () {
37 | const viewportIndices = AceCollabExt.AceViewportUtil.getVisibleIndexRange(sourceEditor);
38 | const rows = AceCollabExt.AceViewportUtil.indicesToRows(sourceEditor, viewportIndices.start, viewportIndices.end);
39 | radarView.setViewRows(sourceUser.id, rows);
40 | }, 0);
41 | });
42 |
43 | sourceSession.selection.on('changeCursor', function(e) {
44 | const cursor = sourceEditor.getCursorPosition();
45 | targetCursorManager.setCursor(sourceUser.id, cursor);
46 | radarView.setCursorRow(sourceUser.id, cursor.row);
47 | });
48 |
49 | sourceSession.selection.on('changeSelection', function(e) {
50 | const rangesJson = AceCollabExt.AceRangeUtil.toJson(sourceEditor.selection.getAllRanges());
51 | const ranges = AceCollabExt.AceRangeUtil.fromJson(rangesJson);
52 | targetSelectionManager.setSelection(sourceUser.id, ranges);
53 | });
54 |
55 | function initEditor(id) {
56 | const editor = ace.edit(id);
57 | editor.setTheme('ace/theme/monokai');
58 |
59 | const session = editor.getSession();
60 | session.setMode('ace/mode/javascript');
61 | session.setValue(editorContents);
62 |
63 | return editor;
64 | }
65 |
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ACE Collaborative Demo
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
Ace Collaborative Example
17 |
18 |
19 |
Source Editor
20 |
21 |
22 |
23 |
Target Editor
24 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@convergencelabs/ace-collab-ext",
3 | "version": "0.6.0",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "@convergencelabs/ace-collab-ext",
9 | "version": "0.6.0",
10 | "license": "MIT",
11 | "dependencies": {
12 | "ace-builds": "^1.4.12"
13 | },
14 | "devDependencies": {
15 | "@rollup/plugin-commonjs": "19.0.0",
16 | "@rollup/plugin-node-resolve": "13.0.0",
17 | "@rollup/plugin-typescript": "8.2.1",
18 | "@types/backbone": "1.4.1",
19 | "clean-css": "^5.1.3",
20 | "fs-extra": "^10.0.0",
21 | "rimraf": "^3.0.2",
22 | "rollup": "2.47.0",
23 | "rollup-plugin-license": "2.3.0",
24 | "rollup-plugin-terser": "7.0.2",
25 | "tslib": "^2.3.0",
26 | "typescript": "4.2.4"
27 | }
28 | },
29 | "node_modules/@babel/code-frame": {
30 | "version": "7.14.5",
31 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz",
32 | "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==",
33 | "dev": true,
34 | "dependencies": {
35 | "@babel/highlight": "^7.14.5"
36 | },
37 | "engines": {
38 | "node": ">=6.9.0"
39 | }
40 | },
41 | "node_modules/@babel/helper-validator-identifier": {
42 | "version": "7.14.5",
43 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz",
44 | "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==",
45 | "dev": true,
46 | "engines": {
47 | "node": ">=6.9.0"
48 | }
49 | },
50 | "node_modules/@babel/highlight": {
51 | "version": "7.14.5",
52 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
53 | "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
54 | "dev": true,
55 | "dependencies": {
56 | "@babel/helper-validator-identifier": "^7.14.5",
57 | "chalk": "^2.0.0",
58 | "js-tokens": "^4.0.0"
59 | },
60 | "engines": {
61 | "node": ">=6.9.0"
62 | }
63 | },
64 | "node_modules/@rollup/plugin-commonjs": {
65 | "version": "19.0.0",
66 | "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-19.0.0.tgz",
67 | "integrity": "sha512-adTpD6ATGbehdaQoZQ6ipDFhdjqsTgpOAhFiPwl+dzre4pPshsecptDPyEFb61JMJ1+mGljktaC4jI8ARMSNyw==",
68 | "dev": true,
69 | "dependencies": {
70 | "@rollup/pluginutils": "^3.1.0",
71 | "commondir": "^1.0.1",
72 | "estree-walker": "^2.0.1",
73 | "glob": "^7.1.6",
74 | "is-reference": "^1.2.1",
75 | "magic-string": "^0.25.7",
76 | "resolve": "^1.17.0"
77 | },
78 | "engines": {
79 | "node": ">= 8.0.0"
80 | },
81 | "peerDependencies": {
82 | "rollup": "^2.38.3"
83 | }
84 | },
85 | "node_modules/@rollup/plugin-node-resolve": {
86 | "version": "13.0.0",
87 | "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.0.0.tgz",
88 | "integrity": "sha512-41X411HJ3oikIDivT5OKe9EZ6ud6DXudtfNrGbC4nniaxx2esiWjkLOzgnZsWq1IM8YIeL2rzRGLZLBjlhnZtQ==",
89 | "dev": true,
90 | "dependencies": {
91 | "@rollup/pluginutils": "^3.1.0",
92 | "@types/resolve": "1.17.1",
93 | "builtin-modules": "^3.1.0",
94 | "deepmerge": "^4.2.2",
95 | "is-module": "^1.0.0",
96 | "resolve": "^1.19.0"
97 | },
98 | "engines": {
99 | "node": ">= 10.0.0"
100 | },
101 | "peerDependencies": {
102 | "rollup": "^2.42.0"
103 | }
104 | },
105 | "node_modules/@rollup/plugin-node-resolve/node_modules/builtin-modules": {
106 | "version": "3.2.0",
107 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz",
108 | "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==",
109 | "dev": true,
110 | "engines": {
111 | "node": ">=6"
112 | },
113 | "funding": {
114 | "url": "https://github.com/sponsors/sindresorhus"
115 | }
116 | },
117 | "node_modules/@rollup/plugin-typescript": {
118 | "version": "8.2.1",
119 | "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.2.1.tgz",
120 | "integrity": "sha512-Qd2E1pleDR4bwyFxqbjt4eJf+wB0UKVMLc7/BAFDGVdAXQMCsD4DUv5/7/ww47BZCYxWtJqe1Lo0KVNswBJlRw==",
121 | "dev": true,
122 | "dependencies": {
123 | "@rollup/pluginutils": "^3.1.0",
124 | "resolve": "^1.17.0"
125 | },
126 | "engines": {
127 | "node": ">=8.0.0"
128 | },
129 | "peerDependencies": {
130 | "rollup": "^2.14.0",
131 | "tslib": "*",
132 | "typescript": ">=3.7.0"
133 | }
134 | },
135 | "node_modules/@rollup/pluginutils": {
136 | "version": "3.1.0",
137 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
138 | "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==",
139 | "dev": true,
140 | "dependencies": {
141 | "@types/estree": "0.0.39",
142 | "estree-walker": "^1.0.1",
143 | "picomatch": "^2.2.2"
144 | },
145 | "engines": {
146 | "node": ">= 8.0.0"
147 | },
148 | "peerDependencies": {
149 | "rollup": "^1.20.0||^2.0.0"
150 | }
151 | },
152 | "node_modules/@rollup/pluginutils/node_modules/estree-walker": {
153 | "version": "1.0.1",
154 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
155 | "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
156 | "dev": true
157 | },
158 | "node_modules/@types/backbone": {
159 | "version": "1.4.1",
160 | "resolved": "https://registry.npmjs.org/@types/backbone/-/backbone-1.4.1.tgz",
161 | "integrity": "sha512-KYfGuQy4d2vvYXbn0uHFZ6brFLndatTMomxBlljpbWf4kFpA3BG/6LA3ec+J9iredrX6eAVI7sm9SVAvwiIM6g==",
162 | "dev": true,
163 | "dependencies": {
164 | "@types/jquery": "*",
165 | "@types/underscore": "*"
166 | }
167 | },
168 | "node_modules/@types/estree": {
169 | "version": "0.0.39",
170 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
171 | "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
172 | "dev": true
173 | },
174 | "node_modules/@types/jquery": {
175 | "version": "3.5.6",
176 | "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.6.tgz",
177 | "integrity": "sha512-SmgCQRzGPId4MZQKDj9Hqc6kSXFNWZFHpELkyK8AQhf8Zr6HKfCzFv9ZC1Fv3FyQttJZOlap3qYb12h61iZAIg==",
178 | "dev": true,
179 | "dependencies": {
180 | "@types/sizzle": "*"
181 | }
182 | },
183 | "node_modules/@types/node": {
184 | "version": "13.9.1",
185 | "resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.1.tgz",
186 | "integrity": "sha512-E6M6N0blf/jiZx8Q3nb0vNaswQeEyn0XlupO+xN6DtJ6r6IT4nXrTry7zhIfYvFCl3/8Cu6WIysmUBKiqV0bqQ==",
187 | "dev": true
188 | },
189 | "node_modules/@types/resolve": {
190 | "version": "1.17.1",
191 | "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
192 | "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==",
193 | "dev": true,
194 | "dependencies": {
195 | "@types/node": "*"
196 | }
197 | },
198 | "node_modules/@types/sizzle": {
199 | "version": "2.3.3",
200 | "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz",
201 | "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==",
202 | "dev": true
203 | },
204 | "node_modules/@types/underscore": {
205 | "version": "1.11.3",
206 | "resolved": "https://registry.npmjs.org/@types/underscore/-/underscore-1.11.3.tgz",
207 | "integrity": "sha512-Fl1TX1dapfXyDqFg2ic9M+vlXRktcPJrc4PR7sRc7sdVrjavg/JHlbUXBt8qWWqhJrmSqg3RNAkAPRiOYw6Ahw==",
208 | "dev": true
209 | },
210 | "node_modules/ace-builds": {
211 | "version": "1.4.12",
212 | "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.12.tgz",
213 | "integrity": "sha512-G+chJctFPiiLGvs3+/Mly3apXTcfgE45dT5yp12BcWZ1kUs+gm0qd3/fv4gsz6fVag4mM0moHVpjHDIgph6Psg=="
214 | },
215 | "node_modules/ansi-styles": {
216 | "version": "3.2.1",
217 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
218 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
219 | "dev": true,
220 | "dependencies": {
221 | "color-convert": "^1.9.0"
222 | },
223 | "engines": {
224 | "node": ">=4"
225 | }
226 | },
227 | "node_modules/array-find-index": {
228 | "version": "1.0.2",
229 | "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
230 | "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
231 | "dev": true,
232 | "engines": {
233 | "node": ">=0.10.0"
234 | }
235 | },
236 | "node_modules/balanced-match": {
237 | "version": "1.0.0",
238 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
239 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
240 | "dev": true
241 | },
242 | "node_modules/brace-expansion": {
243 | "version": "1.1.11",
244 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
245 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
246 | "dev": true,
247 | "dependencies": {
248 | "balanced-match": "^1.0.0",
249 | "concat-map": "0.0.1"
250 | }
251 | },
252 | "node_modules/buffer-from": {
253 | "version": "1.1.1",
254 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
255 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
256 | "dev": true
257 | },
258 | "node_modules/chalk": {
259 | "version": "2.4.2",
260 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
261 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
262 | "dev": true,
263 | "dependencies": {
264 | "ansi-styles": "^3.2.1",
265 | "escape-string-regexp": "^1.0.5",
266 | "supports-color": "^5.3.0"
267 | },
268 | "engines": {
269 | "node": ">=4"
270 | }
271 | },
272 | "node_modules/clean-css": {
273 | "version": "5.1.3",
274 | "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.1.3.tgz",
275 | "integrity": "sha512-qGXzUCDpLwAlPx0kYeU4QXjzQIcIYZbJjD4FNm7NnSjoP0hYMVZhHOpUYJ6AwfkMX2cceLRq54MeCgHy/va1cA==",
276 | "dev": true,
277 | "dependencies": {
278 | "source-map": "~0.6.0"
279 | },
280 | "engines": {
281 | "node": ">= 10.0"
282 | }
283 | },
284 | "node_modules/color-convert": {
285 | "version": "1.9.3",
286 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
287 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
288 | "dev": true,
289 | "dependencies": {
290 | "color-name": "1.1.3"
291 | }
292 | },
293 | "node_modules/color-name": {
294 | "version": "1.1.3",
295 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
296 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
297 | "dev": true
298 | },
299 | "node_modules/commenting": {
300 | "version": "1.1.0",
301 | "resolved": "https://registry.npmjs.org/commenting/-/commenting-1.1.0.tgz",
302 | "integrity": "sha512-YeNK4tavZwtH7jEgK1ZINXzLKm6DZdEMfsaaieOsCAN0S8vsY7UeuO3Q7d/M018EFgE+IeUAuBOKkFccBZsUZA==",
303 | "dev": true
304 | },
305 | "node_modules/commondir": {
306 | "version": "1.0.1",
307 | "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
308 | "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
309 | "dev": true
310 | },
311 | "node_modules/concat-map": {
312 | "version": "0.0.1",
313 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
314 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
315 | "dev": true
316 | },
317 | "node_modules/deepmerge": {
318 | "version": "4.2.2",
319 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
320 | "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
321 | "dev": true,
322 | "engines": {
323 | "node": ">=0.10.0"
324 | }
325 | },
326 | "node_modules/escape-string-regexp": {
327 | "version": "1.0.5",
328 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
329 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
330 | "dev": true,
331 | "engines": {
332 | "node": ">=0.8.0"
333 | }
334 | },
335 | "node_modules/estree-walker": {
336 | "version": "2.0.2",
337 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
338 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
339 | "dev": true
340 | },
341 | "node_modules/fs-extra": {
342 | "version": "10.0.0",
343 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz",
344 | "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==",
345 | "dev": true,
346 | "dependencies": {
347 | "graceful-fs": "^4.2.0",
348 | "jsonfile": "^6.0.1",
349 | "universalify": "^2.0.0"
350 | },
351 | "engines": {
352 | "node": ">=12"
353 | }
354 | },
355 | "node_modules/fs.realpath": {
356 | "version": "1.0.0",
357 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
358 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
359 | "dev": true
360 | },
361 | "node_modules/function-bind": {
362 | "version": "1.1.1",
363 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
364 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
365 | "dev": true
366 | },
367 | "node_modules/glob": {
368 | "version": "7.1.6",
369 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
370 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
371 | "dev": true,
372 | "dependencies": {
373 | "fs.realpath": "^1.0.0",
374 | "inflight": "^1.0.4",
375 | "inherits": "2",
376 | "minimatch": "^3.0.4",
377 | "once": "^1.3.0",
378 | "path-is-absolute": "^1.0.0"
379 | },
380 | "engines": {
381 | "node": "*"
382 | },
383 | "funding": {
384 | "url": "https://github.com/sponsors/isaacs"
385 | }
386 | },
387 | "node_modules/graceful-fs": {
388 | "version": "4.2.3",
389 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
390 | "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
391 | "dev": true
392 | },
393 | "node_modules/has": {
394 | "version": "1.0.3",
395 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
396 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
397 | "dev": true,
398 | "dependencies": {
399 | "function-bind": "^1.1.1"
400 | },
401 | "engines": {
402 | "node": ">= 0.4.0"
403 | }
404 | },
405 | "node_modules/has-flag": {
406 | "version": "3.0.0",
407 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
408 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
409 | "dev": true,
410 | "engines": {
411 | "node": ">=4"
412 | }
413 | },
414 | "node_modules/inflight": {
415 | "version": "1.0.6",
416 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
417 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
418 | "dev": true,
419 | "dependencies": {
420 | "once": "^1.3.0",
421 | "wrappy": "1"
422 | }
423 | },
424 | "node_modules/inherits": {
425 | "version": "2.0.3",
426 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
427 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
428 | "dev": true
429 | },
430 | "node_modules/is-core-module": {
431 | "version": "2.4.0",
432 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz",
433 | "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==",
434 | "dev": true,
435 | "dependencies": {
436 | "has": "^1.0.3"
437 | },
438 | "funding": {
439 | "url": "https://github.com/sponsors/ljharb"
440 | }
441 | },
442 | "node_modules/is-module": {
443 | "version": "1.0.0",
444 | "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
445 | "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
446 | "dev": true
447 | },
448 | "node_modules/is-reference": {
449 | "version": "1.2.1",
450 | "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
451 | "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
452 | "dev": true,
453 | "dependencies": {
454 | "@types/estree": "*"
455 | }
456 | },
457 | "node_modules/jest-worker": {
458 | "version": "26.6.2",
459 | "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
460 | "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==",
461 | "dev": true,
462 | "dependencies": {
463 | "@types/node": "*",
464 | "merge-stream": "^2.0.0",
465 | "supports-color": "^7.0.0"
466 | },
467 | "engines": {
468 | "node": ">= 10.13.0"
469 | }
470 | },
471 | "node_modules/jest-worker/node_modules/has-flag": {
472 | "version": "4.0.0",
473 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
474 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
475 | "dev": true,
476 | "engines": {
477 | "node": ">=8"
478 | }
479 | },
480 | "node_modules/jest-worker/node_modules/supports-color": {
481 | "version": "7.2.0",
482 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
483 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
484 | "dev": true,
485 | "dependencies": {
486 | "has-flag": "^4.0.0"
487 | },
488 | "engines": {
489 | "node": ">=8"
490 | }
491 | },
492 | "node_modules/js-tokens": {
493 | "version": "4.0.0",
494 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
495 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
496 | "dev": true
497 | },
498 | "node_modules/jsonfile": {
499 | "version": "6.1.0",
500 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
501 | "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
502 | "dev": true,
503 | "dependencies": {
504 | "universalify": "^2.0.0"
505 | },
506 | "optionalDependencies": {
507 | "graceful-fs": "^4.1.6"
508 | }
509 | },
510 | "node_modules/lodash": {
511 | "version": "4.17.21",
512 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
513 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
514 | "dev": true
515 | },
516 | "node_modules/magic-string": {
517 | "version": "0.25.7",
518 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
519 | "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
520 | "dev": true,
521 | "dependencies": {
522 | "sourcemap-codec": "^1.4.4"
523 | }
524 | },
525 | "node_modules/merge-stream": {
526 | "version": "2.0.0",
527 | "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
528 | "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
529 | "dev": true
530 | },
531 | "node_modules/minimatch": {
532 | "version": "3.0.4",
533 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
534 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
535 | "dev": true,
536 | "dependencies": {
537 | "brace-expansion": "^1.1.7"
538 | },
539 | "engines": {
540 | "node": "*"
541 | }
542 | },
543 | "node_modules/moment": {
544 | "version": "2.29.1",
545 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
546 | "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==",
547 | "dev": true,
548 | "engines": {
549 | "node": "*"
550 | }
551 | },
552 | "node_modules/once": {
553 | "version": "1.4.0",
554 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
555 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
556 | "dev": true,
557 | "dependencies": {
558 | "wrappy": "1"
559 | }
560 | },
561 | "node_modules/package-name-regex": {
562 | "version": "1.0.9",
563 | "resolved": "https://registry.npmjs.org/package-name-regex/-/package-name-regex-1.0.9.tgz",
564 | "integrity": "sha512-+U2oQCfEz2IlGqws8gmfKzdMDbSd6+RZp6UIFdKo+GAw3+o+kfnsgXkWtJ1JMoKhpP2kEvuYyTy1lXOEQEe0ZA==",
565 | "dev": true
566 | },
567 | "node_modules/path-is-absolute": {
568 | "version": "1.0.1",
569 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
570 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
571 | "dev": true,
572 | "engines": {
573 | "node": ">=0.10.0"
574 | }
575 | },
576 | "node_modules/path-parse": {
577 | "version": "1.0.6",
578 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
579 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
580 | "dev": true
581 | },
582 | "node_modules/picomatch": {
583 | "version": "2.3.0",
584 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
585 | "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
586 | "dev": true,
587 | "engines": {
588 | "node": ">=8.6"
589 | },
590 | "funding": {
591 | "url": "https://github.com/sponsors/jonschlinkert"
592 | }
593 | },
594 | "node_modules/randombytes": {
595 | "version": "2.1.0",
596 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
597 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
598 | "dev": true,
599 | "dependencies": {
600 | "safe-buffer": "^5.1.0"
601 | }
602 | },
603 | "node_modules/resolve": {
604 | "version": "1.20.0",
605 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
606 | "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
607 | "dev": true,
608 | "dependencies": {
609 | "is-core-module": "^2.2.0",
610 | "path-parse": "^1.0.6"
611 | },
612 | "funding": {
613 | "url": "https://github.com/sponsors/ljharb"
614 | }
615 | },
616 | "node_modules/rimraf": {
617 | "version": "3.0.2",
618 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
619 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
620 | "dev": true,
621 | "dependencies": {
622 | "glob": "^7.1.3"
623 | },
624 | "bin": {
625 | "rimraf": "bin.js"
626 | },
627 | "funding": {
628 | "url": "https://github.com/sponsors/isaacs"
629 | }
630 | },
631 | "node_modules/rollup": {
632 | "version": "2.47.0",
633 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.47.0.tgz",
634 | "integrity": "sha512-rqBjgq9hQfW0vRmz+0S062ORRNJXvwRpzxhFXORvar/maZqY6za3rgQ/p1Glg+j1hnc1GtYyQCPiAei95uTElg==",
635 | "dev": true,
636 | "bin": {
637 | "rollup": "dist/bin/rollup"
638 | },
639 | "engines": {
640 | "node": ">=10.0.0"
641 | },
642 | "optionalDependencies": {
643 | "fsevents": "~2.3.1"
644 | }
645 | },
646 | "node_modules/rollup-plugin-license": {
647 | "version": "2.3.0",
648 | "resolved": "https://registry.npmjs.org/rollup-plugin-license/-/rollup-plugin-license-2.3.0.tgz",
649 | "integrity": "sha512-oi8pL59fVTwXCkLUsZ8dVGVJjO7Hcc5UT0chJvKd0MktPgeYHSadkaicAYUemdYHHpjb0D3DyvedZAEPt+2r8w==",
650 | "dev": true,
651 | "dependencies": {
652 | "commenting": "1.1.0",
653 | "glob": "7.1.6",
654 | "lodash": "4.17.21",
655 | "magic-string": "0.25.7",
656 | "mkdirp": "1.0.4",
657 | "moment": "2.29.1",
658 | "package-name-regex": "1.0.9",
659 | "spdx-expression-validate": "2.0.0",
660 | "spdx-satisfies": "5.0.0"
661 | },
662 | "engines": {
663 | "node": ">=10.0.0"
664 | },
665 | "peerDependencies": {
666 | "rollup": "^1.0.0 || ^2.0.0"
667 | }
668 | },
669 | "node_modules/rollup-plugin-license/node_modules/mkdirp": {
670 | "version": "1.0.4",
671 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
672 | "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
673 | "dev": true,
674 | "bin": {
675 | "mkdirp": "bin/cmd.js"
676 | },
677 | "engines": {
678 | "node": ">=10"
679 | }
680 | },
681 | "node_modules/rollup-plugin-terser": {
682 | "version": "7.0.2",
683 | "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz",
684 | "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==",
685 | "dev": true,
686 | "dependencies": {
687 | "@babel/code-frame": "^7.10.4",
688 | "jest-worker": "^26.2.1",
689 | "serialize-javascript": "^4.0.0",
690 | "terser": "^5.0.0"
691 | },
692 | "peerDependencies": {
693 | "rollup": "^2.0.0"
694 | }
695 | },
696 | "node_modules/rollup-plugin-terser/node_modules/commander": {
697 | "version": "2.20.3",
698 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
699 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
700 | "dev": true
701 | },
702 | "node_modules/rollup-plugin-terser/node_modules/serialize-javascript": {
703 | "version": "4.0.0",
704 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
705 | "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
706 | "dev": true,
707 | "dependencies": {
708 | "randombytes": "^2.1.0"
709 | }
710 | },
711 | "node_modules/rollup-plugin-terser/node_modules/source-map": {
712 | "version": "0.7.3",
713 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
714 | "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
715 | "dev": true,
716 | "engines": {
717 | "node": ">= 8"
718 | }
719 | },
720 | "node_modules/rollup-plugin-terser/node_modules/terser": {
721 | "version": "5.7.1",
722 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.1.tgz",
723 | "integrity": "sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg==",
724 | "dev": true,
725 | "dependencies": {
726 | "commander": "^2.20.0",
727 | "source-map": "~0.7.2",
728 | "source-map-support": "~0.5.19"
729 | },
730 | "bin": {
731 | "terser": "bin/terser"
732 | },
733 | "engines": {
734 | "node": ">=10"
735 | }
736 | },
737 | "node_modules/rollup/node_modules/fsevents": {
738 | "version": "2.3.2",
739 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
740 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
741 | "dev": true,
742 | "hasInstallScript": true,
743 | "optional": true,
744 | "os": [
745 | "darwin"
746 | ],
747 | "engines": {
748 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
749 | }
750 | },
751 | "node_modules/safe-buffer": {
752 | "version": "5.1.2",
753 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
754 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
755 | "dev": true
756 | },
757 | "node_modules/source-map": {
758 | "version": "0.6.1",
759 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
760 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
761 | "dev": true,
762 | "engines": {
763 | "node": ">=0.10.0"
764 | }
765 | },
766 | "node_modules/source-map-support": {
767 | "version": "0.5.19",
768 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
769 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
770 | "dev": true,
771 | "dependencies": {
772 | "buffer-from": "^1.0.0",
773 | "source-map": "^0.6.0"
774 | }
775 | },
776 | "node_modules/sourcemap-codec": {
777 | "version": "1.4.8",
778 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
779 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
780 | "dev": true
781 | },
782 | "node_modules/spdx-compare": {
783 | "version": "1.0.0",
784 | "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz",
785 | "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==",
786 | "dev": true,
787 | "dependencies": {
788 | "array-find-index": "^1.0.2",
789 | "spdx-expression-parse": "^3.0.0",
790 | "spdx-ranges": "^2.0.0"
791 | }
792 | },
793 | "node_modules/spdx-exceptions": {
794 | "version": "2.2.0",
795 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
796 | "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
797 | "dev": true
798 | },
799 | "node_modules/spdx-expression-parse": {
800 | "version": "3.0.0",
801 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
802 | "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
803 | "dev": true,
804 | "dependencies": {
805 | "spdx-exceptions": "^2.1.0",
806 | "spdx-license-ids": "^3.0.0"
807 | }
808 | },
809 | "node_modules/spdx-expression-validate": {
810 | "version": "2.0.0",
811 | "resolved": "https://registry.npmjs.org/spdx-expression-validate/-/spdx-expression-validate-2.0.0.tgz",
812 | "integrity": "sha512-b3wydZLM+Tc6CFvaRDBOF9d76oGIHNCLYFeHbftFXUWjnfZWganmDmvtM5sm1cRwJc/VDBMLyGGrsLFd1vOxbg==",
813 | "dev": true,
814 | "dependencies": {
815 | "spdx-expression-parse": "^3.0.0"
816 | }
817 | },
818 | "node_modules/spdx-license-ids": {
819 | "version": "3.0.5",
820 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
821 | "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
822 | "dev": true
823 | },
824 | "node_modules/spdx-ranges": {
825 | "version": "2.1.1",
826 | "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz",
827 | "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==",
828 | "dev": true
829 | },
830 | "node_modules/spdx-satisfies": {
831 | "version": "5.0.0",
832 | "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-5.0.0.tgz",
833 | "integrity": "sha512-/hGhwh20BeGmkA+P/lm06RvXD94JduwNxtx/oX3B5ClPt1/u/m5MCaDNo1tV3Y9laLkQr/NRde63b9lLMhlNfw==",
834 | "dev": true,
835 | "dependencies": {
836 | "spdx-compare": "^1.0.0",
837 | "spdx-expression-parse": "^3.0.0",
838 | "spdx-ranges": "^2.0.0"
839 | }
840 | },
841 | "node_modules/supports-color": {
842 | "version": "5.5.0",
843 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
844 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
845 | "dev": true,
846 | "dependencies": {
847 | "has-flag": "^3.0.0"
848 | },
849 | "engines": {
850 | "node": ">=4"
851 | }
852 | },
853 | "node_modules/tslib": {
854 | "version": "2.3.0",
855 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
856 | "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
857 | "dev": true
858 | },
859 | "node_modules/typescript": {
860 | "version": "4.2.4",
861 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz",
862 | "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==",
863 | "dev": true,
864 | "bin": {
865 | "tsc": "bin/tsc",
866 | "tsserver": "bin/tsserver"
867 | },
868 | "engines": {
869 | "node": ">=4.2.0"
870 | }
871 | },
872 | "node_modules/universalify": {
873 | "version": "2.0.0",
874 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
875 | "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
876 | "dev": true,
877 | "engines": {
878 | "node": ">= 10.0.0"
879 | }
880 | },
881 | "node_modules/wrappy": {
882 | "version": "1.0.2",
883 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
884 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
885 | "dev": true
886 | }
887 | },
888 | "dependencies": {
889 | "@babel/code-frame": {
890 | "version": "7.14.5",
891 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz",
892 | "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==",
893 | "dev": true,
894 | "requires": {
895 | "@babel/highlight": "^7.14.5"
896 | }
897 | },
898 | "@babel/helper-validator-identifier": {
899 | "version": "7.14.5",
900 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz",
901 | "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==",
902 | "dev": true
903 | },
904 | "@babel/highlight": {
905 | "version": "7.14.5",
906 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
907 | "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
908 | "dev": true,
909 | "requires": {
910 | "@babel/helper-validator-identifier": "^7.14.5",
911 | "chalk": "^2.0.0",
912 | "js-tokens": "^4.0.0"
913 | }
914 | },
915 | "@rollup/plugin-commonjs": {
916 | "version": "19.0.0",
917 | "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-19.0.0.tgz",
918 | "integrity": "sha512-adTpD6ATGbehdaQoZQ6ipDFhdjqsTgpOAhFiPwl+dzre4pPshsecptDPyEFb61JMJ1+mGljktaC4jI8ARMSNyw==",
919 | "dev": true,
920 | "requires": {
921 | "@rollup/pluginutils": "^3.1.0",
922 | "commondir": "^1.0.1",
923 | "estree-walker": "^2.0.1",
924 | "glob": "^7.1.6",
925 | "is-reference": "^1.2.1",
926 | "magic-string": "^0.25.7",
927 | "resolve": "^1.17.0"
928 | }
929 | },
930 | "@rollup/plugin-node-resolve": {
931 | "version": "13.0.0",
932 | "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.0.0.tgz",
933 | "integrity": "sha512-41X411HJ3oikIDivT5OKe9EZ6ud6DXudtfNrGbC4nniaxx2esiWjkLOzgnZsWq1IM8YIeL2rzRGLZLBjlhnZtQ==",
934 | "dev": true,
935 | "requires": {
936 | "@rollup/pluginutils": "^3.1.0",
937 | "@types/resolve": "1.17.1",
938 | "builtin-modules": "^3.1.0",
939 | "deepmerge": "^4.2.2",
940 | "is-module": "^1.0.0",
941 | "resolve": "^1.19.0"
942 | },
943 | "dependencies": {
944 | "builtin-modules": {
945 | "version": "3.2.0",
946 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz",
947 | "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==",
948 | "dev": true
949 | }
950 | }
951 | },
952 | "@rollup/plugin-typescript": {
953 | "version": "8.2.1",
954 | "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.2.1.tgz",
955 | "integrity": "sha512-Qd2E1pleDR4bwyFxqbjt4eJf+wB0UKVMLc7/BAFDGVdAXQMCsD4DUv5/7/ww47BZCYxWtJqe1Lo0KVNswBJlRw==",
956 | "dev": true,
957 | "requires": {
958 | "@rollup/pluginutils": "^3.1.0",
959 | "resolve": "^1.17.0"
960 | }
961 | },
962 | "@rollup/pluginutils": {
963 | "version": "3.1.0",
964 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
965 | "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==",
966 | "dev": true,
967 | "requires": {
968 | "@types/estree": "0.0.39",
969 | "estree-walker": "^1.0.1",
970 | "picomatch": "^2.2.2"
971 | },
972 | "dependencies": {
973 | "estree-walker": {
974 | "version": "1.0.1",
975 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
976 | "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
977 | "dev": true
978 | }
979 | }
980 | },
981 | "@types/backbone": {
982 | "version": "1.4.1",
983 | "resolved": "https://registry.npmjs.org/@types/backbone/-/backbone-1.4.1.tgz",
984 | "integrity": "sha512-KYfGuQy4d2vvYXbn0uHFZ6brFLndatTMomxBlljpbWf4kFpA3BG/6LA3ec+J9iredrX6eAVI7sm9SVAvwiIM6g==",
985 | "dev": true,
986 | "requires": {
987 | "@types/jquery": "*",
988 | "@types/underscore": "*"
989 | }
990 | },
991 | "@types/estree": {
992 | "version": "0.0.39",
993 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
994 | "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
995 | "dev": true
996 | },
997 | "@types/jquery": {
998 | "version": "3.5.6",
999 | "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.6.tgz",
1000 | "integrity": "sha512-SmgCQRzGPId4MZQKDj9Hqc6kSXFNWZFHpELkyK8AQhf8Zr6HKfCzFv9ZC1Fv3FyQttJZOlap3qYb12h61iZAIg==",
1001 | "dev": true,
1002 | "requires": {
1003 | "@types/sizzle": "*"
1004 | }
1005 | },
1006 | "@types/node": {
1007 | "version": "13.9.1",
1008 | "resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.1.tgz",
1009 | "integrity": "sha512-E6M6N0blf/jiZx8Q3nb0vNaswQeEyn0XlupO+xN6DtJ6r6IT4nXrTry7zhIfYvFCl3/8Cu6WIysmUBKiqV0bqQ==",
1010 | "dev": true
1011 | },
1012 | "@types/resolve": {
1013 | "version": "1.17.1",
1014 | "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
1015 | "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==",
1016 | "dev": true,
1017 | "requires": {
1018 | "@types/node": "*"
1019 | }
1020 | },
1021 | "@types/sizzle": {
1022 | "version": "2.3.3",
1023 | "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz",
1024 | "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==",
1025 | "dev": true
1026 | },
1027 | "@types/underscore": {
1028 | "version": "1.11.3",
1029 | "resolved": "https://registry.npmjs.org/@types/underscore/-/underscore-1.11.3.tgz",
1030 | "integrity": "sha512-Fl1TX1dapfXyDqFg2ic9M+vlXRktcPJrc4PR7sRc7sdVrjavg/JHlbUXBt8qWWqhJrmSqg3RNAkAPRiOYw6Ahw==",
1031 | "dev": true
1032 | },
1033 | "ace-builds": {
1034 | "version": "1.4.12",
1035 | "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.12.tgz",
1036 | "integrity": "sha512-G+chJctFPiiLGvs3+/Mly3apXTcfgE45dT5yp12BcWZ1kUs+gm0qd3/fv4gsz6fVag4mM0moHVpjHDIgph6Psg=="
1037 | },
1038 | "ansi-styles": {
1039 | "version": "3.2.1",
1040 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
1041 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
1042 | "dev": true,
1043 | "requires": {
1044 | "color-convert": "^1.9.0"
1045 | }
1046 | },
1047 | "array-find-index": {
1048 | "version": "1.0.2",
1049 | "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
1050 | "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
1051 | "dev": true
1052 | },
1053 | "balanced-match": {
1054 | "version": "1.0.0",
1055 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
1056 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
1057 | "dev": true
1058 | },
1059 | "brace-expansion": {
1060 | "version": "1.1.11",
1061 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
1062 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
1063 | "dev": true,
1064 | "requires": {
1065 | "balanced-match": "^1.0.0",
1066 | "concat-map": "0.0.1"
1067 | }
1068 | },
1069 | "buffer-from": {
1070 | "version": "1.1.1",
1071 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
1072 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
1073 | "dev": true
1074 | },
1075 | "chalk": {
1076 | "version": "2.4.2",
1077 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
1078 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
1079 | "dev": true,
1080 | "requires": {
1081 | "ansi-styles": "^3.2.1",
1082 | "escape-string-regexp": "^1.0.5",
1083 | "supports-color": "^5.3.0"
1084 | }
1085 | },
1086 | "clean-css": {
1087 | "version": "5.1.3",
1088 | "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.1.3.tgz",
1089 | "integrity": "sha512-qGXzUCDpLwAlPx0kYeU4QXjzQIcIYZbJjD4FNm7NnSjoP0hYMVZhHOpUYJ6AwfkMX2cceLRq54MeCgHy/va1cA==",
1090 | "dev": true,
1091 | "requires": {
1092 | "source-map": "~0.6.0"
1093 | }
1094 | },
1095 | "color-convert": {
1096 | "version": "1.9.3",
1097 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
1098 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
1099 | "dev": true,
1100 | "requires": {
1101 | "color-name": "1.1.3"
1102 | }
1103 | },
1104 | "color-name": {
1105 | "version": "1.1.3",
1106 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
1107 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
1108 | "dev": true
1109 | },
1110 | "commenting": {
1111 | "version": "1.1.0",
1112 | "resolved": "https://registry.npmjs.org/commenting/-/commenting-1.1.0.tgz",
1113 | "integrity": "sha512-YeNK4tavZwtH7jEgK1ZINXzLKm6DZdEMfsaaieOsCAN0S8vsY7UeuO3Q7d/M018EFgE+IeUAuBOKkFccBZsUZA==",
1114 | "dev": true
1115 | },
1116 | "commondir": {
1117 | "version": "1.0.1",
1118 | "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
1119 | "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
1120 | "dev": true
1121 | },
1122 | "concat-map": {
1123 | "version": "0.0.1",
1124 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
1125 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
1126 | "dev": true
1127 | },
1128 | "deepmerge": {
1129 | "version": "4.2.2",
1130 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
1131 | "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
1132 | "dev": true
1133 | },
1134 | "escape-string-regexp": {
1135 | "version": "1.0.5",
1136 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
1137 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
1138 | "dev": true
1139 | },
1140 | "estree-walker": {
1141 | "version": "2.0.2",
1142 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
1143 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
1144 | "dev": true
1145 | },
1146 | "fs-extra": {
1147 | "version": "10.0.0",
1148 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz",
1149 | "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==",
1150 | "dev": true,
1151 | "requires": {
1152 | "graceful-fs": "^4.2.0",
1153 | "jsonfile": "^6.0.1",
1154 | "universalify": "^2.0.0"
1155 | }
1156 | },
1157 | "fs.realpath": {
1158 | "version": "1.0.0",
1159 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
1160 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
1161 | "dev": true
1162 | },
1163 | "function-bind": {
1164 | "version": "1.1.1",
1165 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
1166 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
1167 | "dev": true
1168 | },
1169 | "glob": {
1170 | "version": "7.1.6",
1171 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
1172 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
1173 | "dev": true,
1174 | "requires": {
1175 | "fs.realpath": "^1.0.0",
1176 | "inflight": "^1.0.4",
1177 | "inherits": "2",
1178 | "minimatch": "^3.0.4",
1179 | "once": "^1.3.0",
1180 | "path-is-absolute": "^1.0.0"
1181 | }
1182 | },
1183 | "graceful-fs": {
1184 | "version": "4.2.3",
1185 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
1186 | "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
1187 | "dev": true
1188 | },
1189 | "has": {
1190 | "version": "1.0.3",
1191 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
1192 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
1193 | "dev": true,
1194 | "requires": {
1195 | "function-bind": "^1.1.1"
1196 | }
1197 | },
1198 | "has-flag": {
1199 | "version": "3.0.0",
1200 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
1201 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
1202 | "dev": true
1203 | },
1204 | "inflight": {
1205 | "version": "1.0.6",
1206 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
1207 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
1208 | "dev": true,
1209 | "requires": {
1210 | "once": "^1.3.0",
1211 | "wrappy": "1"
1212 | }
1213 | },
1214 | "inherits": {
1215 | "version": "2.0.3",
1216 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
1217 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
1218 | "dev": true
1219 | },
1220 | "is-core-module": {
1221 | "version": "2.4.0",
1222 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz",
1223 | "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==",
1224 | "dev": true,
1225 | "requires": {
1226 | "has": "^1.0.3"
1227 | }
1228 | },
1229 | "is-module": {
1230 | "version": "1.0.0",
1231 | "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
1232 | "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
1233 | "dev": true
1234 | },
1235 | "is-reference": {
1236 | "version": "1.2.1",
1237 | "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
1238 | "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
1239 | "dev": true,
1240 | "requires": {
1241 | "@types/estree": "*"
1242 | }
1243 | },
1244 | "jest-worker": {
1245 | "version": "26.6.2",
1246 | "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
1247 | "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==",
1248 | "dev": true,
1249 | "requires": {
1250 | "@types/node": "*",
1251 | "merge-stream": "^2.0.0",
1252 | "supports-color": "^7.0.0"
1253 | },
1254 | "dependencies": {
1255 | "has-flag": {
1256 | "version": "4.0.0",
1257 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
1258 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
1259 | "dev": true
1260 | },
1261 | "supports-color": {
1262 | "version": "7.2.0",
1263 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
1264 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
1265 | "dev": true,
1266 | "requires": {
1267 | "has-flag": "^4.0.0"
1268 | }
1269 | }
1270 | }
1271 | },
1272 | "js-tokens": {
1273 | "version": "4.0.0",
1274 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
1275 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
1276 | "dev": true
1277 | },
1278 | "jsonfile": {
1279 | "version": "6.1.0",
1280 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
1281 | "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
1282 | "dev": true,
1283 | "requires": {
1284 | "graceful-fs": "^4.1.6",
1285 | "universalify": "^2.0.0"
1286 | }
1287 | },
1288 | "lodash": {
1289 | "version": "4.17.21",
1290 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
1291 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
1292 | "dev": true
1293 | },
1294 | "magic-string": {
1295 | "version": "0.25.7",
1296 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
1297 | "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
1298 | "dev": true,
1299 | "requires": {
1300 | "sourcemap-codec": "^1.4.4"
1301 | }
1302 | },
1303 | "merge-stream": {
1304 | "version": "2.0.0",
1305 | "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
1306 | "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
1307 | "dev": true
1308 | },
1309 | "minimatch": {
1310 | "version": "3.0.4",
1311 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
1312 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
1313 | "dev": true,
1314 | "requires": {
1315 | "brace-expansion": "^1.1.7"
1316 | }
1317 | },
1318 | "moment": {
1319 | "version": "2.29.1",
1320 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
1321 | "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==",
1322 | "dev": true
1323 | },
1324 | "once": {
1325 | "version": "1.4.0",
1326 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1327 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
1328 | "dev": true,
1329 | "requires": {
1330 | "wrappy": "1"
1331 | }
1332 | },
1333 | "package-name-regex": {
1334 | "version": "1.0.9",
1335 | "resolved": "https://registry.npmjs.org/package-name-regex/-/package-name-regex-1.0.9.tgz",
1336 | "integrity": "sha512-+U2oQCfEz2IlGqws8gmfKzdMDbSd6+RZp6UIFdKo+GAw3+o+kfnsgXkWtJ1JMoKhpP2kEvuYyTy1lXOEQEe0ZA==",
1337 | "dev": true
1338 | },
1339 | "path-is-absolute": {
1340 | "version": "1.0.1",
1341 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
1342 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
1343 | "dev": true
1344 | },
1345 | "path-parse": {
1346 | "version": "1.0.6",
1347 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
1348 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
1349 | "dev": true
1350 | },
1351 | "picomatch": {
1352 | "version": "2.3.0",
1353 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
1354 | "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
1355 | "dev": true
1356 | },
1357 | "randombytes": {
1358 | "version": "2.1.0",
1359 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
1360 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
1361 | "dev": true,
1362 | "requires": {
1363 | "safe-buffer": "^5.1.0"
1364 | }
1365 | },
1366 | "resolve": {
1367 | "version": "1.20.0",
1368 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
1369 | "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
1370 | "dev": true,
1371 | "requires": {
1372 | "is-core-module": "^2.2.0",
1373 | "path-parse": "^1.0.6"
1374 | }
1375 | },
1376 | "rimraf": {
1377 | "version": "3.0.2",
1378 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
1379 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
1380 | "dev": true,
1381 | "requires": {
1382 | "glob": "^7.1.3"
1383 | }
1384 | },
1385 | "rollup": {
1386 | "version": "2.47.0",
1387 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.47.0.tgz",
1388 | "integrity": "sha512-rqBjgq9hQfW0vRmz+0S062ORRNJXvwRpzxhFXORvar/maZqY6za3rgQ/p1Glg+j1hnc1GtYyQCPiAei95uTElg==",
1389 | "dev": true,
1390 | "requires": {
1391 | "fsevents": "~2.3.1"
1392 | },
1393 | "dependencies": {
1394 | "fsevents": {
1395 | "version": "2.3.2",
1396 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
1397 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
1398 | "dev": true,
1399 | "optional": true
1400 | }
1401 | }
1402 | },
1403 | "rollup-plugin-license": {
1404 | "version": "2.3.0",
1405 | "resolved": "https://registry.npmjs.org/rollup-plugin-license/-/rollup-plugin-license-2.3.0.tgz",
1406 | "integrity": "sha512-oi8pL59fVTwXCkLUsZ8dVGVJjO7Hcc5UT0chJvKd0MktPgeYHSadkaicAYUemdYHHpjb0D3DyvedZAEPt+2r8w==",
1407 | "dev": true,
1408 | "requires": {
1409 | "commenting": "1.1.0",
1410 | "glob": "7.1.6",
1411 | "lodash": "4.17.21",
1412 | "magic-string": "0.25.7",
1413 | "mkdirp": "1.0.4",
1414 | "moment": "2.29.1",
1415 | "package-name-regex": "1.0.9",
1416 | "spdx-expression-validate": "2.0.0",
1417 | "spdx-satisfies": "5.0.0"
1418 | },
1419 | "dependencies": {
1420 | "mkdirp": {
1421 | "version": "1.0.4",
1422 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
1423 | "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
1424 | "dev": true
1425 | }
1426 | }
1427 | },
1428 | "rollup-plugin-terser": {
1429 | "version": "7.0.2",
1430 | "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz",
1431 | "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==",
1432 | "dev": true,
1433 | "requires": {
1434 | "@babel/code-frame": "^7.10.4",
1435 | "jest-worker": "^26.2.1",
1436 | "serialize-javascript": "^4.0.0",
1437 | "terser": "^5.0.0"
1438 | },
1439 | "dependencies": {
1440 | "commander": {
1441 | "version": "2.20.3",
1442 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
1443 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
1444 | "dev": true
1445 | },
1446 | "serialize-javascript": {
1447 | "version": "4.0.0",
1448 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
1449 | "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
1450 | "dev": true,
1451 | "requires": {
1452 | "randombytes": "^2.1.0"
1453 | }
1454 | },
1455 | "source-map": {
1456 | "version": "0.7.3",
1457 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
1458 | "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
1459 | "dev": true
1460 | },
1461 | "terser": {
1462 | "version": "5.7.1",
1463 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.1.tgz",
1464 | "integrity": "sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg==",
1465 | "dev": true,
1466 | "requires": {
1467 | "commander": "^2.20.0",
1468 | "source-map": "~0.7.2",
1469 | "source-map-support": "~0.5.19"
1470 | }
1471 | }
1472 | }
1473 | },
1474 | "safe-buffer": {
1475 | "version": "5.1.2",
1476 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
1477 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
1478 | "dev": true
1479 | },
1480 | "source-map": {
1481 | "version": "0.6.1",
1482 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
1483 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
1484 | "dev": true
1485 | },
1486 | "source-map-support": {
1487 | "version": "0.5.19",
1488 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
1489 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
1490 | "dev": true,
1491 | "requires": {
1492 | "buffer-from": "^1.0.0",
1493 | "source-map": "^0.6.0"
1494 | }
1495 | },
1496 | "sourcemap-codec": {
1497 | "version": "1.4.8",
1498 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
1499 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
1500 | "dev": true
1501 | },
1502 | "spdx-compare": {
1503 | "version": "1.0.0",
1504 | "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz",
1505 | "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==",
1506 | "dev": true,
1507 | "requires": {
1508 | "array-find-index": "^1.0.2",
1509 | "spdx-expression-parse": "^3.0.0",
1510 | "spdx-ranges": "^2.0.0"
1511 | }
1512 | },
1513 | "spdx-exceptions": {
1514 | "version": "2.2.0",
1515 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
1516 | "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
1517 | "dev": true
1518 | },
1519 | "spdx-expression-parse": {
1520 | "version": "3.0.0",
1521 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
1522 | "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
1523 | "dev": true,
1524 | "requires": {
1525 | "spdx-exceptions": "^2.1.0",
1526 | "spdx-license-ids": "^3.0.0"
1527 | }
1528 | },
1529 | "spdx-expression-validate": {
1530 | "version": "2.0.0",
1531 | "resolved": "https://registry.npmjs.org/spdx-expression-validate/-/spdx-expression-validate-2.0.0.tgz",
1532 | "integrity": "sha512-b3wydZLM+Tc6CFvaRDBOF9d76oGIHNCLYFeHbftFXUWjnfZWganmDmvtM5sm1cRwJc/VDBMLyGGrsLFd1vOxbg==",
1533 | "dev": true,
1534 | "requires": {
1535 | "spdx-expression-parse": "^3.0.0"
1536 | }
1537 | },
1538 | "spdx-license-ids": {
1539 | "version": "3.0.5",
1540 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
1541 | "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
1542 | "dev": true
1543 | },
1544 | "spdx-ranges": {
1545 | "version": "2.1.1",
1546 | "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz",
1547 | "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==",
1548 | "dev": true
1549 | },
1550 | "spdx-satisfies": {
1551 | "version": "5.0.0",
1552 | "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-5.0.0.tgz",
1553 | "integrity": "sha512-/hGhwh20BeGmkA+P/lm06RvXD94JduwNxtx/oX3B5ClPt1/u/m5MCaDNo1tV3Y9laLkQr/NRde63b9lLMhlNfw==",
1554 | "dev": true,
1555 | "requires": {
1556 | "spdx-compare": "^1.0.0",
1557 | "spdx-expression-parse": "^3.0.0",
1558 | "spdx-ranges": "^2.0.0"
1559 | }
1560 | },
1561 | "supports-color": {
1562 | "version": "5.5.0",
1563 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
1564 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
1565 | "dev": true,
1566 | "requires": {
1567 | "has-flag": "^3.0.0"
1568 | }
1569 | },
1570 | "tslib": {
1571 | "version": "2.3.0",
1572 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
1573 | "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
1574 | "dev": true
1575 | },
1576 | "typescript": {
1577 | "version": "4.2.4",
1578 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz",
1579 | "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==",
1580 | "dev": true
1581 | },
1582 | "universalify": {
1583 | "version": "2.0.0",
1584 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
1585 | "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
1586 | "dev": true
1587 | },
1588 | "wrappy": {
1589 | "version": "1.0.2",
1590 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1591 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
1592 | "dev": true
1593 | }
1594 | }
1595 | }
1596 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@convergencelabs/ace-collab-ext",
3 | "version": "0.6.0",
4 | "title": "Ace Editor Collaborative Extensions",
5 | "description": "Collaborative Extensions for the Ace Editor",
6 | "keywords": [
7 | "collaboration",
8 | "ace",
9 | "editor"
10 | ],
11 | "homepage": "http://convergencelabs.com",
12 | "author": {
13 | "name": "Convergence Labs",
14 | "email": "info@convergencelabs.com",
15 | "url": "http://convergencelabs.com"
16 | },
17 | "contributors": [],
18 | "repository": {
19 | "type": "git",
20 | "url": "https://github.com/convergencelabs/ace-collab-ext.git"
21 | },
22 | "bugs": {
23 | "url": "https://github.com/convergencelabs/ace-collab-ext/issues"
24 | },
25 | "license": "MIT",
26 | "scripts": {
27 | "build:esm": "tsc --module ES2020 --target ES2020 --outDir dist/module",
28 | "build:commonjs": "tsc --module commonjs --target es5 --outDir dist/lib",
29 | "build:types": "tsc --declaration true --emitDeclarationOnly true --outDir dist/types && node ./scripts/enhance-types.js",
30 | "build:umd": "rollup -c rollup.config.js",
31 | "build:css": "node scripts/build-css.js",
32 | "dist": "npm run build:esm && npm run build:commonjs && npm run build:umd && npm run build:types && npm run build:css",
33 | "clean": "rimraf dist",
34 | "prepack": "npm run dist"
35 | },
36 | "publishConfig": {
37 | "registry": "https://registry.npmjs.org/",
38 | "access": "public"
39 | },
40 | "main": "dist/lib/index.js",
41 | "module": "dist/module/index.js",
42 | "types": "dist/types/index.d.ts",
43 | "browser": "dist/umd/ace-collab-ext.js",
44 | "files": [
45 | "dist",
46 | "example"
47 | ],
48 | "dependencies": {
49 | "ace-builds": "^1.4.12"
50 | },
51 | "devDependencies": {
52 | "@rollup/plugin-commonjs": "19.0.0",
53 | "@rollup/plugin-node-resolve": "13.0.0",
54 | "@rollup/plugin-typescript": "8.2.1",
55 | "@types/backbone": "1.4.1",
56 | "clean-css": "^5.1.3",
57 | "fs-extra": "^10.0.0",
58 | "rimraf": "^3.0.2",
59 | "rollup": "2.47.0",
60 | "rollup-plugin-license": "2.3.0",
61 | "rollup-plugin-terser": "7.0.2",
62 | "tslib": "^2.3.0",
63 | "typescript": "4.2.4"
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | // rollup.config.js
2 | import typescript from '@rollup/plugin-typescript';
3 | import resolve from '@rollup/plugin-node-resolve';
4 | import commonjs from '@rollup/plugin-commonjs';
5 | import license from "rollup-plugin-license";
6 | import {terser} from "rollup-plugin-terser";
7 | import path from "path";
8 |
9 | import pkg from './package.json';
10 |
11 | //
12 | // Commons Settings
13 | //
14 | const input = 'src/ts/index.ts';
15 |
16 | const plugins = [
17 | resolve(),
18 | commonjs(),
19 | typescript(),
20 | license({
21 | banner: {
22 | commentStyle: 'ignored', // The default
23 | content: {
24 | file: path.join(__dirname, 'copyright-header.txt'),
25 | },
26 | }
27 | })
28 | ];
29 |
30 | const moduleName = "AceCollabExt";
31 | const format = "umd";
32 |
33 | const external = [
34 | "ace-builds"
35 | ]
36 |
37 | const globals = {
38 | "ace-builds": "ace"
39 | }
40 |
41 | export default [{
42 | input,
43 | plugins,
44 | external,
45 | output: [
46 | {
47 | name: moduleName,
48 | file: pkg.browser,
49 | format,
50 | sourcemap: true,
51 | globals
52 | }
53 | ]
54 | }, {
55 | input,
56 | plugins: [...plugins, terser()],
57 | external,
58 | output: [
59 | {
60 | name: moduleName,
61 | file: `${path.dirname(pkg.browser)}/${path.basename(pkg.browser, ".js")}.min.js`,
62 | format,
63 | sourcemap: true,
64 | globals
65 | }
66 | ]
67 | }];
--------------------------------------------------------------------------------
/scripts/build-css.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs-extra');
2 | const CleanCSS = require('clean-css');
3 |
4 | fs.copySync('src/css', 'dist/css');
5 |
6 | const css = fs.readFileSync('dist/css/ace-collab-ext.css');
7 | const options = {
8 | sourceMap: true,
9 | sourceMapInlineSources: true
10 | }
11 | const minified = new CleanCSS(options).minify(css);
12 | fs.writeFileSync( 'dist/css/ace-collab-ext.min.css', minified.styles );
13 | fs.writeFileSync( 'dist/css/ace-collab-ext.css.map', minified.sourceMap.toString() );
14 |
--------------------------------------------------------------------------------
/scripts/enhance-types.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 |
3 | fs.appendFileSync('dist/types/index.d.ts', '\nexport as namespace AceCollabExt;\n');
4 |
5 |
--------------------------------------------------------------------------------
/src/css/ace-collab-ext.css:
--------------------------------------------------------------------------------
1 | .ace-multi-cursor {
2 | position: absolute;
3 | pointer-events: auto;
4 | z-index: 10;
5 | }
6 |
7 | .ace-multi-cursor:before {
8 | content: "";
9 | width: 6px;
10 | height: 5px;
11 | display: block;
12 | background: inherit;
13 | margin-left: -2px;
14 | margin-top: -5px;
15 | }
16 |
17 | .ace-multi-cursor-tooltip {
18 | position: absolute;
19 | white-space: nowrap;
20 | color: #FFFFFF;
21 | text-shadow: 0 0 1px #000000;
22 | opacity: 1.0;
23 | font-size: 12px;
24 | padding: 2px;
25 | font-family: sans-serif;
26 |
27 | transition: opacity 0.5s ease-out;
28 | -webkit-transition: opacity 0.5s ease-out;
29 | -moz-transition: opacity 0.5s ease-out;
30 | -ms-transition: opacity 0.5s ease-out;
31 | -o-transition: opacity 0.5s ease-out;
32 | }
33 |
34 | .ace-multi-selection {
35 | position: absolute;
36 | pointer-events: auto;
37 | z-index: 10;
38 | opacity: 0.3;
39 | }
40 |
41 | .ace-radar-view {
42 | position: relative;
43 | min-width: 6px;
44 | }
45 |
46 | .ace-radar-view-scroll-indicator {
47 | position: absolute;
48 | left: 0;
49 | right: 0;
50 | border-radius: 4px;
51 | cursor: pointer;
52 | border-style: double;
53 | border-width: 3px;
54 | }
55 |
56 | .ace-radar-view-cursor-indicator {
57 | position: absolute;
58 | left: 0;
59 | right: 0;
60 | height: 4px;
61 | border-radius: 3px;
62 | cursor: pointer;
63 | border: 1px solid black;
64 | }
65 |
66 | .ace-radar-view-wrapper {
67 | position: relative;
68 | float: left;
69 |
70 | height: 100%;
71 | width: 6px;
72 |
73 | margin-right: 4px;
74 | }
75 |
--------------------------------------------------------------------------------
/src/ts/AceCursorMarker.ts:
--------------------------------------------------------------------------------
1 | import {Ace} from "ace-builds";
2 |
3 | /**
4 | * Represents a marker of a remote users cursor.
5 | */
6 | export class AceCursorMarker implements Ace.MarkerLike {
7 |
8 | public range: Ace.Range;
9 | public type: string;
10 | public renderer?: Ace.MarkerRenderer;
11 | public clazz: string;
12 | public inFront: boolean;
13 | public id: number;
14 |
15 | private readonly _session: Ace.EditSession;
16 | private readonly _label: string;
17 | private readonly _color: string;
18 | private readonly _cursorId: string;
19 | private readonly _id: string;
20 | private readonly _markerElement: HTMLDivElement;
21 | private readonly _cursorElement: HTMLDivElement;
22 | private readonly _tooltipElement: HTMLDivElement;
23 | private _visible: boolean;
24 | private _position: Ace.Point;
25 | private _tooltipTimeout: any;
26 |
27 | /**
28 | * Constructs a new AceCursorMarker
29 | * @param session The Ace Editor Session to bind to.
30 | * @param cursorId the unique id of this cursor.
31 | * @param label The label to display over the cursor.
32 | * @param color The css color of the cursor
33 | * @param position The row / column coordinate of the cursor marker.
34 | */
35 | constructor(session: Ace.EditSession,
36 | cursorId: string,
37 | label: string,
38 | color: string,
39 | position: number | Ace.Point) {
40 | this._session = session;
41 | this._label = label;
42 | this._color = color;
43 | this._position = position ? this._convertPosition(position) : null;
44 | this._cursorId = cursorId;
45 | this._id = null;
46 | this._visible = false;
47 | this._tooltipTimeout = null;
48 |
49 | // Create the HTML elements
50 | this._markerElement = document.createElement("div");
51 | this._cursorElement = document.createElement("div");
52 | this._cursorElement.className = "ace-multi-cursor";
53 | this._cursorElement.style.background = this._color;
54 | this._markerElement.append(this._cursorElement);
55 |
56 | this._tooltipElement = document.createElement("div");
57 | this._tooltipElement.className = "ace-multi-cursor-tooltip";
58 | this._tooltipElement.style.background = this._color;
59 | this._tooltipElement.style.opacity = "0";
60 | this._tooltipElement.innerHTML = label;
61 | this._markerElement.append(this._tooltipElement);
62 | }
63 |
64 | /**
65 | * Called by Ace to update the rendering of the marker.
66 | *
67 | * @param _ The html to render, represented by an array of strings.
68 | * @param markerLayer The marker layer containing the cursor marker.
69 | * @param __ The ace edit session.
70 | * @param layerConfig
71 | */
72 | public update(_: string[], markerLayer: any, __: Ace.EditSession, layerConfig: any): void {
73 | if (this._position === null) {
74 | return;
75 | }
76 |
77 | const screenPosition = this._session.documentToScreenPosition(
78 | this._position.row, this._position.column);
79 |
80 | const top: number = markerLayer.$getTop(screenPosition.row, layerConfig);
81 | const left: number = markerLayer.$padding + screenPosition.column * layerConfig.characterWidth;
82 | const height: number = layerConfig.lineHeight;
83 |
84 | const cursorTop = top + 2;
85 | const cursorHeight = height - 3;
86 | const cursorLeft = left;
87 | const cursorWidth = 2;
88 |
89 | this._cursorElement.style.height = `${cursorHeight}px`;
90 | this._cursorElement.style.width = `${cursorWidth}px`;
91 | this._cursorElement.style.top = `${cursorTop}px`;
92 | this._cursorElement.style.left = `${cursorLeft}px`;
93 |
94 | let toolTipTop = cursorTop - height;
95 | if (toolTipTop < 5) {
96 | toolTipTop = cursorTop + height - 1;
97 | }
98 |
99 | const toolTipLeft = cursorLeft;
100 | this._tooltipElement.style.top = `${toolTipTop - 2}px`;
101 | this._tooltipElement.style.left = `${toolTipLeft - 2}px`;
102 |
103 | // Remove the content node from whatever parent it might have now
104 | // and add it to the new parent node.
105 | this._markerElement.remove();
106 | markerLayer.elt("remote-cursor", "");
107 | const parentNode = markerLayer.element.childNodes[markerLayer.i - 1] || markerLayer.element.lastChild;
108 | parentNode.appendChild(this._markerElement);
109 | }
110 |
111 | /**
112 | * Sets the location of the cursor marker.
113 | * @param position The position of cursor marker.
114 | */
115 | public setPosition(position: number | Ace.Point): void {
116 | this._position = this._convertPosition(position);
117 | this._forceSessionUpdate();
118 | this._tooltipElement.style.opacity = "1";
119 | this._scheduleTooltipHide();
120 | }
121 |
122 | /**
123 | * Sets the marker to visible / invisible.
124 | *
125 | * @param visible true if the marker should be displayed, false otherwise.
126 | */
127 | public setVisible(visible: boolean): void {
128 | const old = this._visible;
129 |
130 | this._visible = visible;
131 | if (old !== this._visible) {
132 | this._markerElement.style.visibility = visible ? "visible" : "hidden";
133 | this._forceSessionUpdate();
134 | }
135 | }
136 |
137 | /**
138 | * Determines if the marker should be visible.
139 | *
140 | * @returns true if the cursor should be visible, false otherwise.
141 | */
142 | public isVisible(): boolean {
143 | return this._visible;
144 | }
145 |
146 | /**
147 | * Gets the unique id of this cursor.
148 | * @returns the unique id of this cursor.
149 | */
150 | public cursorId(): string {
151 | return this._cursorId;
152 | }
153 |
154 | /**
155 | * Gets the id of the marker.
156 | * @returns The marker id.
157 | */
158 | public markerId(): string {
159 | return this._id;
160 | }
161 |
162 | /**
163 | * Gets the label of the marker.
164 | * @returns The marker"s label.
165 | */
166 | public getLabel(): string {
167 | return this._label;
168 | }
169 |
170 | private _forceSessionUpdate(): void {
171 | (this._session as any)._signal("changeFrontMarker");
172 | }
173 |
174 | private _convertPosition(position: number | Ace.Point): Ace.Point {
175 | if (position === null) {
176 | return null;
177 | } else if (typeof position === "number") {
178 | return this._session.getDocument().indexToPosition(position, 0);
179 | } else if (typeof position.row === "number" && typeof position.column === "number") {
180 | return position;
181 | }
182 |
183 | throw new Error(`Invalid position: ${position}`);
184 | }
185 |
186 | private _scheduleTooltipHide(): void {
187 | if (this._tooltipTimeout !== null) {
188 | clearTimeout(this._tooltipTimeout);
189 | }
190 |
191 | this._tooltipTimeout = setTimeout(() => {
192 | this._tooltipElement.style.opacity = "0";
193 | this._tooltipTimeout = null;
194 | }, 2000);
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/src/ts/AceMultiCursorManager.ts:
--------------------------------------------------------------------------------
1 | import {Ace} from "ace-builds";
2 | import {AceCursorMarker} from "./AceCursorMarker";
3 |
4 | /**
5 | * Implements multiple colored cursors in the ace editor. Each cursor is
6 | * associated with a particular user. Each user is identified by a unique id
7 | * and has a color associated with them. Each cursor has a position in the
8 | * editor which is specified by a 2-d row and column ({row: 0, column: 10}).
9 | */
10 | export class AceMultiCursorManager {
11 |
12 | private readonly _cursors: { [key: string]: AceCursorMarker };
13 | private readonly _session: Ace.EditSession;
14 |
15 | /**
16 | * Constructs a new AceMultiCursorManager that is bound to a particular
17 | * Ace EditSession instance.
18 | *
19 | * @param session
20 | * The Ace EditSession to bind to.
21 | */
22 | constructor(session: Ace.EditSession) {
23 | this._cursors = {};
24 | this._session = session;
25 | }
26 |
27 | /**
28 | * Adds a new collaborative selection.
29 | *
30 | * @param id
31 | * The unique system identifier for the user associated with this selection.
32 | * @param label
33 | * A human readable / meaningful label / title that identifies the user.
34 | * @param color
35 | * A valid css color string.
36 | * @param position
37 | * A 2-d position or linear index indicating the location of the cursor.
38 | */
39 | public addCursor(id: string, label: string, color: string, position: number | Ace.Point): void {
40 | if (this._cursors[id] !== undefined) {
41 | throw new Error(`Cursor with id already defined: ${id}`);
42 | }
43 |
44 | const marker: AceCursorMarker = new AceCursorMarker(this._session, id, label, color, position);
45 |
46 | this._cursors[id] = marker;
47 | this._session.addDynamicMarker(marker, true);
48 | }
49 |
50 | /**
51 | * Updates the selection for a particular user.
52 | *
53 | * @param id
54 | * The unique identifier for the user.
55 | * @param position
56 | * A 2-d position or linear index indicating the location of the cursor.
57 | */
58 | public setCursor(id: string, position: number | Ace.Point): void {
59 | const cursor: AceCursorMarker = this._getCursor(id);
60 |
61 | cursor.setPosition(position);
62 | }
63 |
64 | /**
65 | * Clears the cursor (but does not remove it) for the specified user.
66 | *
67 | * @param id
68 | * The unique identifier for the user.
69 | */
70 | public clearCursor(id: string): void {
71 | const cursor = this._getCursor(id);
72 |
73 | cursor.setPosition(null);
74 | }
75 |
76 | /**
77 | * Removes the cursor for the specified user.
78 | *
79 | * @param id
80 | * The unique identifier for the user.
81 | */
82 | public removeCursor(id: string): void {
83 | const cursor = this._cursors[id];
84 |
85 | if (cursor === undefined) {
86 | throw new Error(`Cursor not found: ${id}`);
87 | }
88 | // Note: ace adds an id field to all added markers.
89 | this._session.removeMarker((cursor as any).id);
90 | delete this._cursors[id];
91 | }
92 |
93 | /**
94 | * Removes all cursors.
95 | */
96 | public removeAll(): void {
97 | Object.getOwnPropertyNames(this._cursors).forEach((key) => {
98 | this.removeCursor(this._cursors[key].cursorId());
99 | });
100 | }
101 |
102 | private _getCursor(id: string): AceCursorMarker {
103 | const cursor: AceCursorMarker = this._cursors[id];
104 |
105 | if (cursor === undefined) {
106 | throw new Error(`Cursor not found: ${id}`);
107 | }
108 | return cursor;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/ts/AceMultiSelectionManager.ts:
--------------------------------------------------------------------------------
1 | import {Ace} from "ace-builds";
2 | import {AceSelectionMarker} from "./AceSelectionMarker";
3 |
4 | /**
5 | * Implements multiple colored selections in the ace editor. Each selection is
6 | * associated with a particular user. Each user is identified by a unique id
7 | * and has a color associated with them. The selection manager supports block
8 | * selection through multiple AceRanges.
9 | */
10 | export class AceMultiSelectionManager {
11 |
12 | private readonly _selections: { [key: string]: AceSelectionMarker };
13 | private readonly _session: Ace.EditSession;
14 |
15 | /**
16 | * Constructs a new AceMultiSelectionManager that is bound to a particular
17 | * Ace EditSession instance.
18 | *
19 | * @param session
20 | * The Ace EditSession to bind to.
21 | */
22 | constructor(session: Ace.EditSession) {
23 | this._selections = {};
24 | this._session = session;
25 | }
26 |
27 | /**
28 | * Adds a new collaborative selection.
29 | *
30 | * @param id
31 | * The unique system identifier for the user associated with this selection.
32 | * @param label
33 | * A human readable / meaningful label / title that identifies the user.
34 | * @param color
35 | * A valid css color string.
36 | * @param ranges
37 | * An array of ace ranges that specify the initial selection.
38 | */
39 | public addSelection(id: string, label: string, color: string, ranges: Ace.Range[]): void {
40 | if (this._selections[id] !== undefined) {
41 | throw new Error("Selection with id already defined: " + id);
42 | }
43 |
44 | const marker = new AceSelectionMarker(this._session, id, label, color, ranges);
45 |
46 | this._selections[id] = marker;
47 | this._session.addDynamicMarker(marker, false);
48 | }
49 |
50 | /**
51 | * Updates the selection for a particular user.
52 | *
53 | * @param id
54 | * The unique identifier for the user.
55 | * @param ranges
56 | * The array of ranges that specify the selection.
57 | */
58 | public setSelection(id: string, ranges: Ace.Range[]) {
59 | const selection = this._getSelection(id);
60 |
61 | selection.setSelection(ranges);
62 | }
63 |
64 | /**
65 | * Clears the selection (but does not remove it) for the specified user.
66 | * @param id
67 | * The unique identifier for the user.
68 | */
69 | public clearSelection(id: string): void {
70 | const selection = this._getSelection(id);
71 |
72 | selection.setSelection(null);
73 | }
74 |
75 | /**
76 | * Removes the selection for the specified user.
77 | * @param id
78 | * The unique identifier for the user.
79 | */
80 | public removeSelection(id: string) {
81 | const selection = this._selections[id];
82 |
83 | if (selection === undefined) {
84 | throw new Error("Selection not found: " + id);
85 | }
86 |
87 | // note: ace adds the id property to whatever marker you pass in.
88 | this._session.removeMarker((selection as any).id);
89 | delete this._selections[id];
90 | }
91 |
92 | /**
93 | * Removes all selections.
94 | */
95 | public removeAll(): void {
96 | Object.getOwnPropertyNames(this._selections).forEach((key) => {
97 | this.removeSelection(this._selections[key].selectionId());
98 | });
99 | }
100 |
101 | private _getSelection(id: string): AceSelectionMarker {
102 | const selection: AceSelectionMarker = this._selections[id];
103 |
104 | if (selection === undefined) {
105 | throw new Error("Selection not found: " + id);
106 | }
107 | return selection;
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/ts/AceRadarView.ts:
--------------------------------------------------------------------------------
1 | import {Ace} from "ace-builds";
2 | import {AceRadarViewIndicator} from "./AceRadarViewIndicator";
3 | import {IRowRange} from "./RowRange";
4 |
5 | /**
6 | * Implements viewport awareness in the Ace Editor by showing where remote
7 | * users are scrolled too and where there cursor is in the document, even
8 | * if the cursor is not in view.
9 | */
10 | export class AceRadarView {
11 | private readonly _views: { [key: string]: AceRadarViewIndicator };
12 | private readonly _editor: Ace.Editor;
13 | private _container: HTMLElement;
14 |
15 | /**
16 | * Constructs a new AceRadarView bound to the supplied element and editor.
17 | *
18 | * @param element
19 | * The HTML Element that the AceRadarView should render to.
20 | * @param editor
21 | * The Ace Editor to listen to events from.
22 | */
23 | constructor(element: HTMLElement | string, editor: Ace.Editor) {
24 | this._container = null;
25 | if (typeof element === "string") {
26 | this._container = document.getElementById(element);
27 | } else {
28 | this._container = element;
29 | }
30 |
31 | this._container.style.position = "relative";
32 | this._views = {};
33 | this._editor = editor;
34 | }
35 |
36 | /**
37 | * Add a view indicator for a new remote user.
38 | *
39 | * @param id
40 | * The unique id of the user.
41 | * @param label
42 | * A text label to displAce for the user.
43 | * @param color
44 | * The color to render the indicator with.
45 | * @param viewRows
46 | * The rows the user's viewport spans.
47 | * @param cursorRow
48 | * The row that the user's cursor is on.
49 | */
50 | public addView(id: string, label: string, color: string, viewRows: IRowRange, cursorRow: number) {
51 | const indicator = new AceRadarViewIndicator(
52 | label,
53 | color,
54 | viewRows,
55 | cursorRow,
56 | this._editor
57 | );
58 |
59 | this._container.appendChild(indicator.element());
60 | indicator.update();
61 |
62 | this._views[id] = indicator;
63 | }
64 |
65 | /**
66 | * Determines if the AceRadarView has an indicator for this specified user.
67 | *
68 | * @param id
69 | * The id of the user to check for.
70 | * @returns
71 | * True if the AceRadarView has an indicator for this user, false otherwise.
72 | */
73 | public hasView(id: string): boolean {
74 | return this._views[id] !== undefined;
75 | }
76 |
77 | /**
78 | * Sets the view row span for a particular user.
79 | *
80 | * @param id
81 | * The id of the user to set the rows for.
82 | * @param rows
83 | * The row range to set.
84 | */
85 | public setViewRows(id: string, rows: IRowRange) {
86 | const indicator = this._views[id];
87 | indicator.setViewRows(rows);
88 | }
89 |
90 | /**
91 | * Sets the cursor row for a particular user.
92 | *
93 | * @param id
94 | * The id of the user to set the cursor row for.
95 | * @param row
96 | * The row to set.
97 | */
98 | public setCursorRow(id: string, row: number) {
99 | const indicator = this._views[id];
100 | indicator.setCursorRow(row);
101 | }
102 |
103 | /**
104 | * Clears the view for a particular user, causing their indicator to disapear.
105 | * @param id
106 | * The id of the user to clear.
107 | */
108 | public clearView(id: string): void {
109 | const indicator = this._views[id];
110 | indicator.setCursorRow(null);
111 | indicator.setViewRows(null);
112 | }
113 |
114 | /**
115 | * Removes the view indicator for the specified user.
116 | * @param id
117 | * The id of the user to remove the view indicator for.
118 | */
119 | public removeView(id: string): void {
120 | const indicator = this._views[id];
121 | indicator.dispose();
122 | delete this._views[id];
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/src/ts/AceRadarViewIndicator.ts:
--------------------------------------------------------------------------------
1 | import {Ace} from "ace-builds";
2 | import {IRowRange} from "./RowRange";
3 |
4 | export class AceRadarViewIndicator {
5 |
6 | private readonly _label: string;
7 | private readonly _color: string;
8 | private readonly _editorListener: () => void;
9 | private readonly _scrollElement: HTMLDivElement;
10 | private readonly _cursorElement: HTMLDivElement;
11 | private readonly _wrapper: HTMLDivElement;
12 | private _viewRows: IRowRange;
13 | private _cursorRow: number;
14 | private _editor: Ace.Editor;
15 | private _docLineCount: number;
16 |
17 | constructor(label: string, color: string, viewRows: IRowRange, cursorRow: number, editor: Ace.Editor) {
18 | this._label = label;
19 | this._color = color;
20 | this._viewRows = viewRows;
21 | this._cursorRow = cursorRow;
22 | this._editor = editor;
23 | this._docLineCount = editor.getSession().getLength();
24 |
25 | this._editorListener = () => {
26 | const newLineCount = this._editor.getSession().getLength();
27 |
28 | if (newLineCount !== this._docLineCount) {
29 | this._docLineCount = newLineCount;
30 | this.update();
31 | }
32 | };
33 | this._editor.on("change", this._editorListener);
34 |
35 | this._scrollElement = document.createElement("div");
36 | this._scrollElement.className = "ace-radar-view-scroll-indicator";
37 |
38 | this._scrollElement.style.borderColor = this._color;
39 | this._scrollElement.style.background = this._color;
40 |
41 | // todo implement a custom tooltip for consistent presentation.
42 | this._scrollElement.title = this._label;
43 |
44 | this._scrollElement.addEventListener("click", () => {
45 | const middle = ((this._viewRows.end - this._viewRows.start) / 2) + this._viewRows.start;
46 |
47 | this._editor.scrollToLine(middle, true, false, () => { /* no-op */
48 | });
49 | }, false);
50 |
51 | this._cursorElement = document.createElement("div");
52 | this._cursorElement.className = "ace-radar-view-cursor-indicator";
53 | this._cursorElement.style.background = this._color;
54 | this._cursorElement.title = this._label;
55 |
56 | this._cursorElement.addEventListener("click", () => {
57 | this._editor.scrollToLine(this._cursorRow, true, false, () => { /* no-op */
58 | });
59 | }, false);
60 |
61 | this._wrapper = document.createElement("div");
62 | this._wrapper.className = "ace-radar-view-wrapper";
63 | this._wrapper.style.display = "none";
64 |
65 | this._wrapper.appendChild(this._scrollElement);
66 | this._wrapper.appendChild(this._cursorElement);
67 | }
68 |
69 | public element(): HTMLDivElement {
70 | return this._wrapper;
71 | }
72 |
73 | public setCursorRow(cursorRow: number): void {
74 | this._cursorRow = cursorRow;
75 | this.update();
76 | }
77 |
78 | public setViewRows(viewRows: IRowRange): void {
79 | this._viewRows = viewRows;
80 | this.update();
81 | }
82 |
83 | public update(): void {
84 | if (!_isSet(this._viewRows) && !_isSet(this._cursorRow)) {
85 | this._wrapper.style.display = "none";
86 | } else {
87 | this._wrapper.style.display = null;
88 | const maxLine = this._docLineCount - 1;
89 |
90 | if (!_isSet(this._viewRows)) {
91 | this._scrollElement.style.display = "none";
92 | } else {
93 | const topPercent = Math.min(maxLine, this._viewRows.start) / maxLine * 100;
94 | const bottomPercent = 100 - (Math.min(maxLine, this._viewRows.end) / maxLine * 100);
95 |
96 | this._scrollElement.style.top = topPercent + "%";
97 | this._scrollElement.style.bottom = bottomPercent + "%";
98 | this._scrollElement.style.display = null;
99 | }
100 |
101 | if (!_isSet(this._cursorRow)) {
102 | this._cursorElement.style.display = "none";
103 | } else {
104 | const cursorPercent = Math.min(this._cursorRow, maxLine) / maxLine;
105 | const ratio = (this._wrapper.offsetHeight - this._cursorElement.offsetHeight) / this._wrapper.offsetHeight;
106 | const cursorTop = cursorPercent * ratio * 100;
107 |
108 | this._cursorElement.style.top = cursorTop + "%";
109 | this._cursorElement.style.display = null;
110 | }
111 | }
112 | }
113 |
114 | public dispose(): void {
115 | this._wrapper.parentNode.removeChild(this._wrapper);
116 | this._editor.off("change", this._editorListener);
117 | }
118 | }
119 |
120 | function _isSet(value: any): boolean {
121 | return value !== undefined && value !== null;
122 | }
123 |
--------------------------------------------------------------------------------
/src/ts/AceRangeUtil.ts:
--------------------------------------------------------------------------------
1 | import {Ace, Range} from "ace-builds";
2 |
3 | export interface IRangeData {
4 | start: {row: number, column: number};
5 | end: {row: number, column: number};
6 | }
7 |
8 | /**
9 | * A helper class for working with Ace Ranges.
10 | */
11 | export class AceRangeUtil {
12 |
13 | public static rangeToJson(range: Ace.Range): IRangeData {
14 | return {
15 | start: {
16 | row: range.start.row,
17 | column: range.start.column
18 | },
19 | end: {
20 | row: range.end.row,
21 | column: range.end.column
22 | }
23 | };
24 | }
25 |
26 | public static jsonToRange(range: IRangeData): Ace.Range {
27 | return new Range(
28 | range.start.row,
29 | range.start.column,
30 | range.end.row,
31 | range.end.column);
32 | }
33 |
34 | public static rangesToJson(ranges: Ace.Range[]): IRangeData[] {
35 | return ranges.map((range) => {
36 | return AceRangeUtil.rangeToJson(range);
37 | });
38 | }
39 |
40 | public static jsonToRanges(ranges: IRangeData[]): Ace.Range[] {
41 | return ranges.map((range) => {
42 | return AceRangeUtil.jsonToRange(range);
43 | });
44 | }
45 |
46 | public static toJson(value: Ace.Range): IRangeData;
47 | public static toJson(value: Ace.Range[]): IRangeData[];
48 | public static toJson(value: Ace.Range | Ace.Range[]) {
49 | if (Array.isArray(value)) {
50 | return AceRangeUtil.rangesToJson(value);
51 | }
52 |
53 | return AceRangeUtil.rangeToJson(value);
54 | }
55 |
56 | public static fromJson(value: IRangeData): Ace.Range;
57 | public static fromJson(value: IRangeData[]): Ace.Range[];
58 | public static fromJson(value: IRangeData | IRangeData[]): Ace.Range | Ace.Range[] {
59 | if (Array.isArray(value)) {
60 | return AceRangeUtil.jsonToRanges(value);
61 | }
62 |
63 | return AceRangeUtil.jsonToRange(value);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/ts/AceSelectionMarker.ts:
--------------------------------------------------------------------------------
1 | import {Ace} from "ace-builds";
2 |
3 | export interface ISelectionBounds {
4 | height?: number;
5 | width?: number;
6 | top?: number;
7 | left?: number;
8 | bottom?: number;
9 | right?: number;
10 | }
11 |
12 | export class AceSelectionMarker implements Ace.MarkerLike {
13 | public range: Ace.Range;
14 | public type: string;
15 | public renderer?: Ace.MarkerRenderer;
16 | public clazz: string;
17 | public inFront: boolean;
18 | public id: number;
19 |
20 | private _session: Ace.EditSession;
21 | private readonly _label: string;
22 | private readonly _color: string;
23 | private _ranges: Ace.Range[];
24 | private readonly _selectionId: string;
25 | private readonly _id: string;
26 | private readonly _markerElement: HTMLDivElement;
27 |
28 | constructor(session: Ace.EditSession, selectionId: string, label: string, color: string, ranges: Ace.Range[]) {
29 | this._session = session;
30 | this._label = label;
31 | this._color = color;
32 | this._ranges = ranges || [];
33 | this._selectionId = selectionId;
34 | this._id = null;
35 | this._markerElement = document.createElement("div");
36 | }
37 |
38 | public update(_: string[], markerLayer: any, session: Ace.EditSession, layerConfig: any): void {
39 | while (this._markerElement.hasChildNodes()) {
40 | this._markerElement.removeChild(this._markerElement.lastChild);
41 | }
42 |
43 | this._ranges.forEach((range) => {
44 | this._renderRange(markerLayer, session, layerConfig, range);
45 | });
46 |
47 | this._markerElement.remove();
48 | markerLayer.elt("remote-selection", "");
49 | const parentNode = markerLayer.element.childNodes[markerLayer.i - 1] || markerLayer.element.lastChild;
50 | parentNode.appendChild(this._markerElement);
51 | }
52 |
53 | public setSelection(ranges: Ace.Range[]): void {
54 | if (ranges === undefined || ranges === null) {
55 | this._ranges = [];
56 | } else if (ranges instanceof Array) {
57 | this._ranges = ranges;
58 | } else {
59 | this._ranges = [ranges];
60 | }
61 |
62 | this._forceSessionUpdate();
63 | }
64 |
65 | public getLabel(): string {
66 | return this._label;
67 | }
68 |
69 | public selectionId(): string {
70 | return this._selectionId;
71 | }
72 |
73 | public markerId(): string {
74 | return this._id;
75 | }
76 |
77 | private _renderLine(bounds: ISelectionBounds): void {
78 | const div = document.createElement("div");
79 | div.className = "ace-multi-selection";
80 | div.style.backgroundColor = this._color;
81 |
82 | if (typeof bounds.height === "number") {
83 | div.style.height = `${bounds.height}px`;
84 | }
85 |
86 | if (typeof bounds.width === "number") {
87 | div.style.width = `${bounds.width}px`;
88 | }
89 |
90 | if (typeof bounds.top === "number") {
91 | div.style.top = `${bounds.top}px`;
92 | }
93 |
94 | if (typeof bounds.left === "number") {
95 | div.style.left = `${bounds.left}px`;
96 | }
97 |
98 | if (typeof bounds.bottom === "number") {
99 | div.style.bottom = `${bounds.bottom}px`;
100 | }
101 |
102 | if (typeof bounds.right === "number") {
103 | div.style.right = `${bounds.right}px`;
104 | }
105 |
106 | this._markerElement.append(div);
107 | }
108 |
109 | private _renderRange(markerLayer: any, session: Ace.EditSession, layerConfig: any, range: Ace.Range): void {
110 | const screenRange: Ace.Range = range.toScreenRange(session);
111 |
112 | let height: number = layerConfig.lineHeight;
113 | let top: number = markerLayer.$getTop(screenRange.start.row, layerConfig);
114 | let width: number = 0;
115 | const right = 0;
116 | const left: number = markerLayer.$padding + screenRange.start.column * layerConfig.characterWidth;
117 |
118 | if (screenRange.isMultiLine()) {
119 | // Render the start line
120 | this._renderLine({height, right, top, left});
121 |
122 | // from start of the last line to the selection end
123 | top = markerLayer.$getTop(screenRange.end.row, layerConfig);
124 | width = screenRange.end.column * layerConfig.characterWidth;
125 | this._renderLine({height, width, top, left: markerLayer.$padding});
126 |
127 | // all the complete lines
128 | height = (screenRange.end.row - screenRange.start.row - 1) * layerConfig.lineHeight;
129 | if (height < 0) {
130 | return;
131 | }
132 | top = markerLayer.$getTop(screenRange.start.row + 1, layerConfig);
133 | this._renderLine({height, right, top, left: markerLayer.$padding});
134 | } else {
135 | width = (range.end.column - range.start.column) * layerConfig.characterWidth;
136 | this._renderLine({height, width, top, left});
137 | }
138 | }
139 |
140 | private _forceSessionUpdate(): void {
141 | (this._session as any)._signal("changeBackMarker");
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/src/ts/AceViewportUtil.ts:
--------------------------------------------------------------------------------
1 | import {Ace} from "ace-builds";
2 | import {IIndexRange} from "./IndexRange";
3 | import {IRowRange} from "./RowRange";
4 |
5 | export class AceViewportUtil {
6 |
7 | public static getVisibleIndexRange(editor: Ace.Editor): IIndexRange {
8 | let firstRow: number = editor.getFirstVisibleRow();
9 | let lastRow: number = editor.getLastVisibleRow();
10 |
11 | if (!editor.isRowFullyVisible(firstRow)) {
12 | firstRow++;
13 | }
14 |
15 | if (!editor.isRowFullyVisible(lastRow)) {
16 | lastRow--;
17 | }
18 |
19 | const startPos: number = editor.getSession().getDocument().positionToIndex({row: firstRow, column: 0}, 0);
20 |
21 | // todo, this should probably be the end of the row
22 | const endPos: number = editor.getSession().getDocument().positionToIndex({row: lastRow, column: 0}, 0);
23 |
24 | return {
25 | start: startPos,
26 | end: endPos
27 | };
28 | }
29 |
30 | public static indicesToRows(editor: Ace.Editor, startIndex: number, endIndex: number): IRowRange {
31 | const startRow: number = editor.getSession().getDocument().indexToPosition(startIndex, 0).row;
32 | const endRow: number = editor.getSession().getDocument().indexToPosition(endIndex, 0).row;
33 |
34 | return {
35 | start: startRow,
36 | end: endRow
37 | };
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/ts/IndexRange.ts:
--------------------------------------------------------------------------------
1 | export interface IIndexRange {
2 | start: number;
3 | end: number;
4 | }
5 |
--------------------------------------------------------------------------------
/src/ts/RowRange.ts:
--------------------------------------------------------------------------------
1 | export interface IRowRange {
2 | start: number;
3 | end: number;
4 | }
5 |
--------------------------------------------------------------------------------
/src/ts/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./AceMultiSelectionManager";
2 | export * from "./AceMultiCursorManager";
3 | export * from "./AceRangeUtil";
4 | export * from "./AceRadarView";
5 | export * from "./AceViewportUtil";
6 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "ES2020",
5 | "outDir": "dist",
6 | "preserveConstEnums": true,
7 | "moduleResolution": "node",
8 | "experimentalDecorators": true,
9 | "declaration": false,
10 | "esModuleInterop": true,
11 | "sourceMap": true,
12 | "allowSyntheticDefaultImports": true,
13 | "inlineSources": true,
14 | "baseUrl": "./src/ts",
15 | "lib": ["dom", "es6", "es7"]
16 | },
17 | "include": [
18 | "src/**/*"
19 | ],
20 | "exclude": [
21 | "build",
22 | "dist",
23 | "example"
24 | ]
25 | }
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tslint:recommended",
3 | "rules": {
4 | "object-literal-sort-keys": false,
5 | "trailing-comma": false,
6 | "variable-name": false
7 | }
8 | }
--------------------------------------------------------------------------------