From 086e878b60370db23ffb49f603140c9dbebeec3b Mon Sep 17 00:00:00 2001 From: yunjy Date: Fri, 19 Aug 2022 16:02:03 +0900 Subject: [PATCH] =?UTF-8?q?=EC=88=98=EC=A0=95=EA=B0=80=EB=8A=A5=20?= =?UTF-8?q?=EB=B2=94=EC=9C=84=20=ED=95=98=EC=9D=B4=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8,=20IMPORT=20=EC=B6=94=EA=B0=80,=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A6=BD=ED=8A=B8=20=EC=84=A0=ED=83=9D=20=ED=95=84=EB=93=9CSel?= =?UTF-8?q?ect2=20=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../constrainedEditorPlugin.css | 7 + .../constrainedEditorPlugin.js | 1052 +++++++++++++++++ .../constrainedEditorPlugin.js.map | 1 + .../constrainedEditorPlugin.min.js | 2 + .../constrainedEditorPlugin.min.js.map | 1 + .../esm/constrainedEditor.css | 7 + .../esm/constrainedEditor.js | 212 ++++ .../esm/constrainedModel.js | 560 +++++++++ .../esm/utils/deepClone.js | 73 ++ .../esm/utils/definedErrors.js | 7 + .../esm/utils/enums.js | 5 + .../esm/utils/validators.js | 44 + 12 files changed, 1971 insertions(+) create mode 100644 src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.css create mode 100644 src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.js create mode 100644 src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.js.map create mode 100644 src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.min.js create mode 100644 src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.min.js.map create mode 100644 src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/constrainedEditor.css create mode 100644 src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/constrainedEditor.js create mode 100644 src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/constrainedModel.js create mode 100644 src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/utils/deepClone.js create mode 100644 src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/utils/definedErrors.js create mode 100644 src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/utils/enums.js create mode 100644 src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/utils/validators.js diff --git a/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.css b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.css new file mode 100644 index 0000000..0ddb0d4 --- /dev/null +++ b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.css @@ -0,0 +1,7 @@ +.editableArea--single-line { + background: #dde969; +} + +.editableArea--multi-line { + background: #ffb74e; +} \ No newline at end of file diff --git a/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.js b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.js new file mode 100644 index 0000000..08c7e25 --- /dev/null +++ b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.js @@ -0,0 +1,1052 @@ +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ({ + +/***/ "./src/constrainedModel.js": +/*!*********************************!*\ + !*** ./src/constrainedModel.js ***! + \*********************************/ +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "constrainedModel": () => (/* binding */ constrainedModel), +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _utils_deepClone_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils/deepClone.js */ "./src/utils/deepClone.js"); +/* harmony import */ var _utils_enums_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utils/enums.js */ "./src/utils/enums.js"); + + +const constrainedModel = function (model, ranges, monaco) { + const rangeConstructor = monaco.Range; + const sortRangesInAscendingOrder = function (rangeObject1, rangeObject2) { + const rangeA = rangeObject1.range; + const rangeB = rangeObject2.range; + if ( + rangeA[0] < rangeB[0] || + (rangeA[0] === rangeB[0] && rangeA[3] < rangeB[1]) + ) { + return -1; + } + } + const normalizeRange = function (range, content) { + const lines = content.split('\n'); + const noOfLines = lines.length; + const normalizedRange = []; + range.forEach(function (value, index) { + if (value === 0) { + throw new Error('Range values cannot be zero');//No I18n + } + switch (index) { + case 0: { + if (value < 0) { + throw new Error('Start Line of Range cannot be negative');//No I18n + } else if (value > noOfLines) { + throw new Error('Provided Start Line(' + value + ') is out of bounds. Max Lines in content is ' + noOfLines);//No I18n + } + normalizedRange[index] = value; + } + break; + case 1: { + let actualStartCol = value; + const startLineNo = normalizedRange[0]; + const maxCols = lines[startLineNo - 1].length + if (actualStartCol < 0) { + actualStartCol = maxCols - Math.abs(actualStartCol); + if (actualStartCol < 0) { + throw new Error('Provided Start Column(' + value + ') is out of bounds. Max Column in line ' + startLineNo + ' is ' + maxCols);//No I18n + } + } else if (actualStartCol > (maxCols + 1)) { + throw new Error('Provided Start Column(' + value + ') is out of bounds. Max Column in line ' + startLineNo + ' is ' + maxCols);//No I18n + } + normalizedRange[index] = actualStartCol; + } + break; + case 2: { + let actualEndLine = value; + if (actualEndLine < 0) { + actualEndLine = noOfLines - Math.abs(value); + if (actualEndLine < 0) { + throw new Error('Provided End Line(' + value + ') is out of bounds. Max Lines in content is ' + noOfLines);//No I18n + } + if (actualEndLine < normalizedRange[0]) { + console.warn('Provided End Line(' + value + ') is less than the start Line, the Restriction may not behave as expected');//No I18n + } + } else if (value > noOfLines) { + throw new Error('Provided End Line(' + value + ') is out of bounds. Max Lines in content is ' + noOfLines);//No I18n + } + normalizedRange[index] = actualEndLine; + } + break; + case 3: { + let actualEndCol = value; + const endLineNo = normalizedRange[2]; + const maxCols = lines[endLineNo - 1].length + if (actualEndCol < 0) { + actualEndCol = maxCols - Math.abs(actualEndCol); + if (actualEndCol < 0) { + throw new Error('Provided End Column(' + value + ') is out of bounds. Max Column in line ' + endLineNo + ' is ' + maxCols);//No I18n + } + } else if (actualEndCol > (maxCols + 1)) { + throw new Error('Provided Start Column(' + value + ') is out of bounds. Max Column in line ' + endLineNo + ' is ' + maxCols);//No I18n + } + normalizedRange[index] = actualEndCol; + } + break; + } + }) + return normalizedRange; + } + let restrictions = (0,_utils_deepClone_js__WEBPACK_IMPORTED_MODULE_0__.default)(ranges).sort(sortRangesInAscendingOrder); + const prepareRestrictions = function (restrictions) { + const content = model.getValue(); + restrictions.forEach(function (restriction, index) { + const range = normalizeRange(restriction.range, content); + const startLine = range[0]; + const startCol = range[1]; + const endLine = range[2]; + const endCol = range[3]; + restriction._originalRange = range.slice(); + restriction.range = new rangeConstructor(startLine, startCol, endLine, endCol); + restriction.index = index; + if (!restriction.allowMultiline) { + restriction.allowMultiline = rangeConstructor.spansMultipleLines(restriction.range) + } + if (!restriction.label) { + restriction.label = `[${startLine},${startCol} -> ${endLine}${endCol}]`; + } + }); + } + const getCurrentEditableRanges = function () { + return restrictions.reduce(function (acc, restriction) { + acc[restriction.label] = { + allowMultiline: restriction.allowMultiline || false, + index: restriction.index, + range: Object.assign({}, restriction.range), + originalRange: restriction._originalRange.slice() + }; + return acc; + }, {}); + } + const getValueInEditableRanges = function () { + return restrictions.reduce(function (acc, restriction) { + acc[restriction.label] = model.getValueInRange(restriction.range); + return acc; + }, {}); + } + const updateValueInEditableRanges = function (object, forceMoveMarkers) { + if (typeof object === 'object' && !Array.isArray(object)) { + forceMoveMarkers = typeof forceMoveMarkers === 'boolean' ? forceMoveMarkers : false; + const restrictionsMap = restrictions.reduce(function (acc, restriction) { + if (restriction.label) { + acc[restriction.label] = restriction; + } + return acc; + }, {}); + for (let label in object) { + const restriction = restrictionsMap[label]; + if (restriction) { + const value = object[label]; + if (doesChangeHasMultilineConflict(restriction, value)) { + throw new Error('Multiline change is not allowed for ' + label); + } + const newRange = (0,_utils_deepClone_js__WEBPACK_IMPORTED_MODULE_0__.default)(restriction.range); + newRange.endLine = newRange.startLine + value.split('\n').length - 1; + newRange.endColumn = value.split('\n').pop().length; + if (isChangeInvalidAsPerUser(restriction, value, newRange)) { + throw new Error('Change is invalidated by validate function of ' + label); + } + model.applyEdits([{ + forceMoveMarkers: !!forceMoveMarkers, + range: restriction.range, + text: value + }]); + } else { + console.error('No restriction found for ' + label); + } + } + } else { + throw new Error('Value must be an object');//No I18n + } + } + const disposeRestrictions = function () { + model._restrictionChangeListener.dispose(); + window.removeEventListener("error", handleUnhandledPromiseRejection); + delete model.editInRestrictedArea; + delete model.disposeRestrictions; + delete model.getValueInEditableRanges; + delete model.updateValueInEditableRanges; + delete model.updateRestrictions; + delete model.getCurrentEditableRanges; + delete model.toggleHighlightOfEditableAreas; + delete model._hasHighlight; + delete model._isRestrictedModel; + delete model._isCursorAtCheckPoint; + delete model._currentCursorPositions; + delete model._editableRangeChangeListener; + delete model._restrictionChangeListener; + delete model._oldDecorations; + delete model._oldDecorationsSource; + return model; + } + const isCursorAtCheckPoint = function (positions) { + positions.some(function (position) { + const posLineNumber = position.lineNumber; + const posCol = position.column; + const length = restrictions.length; + for (let i = 0; i < length; i++) { + const range = restrictions[i].range; + if ( + (range.startLineNumber === posLineNumber && range.startColumn === posCol) || + (range.endLineNumber === posLineNumber && range.endColumn === posCol) + ) { + model.pushStackElement(); + return true; + } + } + }); + }; + const addEditableRangeListener = function (callback) { + if (typeof callback === 'function') { + model._editableRangeChangeListener.push(callback); + } + }; + const triggerChangeListenersWith = function (currentChanges, allChanges) { + const currentRanges = getCurrentEditableRanges(); + model._editableRangeChangeListener.forEach(function (callback) { + callback.call(model, currentChanges, allChanges, currentRanges); + }); + }; + const doUndo = function () { + return Promise.resolve().then(function () { + model.editInRestrictedArea = true; + model.undo(); + model.editInRestrictedArea = false; + if (model._hasHighlight && model._oldDecorationsSource) { + // id present in the decorations info will be omitted by monaco + // So we don't need to remove the old decorations id + model.deltaDecorations(model._oldDecorations, model._oldDecorationsSource); + model._oldDecorationsSource.forEach(function (object) { + object.range = model.getDecorationRange(object.id); + }); + } + }); + }; + const updateRange = function (restriction, range, finalLine, finalColumn, changes, changeIndex) { + let oldRangeEndLineNumber = range.endLineNumber; + let oldRangeEndColumn = range.endColumn; + restriction.prevRange = range; + restriction.range = range.setEndPosition(finalLine, finalColumn); + const length = restrictions.length; + let changesLength = changes.length; + const diffInCol = finalColumn - oldRangeEndColumn; + const diffInRow = finalLine - oldRangeEndLineNumber; + + const cursorPositions = model._currentCursorPositions || []; + const noOfCursorPositions = cursorPositions.length; + // if (noOfCursorPositions > 0) { + if (changesLength !== noOfCursorPositions) { + changes = changes.filter(function (change) { + const range = change.range; + for (let i = 0; i < noOfCursorPositions; i++) { + const cursorPosition = cursorPositions[i]; + if ( + (range.startLineNumber === cursorPosition.startLineNumber) && + (range.endLineNumber === cursorPosition.endLineNumber) && + (range.startColumn === cursorPosition.startColumn) && + (range.endColumn === cursorPosition.endColumn) + ) { + return true; + } + } + return false; + }); + changesLength = changes.length; + } + if (diffInRow !== 0) { + for (let i = restriction.index + 1; i < length; i++) { + const nextRestriction = restrictions[i]; + const nextRange = nextRestriction.range; + if (oldRangeEndLineNumber === nextRange.startLineNumber) { + nextRange.startColumn += diffInCol; + } + if (oldRangeEndLineNumber === nextRange.endLineNumber) { + nextRange.endColumn += diffInCol; + } + nextRange.startLineNumber += diffInRow; + nextRange.endLineNumber += diffInRow; + nextRestriction.range = nextRange; + } + for (let i = changeIndex + 1; i < changesLength; i++) { + const nextChange = changes[i]; + const rangeInChange = nextChange.range; + const rangeAsString = rangeInChange.toString(); + const rangeMapValue = rangeMap[rangeAsString]; + delete rangeMap[rangeAsString]; + if (oldRangeEndLineNumber === rangeInChange.startLineNumber) { + rangeInChange.startColumn += diffInCol; + } + if (oldRangeEndLineNumber === rangeInChange.endLineNumber) { + rangeInChange.endColumn += diffInCol; + } + rangeInChange.startLineNumber += diffInRow; + rangeInChange.endLineNumber += diffInRow; + nextChange.range = rangeInChange; + rangeMap[rangeInChange.toString()] = rangeMapValue; + } + } else { + // Only Column might have changed + for (let i = restriction.index + 1; i < length; i++) { + const nextRestriction = restrictions[i]; + const nextRange = nextRestriction.range; + if (nextRange.startLineNumber > oldRangeEndLineNumber) { + break; + } else { + nextRange.startColumn += diffInCol; + nextRange.endColumn += diffInCol; + nextRestriction.range = nextRange; + } + } + for (let i = changeIndex + 1; i < changesLength; i++) { + // rangeMap + const nextChange = changes[i]; + const rangeInChange = nextChange.range; + const rangeAsString = rangeInChange.toString(); + const rangeMapValue = rangeMap[rangeAsString]; + delete rangeMap[rangeAsString]; + if (rangeInChange.startLineNumber > oldRangeEndLineNumber) { + rangeMap[rangeInChange.toString()] = rangeMapValue; + break; + } else { + rangeInChange.startColumn += diffInCol; + rangeInChange.endColumn += diffInCol; + nextChange.range = rangeInChange; + rangeMap[rangeInChange.toString()] = rangeMapValue; + } + } + } + // } + }; + const getInfoFrom = function (change, editableRange) { + const info = {}; + const range = change.range; + // Get State + if (change.text === '') { + info.isDeletion = true; + } else if ( + (range.startLineNumber === range.endLineNumber) && + (range.startColumn === range.endColumn) + ) { + info.isAddition = true; + } else { + info.isReplacement = true; + } + // Get Position Of Range + info.startLineOfRange = range.startLineNumber === editableRange.startLineNumber; + info.startColumnOfRange = range.startColumn === editableRange.startColumn; + + info.endLineOfRange = range.endLineNumber === editableRange.endLineNumber; + info.endColumnOfRange = range.endColumn === editableRange.endColumn; + + info.middleLineOfRange = !info.startLineOfRange && !info.endLineOfRange; + + // Editable Range Span + if (editableRange.startLineNumber === editableRange.endLineNumber) { + info.rangeIsSingleLine = true; + } else { + info.rangeIsMultiLine = true; + } + return info; + }; + const updateRestrictions = function (ranges) { + restrictions = (0,_utils_deepClone_js__WEBPACK_IMPORTED_MODULE_0__.default)(ranges).sort(sortRangesInAscendingOrder); + prepareRestrictions(restrictions); + }; + const toggleHighlightOfEditableAreas = function () { + if (!model._hasHighlight) { + const decorations = restrictions.map(function (restriction) { + const decoration = { + range: restriction.range, + options: { + className: restriction.allowMultiline ? + _utils_enums_js__WEBPACK_IMPORTED_MODULE_1__.default.MULTI_LINE_HIGHLIGHT_CLASS : + _utils_enums_js__WEBPACK_IMPORTED_MODULE_1__.default.SINGLE_LINE_HIGHLIGHT_CLASS + } + } + if (restriction.label) { + decoration.hoverMessage = restriction.label; + } + return decoration; + }); + model._oldDecorations = model.deltaDecorations([], decorations); + model._oldDecorationsSource = decorations.map(function (decoration, index) { + return Object.assign({}, decoration, { id: model._oldDecorations[index] }); + }); + model._hasHighlight = true; + } else { + model.deltaDecorations(model._oldDecorations, []); + delete model._oldDecorations; + delete model._oldDecorationsSource; + model._hasHighlight = false; + } + } + const handleUnhandledPromiseRejection = function () { + console.debug('handler for unhandled promise rejection'); + }; + const setAllRangesToPrev = function (rangeMap) { + for (let key in rangeMap) { + const restriction = rangeMap[key]; + restriction.range = restriction.prevRange; + } + }; + const doesChangeHasMultilineConflict = function (restriction, text) { + return !restriction.allowMultiline && text.includes('\n'); + }; + const isChangeInvalidAsPerUser = function (restriction, value, range) { + return restriction.validate && !restriction.validate(value, range, restriction.lastInfo); + } + + const manipulatorApi = { + _isRestrictedModel: true, + _isRestrictedValueValid: true, + _editableRangeChangeListener: [], + _isCursorAtCheckPoint: isCursorAtCheckPoint, + _currentCursorPositions: [] + } + + prepareRestrictions(restrictions); + model._hasHighlight = false; + manipulatorApi._restrictionChangeListener = model.onDidChangeContent(function (contentChangedEvent) { + const isUndoing = contentChangedEvent.isUndoing; + model._isRestrictedValueValid = true; + if (!(isUndoing && model.editInRestrictedArea)) { + const changes = contentChangedEvent.changes.sort(sortRangesInAscendingOrder); + const rangeMap = {}; + const length = restrictions.length; + const isAllChangesValid = changes.every(function (change) { + const editedRange = change.range; + const rangeAsString = editedRange.toString(); + rangeMap[rangeAsString] = null; + for (let i = 0; i < length; i++) { + const restriction = restrictions[i]; + const range = restriction.range; + if (range.containsRange(editedRange)) { + if (doesChangeHasMultilineConflict(restriction, change.text)) { + return false; + } + rangeMap[rangeAsString] = restriction; + return true; + } + } + return false; + }) + if (isAllChangesValid) { + changes.forEach(function (change, changeIndex) { + const changedRange = change.range; + const restriction = rangeMap[changedRange.toString()]; + const editableRange = restriction.range; + const text = change.text || ''; + /** + * Things to check before implementing the change + * - A | D | R => Addition | Deletion | Replacement + * - MC | SC => MultiLineChange | SingleLineChange + * - SOR | MOR | EOR => Change Occured in - Start Of Range | Middle Of Range | End Of Range + * - SSL | SML => Editable Range - Spans Single Line | Spans Multiple Line + */ + const noOfLinesAdded = (text.match(/\n/g) || []).length; + const noOfColsAddedAtLastLine = text.split(/\n/g).pop().length; + + const lineDiffInRange = changedRange.endLineNumber - changedRange.startLineNumber; + const colDiffInRange = changedRange.endColumn - changedRange.startColumn; + + let finalLine = editableRange.endLineNumber; + let finalColumn = editableRange.endColumn; + + let columnsCarriedToEnd = 0; + if ( + (editableRange.endLineNumber === changedRange.startLineNumber) || + (editableRange.endLineNumber === changedRange.endLineNumber) + ) { + columnsCarriedToEnd += (editableRange.endColumn - changedRange.startColumn) + 1; + } + + const info = getInfoFrom(change, editableRange); + restriction.lastInfo = info; + if (info.isAddition || info.isReplacement) { + if (info.rangeIsSingleLine) { + /** + * Only Column Change has occurred , so regardless of the position of the change + * Addition of noOfCols is enough + */ + if (noOfLinesAdded === 0) { + finalColumn += noOfColsAddedAtLastLine; + } else { + finalLine += noOfLinesAdded; + if (info.startColumnOfRange) { + finalColumn += noOfColsAddedAtLastLine + } else if (info.endColumnOfRange) { + finalColumn = (noOfColsAddedAtLastLine + 1) + } else { + finalColumn = (noOfColsAddedAtLastLine + columnsCarriedToEnd) + } + } + } + if (info.rangeIsMultiLine) { + // Handling for Start Of Range is not required + finalLine += noOfLinesAdded; + if (info.endLineOfRange) { + if (noOfLinesAdded === 0) { + finalColumn += noOfColsAddedAtLastLine; + } else { + finalColumn = (columnsCarriedToEnd + noOfColsAddedAtLastLine); + } + } + } + } + if (info.isDeletion || info.isReplacement) { + if (info.rangeIsSingleLine) { + finalColumn -= colDiffInRange; + } + if (info.rangeIsMultiLine) { + if (info.endLineOfRange) { + finalLine -= lineDiffInRange; + finalColumn -= colDiffInRange; + } else { + finalLine -= lineDiffInRange; + } + } + } + updateRange(restriction, editableRange, finalLine, finalColumn, changes, changeIndex); + }); + const values = model.getValueInEditableRanges(); + const currentlyEditedRanges = {}; + for (let key in rangeMap) { + const restriction = rangeMap[key]; + const range = restriction.range; + const rangeString = restriction.label || range.toString(); + const value = values[rangeString]; + if (isChangeInvalidAsPerUser(restriction, value, range)) { + setAllRangesToPrev(rangeMap); + doUndo(); + return; // Breaks the loop and prevents the triggerChangeListener + } + currentlyEditedRanges[rangeString] = value; + } + if (model._hasHighlight) { + model._oldDecorationsSource.forEach(function (object) { + object.range = model.getDecorationRange(object.id); + }); + } + triggerChangeListenersWith(currentlyEditedRanges, values); + } else { + doUndo(); + } + } else if (model.editInRestrictedArea) { + model._isRestrictedValueValid = false; + } + }); + window.onerror = handleUnhandledPromiseRejection; + const exposedApi = { + editInRestrictedArea: false, + getCurrentEditableRanges: getCurrentEditableRanges, + getValueInEditableRanges: getValueInEditableRanges, + disposeRestrictions: disposeRestrictions, + onDidChangeContentInEditableRange: addEditableRangeListener, + updateRestrictions: updateRestrictions, + updateValueInEditableRanges: updateValueInEditableRanges, + toggleHighlightOfEditableAreas: toggleHighlightOfEditableAreas + } + for (let funcName in manipulatorApi) { + Object.defineProperty(model, funcName, { + enumerable: false, + configurable: true, + writable: true, + value: manipulatorApi[funcName] + }) + } + for (let apiName in exposedApi) { + Object.defineProperty(model, apiName, { + enumerable: false, + configurable: true, + writable: true, + value: exposedApi[apiName] + }) + } + return model; +} +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (constrainedModel); + +/***/ }), + +/***/ "./src/utils/deepClone.js": +/*!********************************!*\ + !*** ./src/utils/deepClone.js ***! + \********************************/ +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "deepClone": () => (/* binding */ deepClone), +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const deepClone = (function () { + const byPassPrimitives = function (value, callback) { + if (typeof value !== 'object' || value === null) { + return this.freeze ? Object.freeze(value) : value; + } + if (value instanceof Date) { + return this.freeze ? Object.freeze(new Date(value)) : new Date(value); + } + return callback.call(this, value); + } + const cloneArray = function (array, callback) { + const keys = Object.keys(array); + const arrayClone = new Array(keys.length) + for (let i = 0; i < keys.length; i++) { + arrayClone[keys[i]] = byPassPrimitives.call(this, array[keys[i]], callback); + } + return arrayClone; + } + const cloner = function (object) { + return byPassPrimitives.call(this, object, function (object) { + if (Array.isArray(object)) { + return cloneArray.call(this, object, cloner) + } + const clone = {}; + for (let key in object) { + if (!this.withProto && Object.hasOwnProperty.call(object, key) === false) { + continue; + } + clone[key] = byPassPrimitives.call(this, object[key], cloner); + } + return clone; + }) + } + const config = (function () { + const constructOptionForCode = function (value) { + const options = [ + 'withProto', + 'freeze' + ] + this[value] = options.reduce(function (acc, option) { + if (acc[option] = (value >= this[option])) { + value -= this[option] + } + return acc; + }.bind(this), {}) + } + const codes = Object.create(Object.defineProperties({}, { + withProto: { value: 1 }, + freeze: { value: 2 } + })); + for (let i = 0; i <= 3; i++) { + constructOptionForCode.call(codes, i); + } + return codes; + }()); + const methods = { + withProto: cloner.bind(config[1]), + andFreeze: cloner.bind(config[2]), + withProtoAndFreeze: cloner.bind(config[3]) + } + const API = cloner.bind(config[0]); + for (let methodName in methods) { + Object.defineProperty(API, methodName, { + enumerable: false, + writable: false, + configurable: false, + value: methods[methodName] + }) + } + return API; +}()); + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (deepClone); + +/***/ }), + +/***/ "./src/utils/definedErrors.js": +/*!************************************!*\ + !*** ./src/utils/definedErrors.js ***! + \************************************/ +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "TypeMustBe": () => (/* binding */ TypeMustBe), +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const TypeMustBe = function (type, key, additional) { + return 'The value for the ' + key + ' should be of type ' + (Array.isArray(type) ? type.join(' | ') : type) + '. ' + (additional || '') +} +const definedErrors = { + TypeMustBe : TypeMustBe +}; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (definedErrors); + +/***/ }), + +/***/ "./src/utils/enums.js": +/*!****************************!*\ + !*** ./src/utils/enums.js ***! + \****************************/ +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "enums": () => (/* binding */ enums), +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const enums = { + SINGLE_LINE_HIGHLIGHT_CLASS: 'editableArea--single-line', + MULTI_LINE_HIGHLIGHT_CLASS: 'editableArea--multi-line' +} +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (enums); + +/***/ }), + +/***/ "./src/utils/validators.js": +/*!*********************************!*\ + !*** ./src/utils/validators.js ***! + \*********************************/ +/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +const validators = { + initWith: function (monaco) { + const dummyDiv = document.createElement('div'); + const dummyEditorInstance = monaco.editor.create(dummyDiv); + const editorInstanceConstructorName = dummyEditorInstance.constructor.name; + const editorModelConstructorName = dummyEditorInstance.getModel().constructor.name; + const instanceCheck = function (valueToValidate) { + return valueToValidate.constructor.name === editorInstanceConstructorName; + } + const modelCheck = function (valueToValidate) { + return valueToValidate.constructor.name === editorModelConstructorName; + } + const rangesCheck = function (ranges) { + if (Array.isArray(ranges)) { + return ranges.every(function (rangeObj) { + if (typeof rangeObj === 'object' && rangeObj.constructor.name === 'Object') { + if (!rangeObj.hasOwnProperty('range')) return false; + if (!Array.isArray(rangeObj.range)) return false; + if (rangeObj.range.length !== 4) return false; + if (!(rangeObj.range.every(num => num > 0 && parseInt(num) === num))) return false; + if (rangeObj.hasOwnProperty('allowMultiline')) { + if (typeof rangeObj.allowMultiline !== 'boolean') return false; + } + if (rangeObj.hasOwnProperty('label')) { + if (typeof rangeObj.label !== 'string') return false; + } + if (rangeObj.hasOwnProperty('validate')) { + if (typeof rangeObj.validate !== 'function') return false; + } + return true; + } + return false; + }); + } + return false; + } + return { + isInstanceValid: instanceCheck, + isModelValid: modelCheck, + isRangesValid: rangesCheck + } + } +} +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (validators); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. +(() => { +/*!**********************************!*\ + !*** ./src/constrainedEditor.js ***! + \**********************************/ +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "constrainedEditor": () => (/* binding */ constrainedEditor), +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _utils_validators_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils/validators.js */ "./src/utils/validators.js"); +/* harmony import */ var _utils_definedErrors_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utils/definedErrors.js */ "./src/utils/definedErrors.js"); +/* harmony import */ var _constrainedModel_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./constrainedModel.js */ "./src/constrainedModel.js"); + + + + +function constrainedEditor(monaco) { + /** + * Injected Dependencies + */ + if (monaco === undefined) { + throw new Error([ + "Please pass the monaco global variable into function as", + "(eg:)constrainedEditor({ range : monaco.range });", + ].join('\n')); + } + /** + * + * @param {Object} editorInstance This should be the monaco editor instance. + * @description This is the listener function to check whether the cursor is at checkpoints + * (i.e) the point where editable and non editable portions meet + */ + const listenerFn = function (editorInstance) { + const model = editorInstance.getModel(); + if (model._isCursorAtCheckPoint) { + const selections = editorInstance.getSelections(); + const positions = selections.map(function (selection) { + return { + lineNumber: selection.positionLineNumber, + column: selection.positionColumn + } + }); + model._isCursorAtCheckPoint(positions); + model._currentCursorPositions = selections; + } + } + const _uriRestrictionMap = {}; + const { isInstanceValid, isModelValid, isRangesValid } = _utils_validators_js__WEBPACK_IMPORTED_MODULE_0__.default.initWith(monaco); + /** + * + * @param {Object} editorInstance This should be the monaco editor instance + * @returns {Boolean} + */ + const initInEditorInstance = function (editorInstance) { + if (isInstanceValid(editorInstance)) { + const domNode = editorInstance.getDomNode(); + manipulator._listener = listenerFn.bind(API, editorInstance); + manipulator._editorInstance = editorInstance; + manipulator._editorInstance._isInDevMode = false; + domNode.addEventListener('keydown', manipulator._listener, true); + editorInstance.onDidChangeModel(function () { + // domNode - refers old dom node + domNode.removeEventListener('keydown', manipulator._listener, true) + const newDomNode = editorInstance.getDomNode(); // Gets Current dom node + newDomNode.addEventListener('keydown', manipulator._listener, true); + domNode = newDomNode; + }) + return true; + } else { + throw new Error( + (0,_utils_definedErrors_js__WEBPACK_IMPORTED_MODULE_1__.TypeMustBe)( + 'ICodeEditor', + 'editorInstance', + 'This type interface can be found in monaco editor documentation' + ) + ) + } + } + /** + * + * @param {Object} model This should be the monaco editor model instance. Refer https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.itextmodel.html + * @param {*} ranges This should be the array of range objects. Refer constrained editor plugin documentation + * @returns model + */ + const addRestrictionsTo = function (model, ranges) { + if (isModelValid(model)) { + if (isRangesValid(ranges)) { + const modelToConstrain = (0,_constrainedModel_js__WEBPACK_IMPORTED_MODULE_2__.default)(model, ranges, monaco, manipulator._editorInstance); + _uriRestrictionMap[modelToConstrain.uri.toString()] = modelToConstrain; + return modelToConstrain; + } else { + throw new Error( + (0,_utils_definedErrors_js__WEBPACK_IMPORTED_MODULE_1__.TypeMustBe)( + 'Array', + 'ranges', + 'Please refer constrained editor documentation for proper structure' + ) + ) + } + } else { + throw new Error( + (0,_utils_definedErrors_js__WEBPACK_IMPORTED_MODULE_1__.TypeMustBe)( + 'ICodeEditor', + 'editorInstance', + 'This type interface can be found in monaco editor documentation' + ) + ) + } + } + /** + * + * @param {Object} model This should be the monaco editor model instance. Refer https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.itextmodel.html + * @returns {Boolean} True if the restrictions are removed + */ + const removeRestrictionsIn = function (model) { + if (isModelValid(model)) { + const uri = model.uri.toString(); + const restrictedModel = _uriRestrictionMap[uri]; + if (restrictedModel) { + return restrictedModel.disposeRestrictions(); + } else { + console.warn('Current Model is not a restricted Model'); + return false; + } + } else { + throw new Error( + (0,_utils_definedErrors_js__WEBPACK_IMPORTED_MODULE_1__.TypeMustBe)( + 'ICodeEditor', + 'editorInstance', + 'This type interface can be found in monaco editor documentation' + ) + ) + } + } + /** + * + * @returns {Boolean} True if the constrainer is disposed + */ + const disposeConstrainer = function () { + if (manipulator._editorInstance) { + const instance = manipulator._editorInstance; + const domNode = instance.getDomNode(); + domNode.removeEventListener('keydown', manipulator._listener); + delete manipulator._listener; + delete manipulator._editorInstance._isInDevMode; + delete manipulator._editorInstance._devModeAction; + delete manipulator._editorInstance; + for (let key in _uriRestrictionMap) { + delete _uriRestrictionMap[key]; + } + return true; + } + return false; + } + /** + * @description This function used to make the developer to find the ranges of selected portions + */ + const toggleDevMode = function () { + if (manipulator._editorInstance._isInDevMode) { + manipulator._editorInstance._isInDevMode = false; + manipulator._editorInstance._devModeAction.dispose(); + delete manipulator._editorInstance._devModeAction; + } else { + manipulator._editorInstance._isInDevMode = true; + manipulator._editorInstance._devModeAction = manipulator._editorInstance.addAction({ + id: 'showRange', + label: 'Show Range in console', + contextMenuGroupId: 'navigation', + contextMenuOrder: 1.5, + run: function (editor) { + const selections = editor.getSelections(); + const ranges = selections.reduce(function (acc, { startLineNumber, endLineNumber, startColumn, endColumn }) { + acc.push('range : ' + JSON.stringify([ + startLineNumber, + startColumn, + endLineNumber, + endColumn + ])); + return acc; + }, []).join('\n'); + console.log(`Selected Ranges : \n` + JSON.stringify(ranges, null, 2)); + } + }); + } + } + + /** + * Main Function starts here + */ + // @internal + const manipulator = { + /** + * These variables should not be modified by external code + * This has to be used for debugging and testing + */ + _listener: null, + _editorInstance: null, + _uriRestrictionMap: _uriRestrictionMap, + _injectedResources: monaco + } + const API = Object.create(manipulator); + const exposedMethods = { + /** + * These functions are exposed to the user + * These functions should be protected from editing + */ + initializeIn: initInEditorInstance, + addRestrictionsTo: addRestrictionsTo, + removeRestrictionsIn: removeRestrictionsIn, + disposeConstrainer: disposeConstrainer, + toggleDevMode: toggleDevMode + } + for (let methodName in exposedMethods) { + Object.defineProperty(API, methodName, { + enumerable: false, + writable: false, + configurable: false, + value: exposedMethods[methodName] + }) + } + return Object.freeze(API); +} + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (constrainedEditor); +})(); + +window.constrainedEditor = __webpack_exports__.default; +/******/ })() +; +//# sourceMappingURL=constrainedEditorPlugin.js.map \ No newline at end of file diff --git a/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.js.map b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.js.map new file mode 100644 index 0000000..fcecbce --- /dev/null +++ b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack://constrainedEditor/./src/constrainedModel.js","webpack://constrainedEditor/./src/utils/deepClone.js","webpack://constrainedEditor/./src/utils/definedErrors.js","webpack://constrainedEditor/./src/utils/enums.js","webpack://constrainedEditor/./src/utils/validators.js","webpack://constrainedEditor/webpack/bootstrap","webpack://constrainedEditor/webpack/runtime/define property getters","webpack://constrainedEditor/webpack/runtime/hasOwnProperty shorthand","webpack://constrainedEditor/webpack/runtime/make namespace object","webpack://constrainedEditor/./src/constrainedEditor.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAA6C;AACR;AAC9B;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uDAAuD;AACvD;AACA;AACA;AACA;AACA,sEAAsE;AACtE,WAAW;AACX,yHAAyH;AACzH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6IAA6I;AAC7I;AACA,WAAW;AACX,2IAA2I;AAC3I;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yHAAyH;AACzH;AACA;AACA,uIAAuI;AACvI;AACA,WAAW;AACX,uHAAuH;AACvH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yIAAyI;AACzI;AACA,WAAW;AACX,yIAAyI;AACzI;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,qBAAqB,4DAAS;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,UAAU,GAAG,SAAS,MAAM,QAAQ,EAAE,OAAO;AAC7E;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B;AAC/B;AACA;AACA;AACA,KAAK,IAAI;AACT;AACA;AACA;AACA;AACA;AACA,KAAK,IAAI;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,IAAI;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,4DAAS;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX,SAAS;AACT;AACA;AACA;AACA,KAAK;AACL,iDAAiD;AACjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB,YAAY;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,yBAAyB;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA,yCAAyC,YAAY;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,mBAAmB;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,yCAAyC,YAAY;AACrD;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA,mCAAmC,mBAAmB;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,mBAAmB,4DAAS;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,+EAAgC;AAC9C,cAAc,gFAAiC;AAC/C;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA,+BAA+B,eAAe,mCAAmC;AACjF,OAAO;AACP;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,YAAY;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA,iBAAiB;AACjB;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAmB;AACnB;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA,OAAO;AACP;AACA;AACA,KAAK;AACL;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,iEAAe,gBAAgB,E;;;;;;;;;;;;;;;AC/iBxB;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAmB,iBAAiB;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAe;AACtB;AACA,0DAA0D;AAC1D,kBAAkB,WAAW;AAC7B,eAAe;AACf,KAAK;AACL,mBAAmB,QAAQ;AAC3B;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,CAAC;;AAED,iEAAe,SAAS,E;;;;;;;;;;;;;;;ACxEjB;AACP;AACA;AACA;AACA;AACA;AACA,iEAAe,aAAa,E;;;;;;;;;;;;;;;ACNrB;AACP;AACA;AACA;AACA,iEAAe,KAAK,E;;;;;;;;;;;;;;ACJpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iEAAe,UAAU,E;;;;;;UC3CzB;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;;;;WCtBA;WACA;WACA;WACA;WACA,wCAAwC,yCAAyC;WACjF;WACA;WACA,E;;;;;WCPA,wF;;;;;WCAA;WACA;WACA;WACA,sDAAsD,kBAAkB;WACxE;WACA,+CAA+C,cAAc;WAC7D,E;;;;;;;;;;;;;;;;;;ACN+C;AACO;AACD;;AAE9C;AACP;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,uBAAuB,EAAE;AACxD;AACA;AACA;AACA;AACA,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA,SAAS,+CAA+C,GAAG,kEAAmB;AAC9E;AACA;AACA,aAAa,OAAO;AACpB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uDAAuD;AACvD;AACA;AACA,OAAO;AACP;AACA,KAAK;AACL;AACA,QAAQ,mEAAU;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa,OAAO;AACpB,aAAa,EAAE;AACf;AACA;AACA;AACA;AACA;AACA,iCAAiC,6DAAgB;AACjD;AACA;AACA,OAAO;AACP;AACA,UAAU,mEAAU;AACpB;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,QAAQ,mEAAU;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa,OAAO;AACpB,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA,KAAK;AACL;AACA,QAAQ,mEAAU;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2DAA2D,yDAAyD;AACpH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA,iEAAe,iBAAiB,E","file":"constrainedEditorPlugin.js","sourcesContent":["import deepClone from './utils/deepClone.js';\nimport enums from './utils/enums.js';\nexport const constrainedModel = function (model, ranges, monaco) {\n const rangeConstructor = monaco.Range;\n const sortRangesInAscendingOrder = function (rangeObject1, rangeObject2) {\n const rangeA = rangeObject1.range;\n const rangeB = rangeObject2.range;\n if (\n rangeA[0] < rangeB[0] ||\n (rangeA[0] === rangeB[0] && rangeA[3] < rangeB[1])\n ) {\n return -1;\n }\n }\n const normalizeRange = function (range, content) {\n const lines = content.split('\\n');\n const noOfLines = lines.length;\n const normalizedRange = [];\n range.forEach(function (value, index) {\n if (value === 0) {\n throw new Error('Range values cannot be zero');//No I18n\n }\n switch (index) {\n case 0: {\n if (value < 0) {\n throw new Error('Start Line of Range cannot be negative');//No I18n\n } else if (value > noOfLines) {\n throw new Error('Provided Start Line(' + value + ') is out of bounds. Max Lines in content is ' + noOfLines);//No I18n\n }\n normalizedRange[index] = value;\n }\n break;\n case 1: {\n let actualStartCol = value;\n const startLineNo = normalizedRange[0];\n const maxCols = lines[startLineNo - 1].length\n if (actualStartCol < 0) {\n actualStartCol = maxCols - Math.abs(actualStartCol);\n if (actualStartCol < 0) {\n throw new Error('Provided Start Column(' + value + ') is out of bounds. Max Column in line ' + startLineNo + ' is ' + maxCols);//No I18n\n }\n } else if (actualStartCol > (maxCols + 1)) {\n throw new Error('Provided Start Column(' + value + ') is out of bounds. Max Column in line ' + startLineNo + ' is ' + maxCols);//No I18n\n }\n normalizedRange[index] = actualStartCol;\n }\n break;\n case 2: {\n let actualEndLine = value;\n if (actualEndLine < 0) {\n actualEndLine = noOfLines - Math.abs(value);\n if (actualEndLine < 0) {\n throw new Error('Provided End Line(' + value + ') is out of bounds. Max Lines in content is ' + noOfLines);//No I18n\n }\n if (actualEndLine < normalizedRange[0]) {\n console.warn('Provided End Line(' + value + ') is less than the start Line, the Restriction may not behave as expected');//No I18n\n }\n } else if (value > noOfLines) {\n throw new Error('Provided End Line(' + value + ') is out of bounds. Max Lines in content is ' + noOfLines);//No I18n\n }\n normalizedRange[index] = actualEndLine;\n }\n break;\n case 3: {\n let actualEndCol = value;\n const endLineNo = normalizedRange[2];\n const maxCols = lines[endLineNo - 1].length\n if (actualEndCol < 0) {\n actualEndCol = maxCols - Math.abs(actualEndCol);\n if (actualEndCol < 0) {\n throw new Error('Provided End Column(' + value + ') is out of bounds. Max Column in line ' + endLineNo + ' is ' + maxCols);//No I18n\n }\n } else if (actualEndCol > (maxCols + 1)) {\n throw new Error('Provided Start Column(' + value + ') is out of bounds. Max Column in line ' + endLineNo + ' is ' + maxCols);//No I18n\n }\n normalizedRange[index] = actualEndCol;\n }\n break;\n }\n })\n return normalizedRange;\n }\n let restrictions = deepClone(ranges).sort(sortRangesInAscendingOrder);\n const prepareRestrictions = function (restrictions) {\n const content = model.getValue();\n restrictions.forEach(function (restriction, index) {\n const range = normalizeRange(restriction.range, content);\n const startLine = range[0];\n const startCol = range[1];\n const endLine = range[2];\n const endCol = range[3];\n restriction._originalRange = range.slice();\n restriction.range = new rangeConstructor(startLine, startCol, endLine, endCol);\n restriction.index = index;\n if (!restriction.allowMultiline) {\n restriction.allowMultiline = rangeConstructor.spansMultipleLines(restriction.range)\n }\n if (!restriction.label) {\n restriction.label = `[${startLine},${startCol} -> ${endLine}${endCol}]`;\n }\n });\n }\n const getCurrentEditableRanges = function () {\n return restrictions.reduce(function (acc, restriction) {\n acc[restriction.label] = {\n allowMultiline: restriction.allowMultiline || false,\n index: restriction.index,\n range: Object.assign({}, restriction.range),\n originalRange: restriction._originalRange.slice()\n };\n return acc;\n }, {});\n }\n const getValueInEditableRanges = function () {\n return restrictions.reduce(function (acc, restriction) {\n acc[restriction.label] = model.getValueInRange(restriction.range);\n return acc;\n }, {});\n }\n const updateValueInEditableRanges = function (object, forceMoveMarkers) {\n if (typeof object === 'object' && !Array.isArray(object)) {\n forceMoveMarkers = typeof forceMoveMarkers === 'boolean' ? forceMoveMarkers : false;\n const restrictionsMap = restrictions.reduce(function (acc, restriction) {\n if (restriction.label) {\n acc[restriction.label] = restriction;\n }\n return acc;\n }, {});\n for (let label in object) {\n const restriction = restrictionsMap[label];\n if (restriction) {\n const value = object[label];\n if (doesChangeHasMultilineConflict(restriction, value)) {\n throw new Error('Multiline change is not allowed for ' + label);\n }\n const newRange = deepClone(restriction.range);\n newRange.endLine = newRange.startLine + value.split('\\n').length - 1;\n newRange.endColumn = value.split('\\n').pop().length;\n if (isChangeInvalidAsPerUser(restriction, value, newRange)) {\n throw new Error('Change is invalidated by validate function of ' + label);\n }\n model.applyEdits([{\n forceMoveMarkers: !!forceMoveMarkers,\n range: restriction.range,\n text: value\n }]);\n } else {\n console.error('No restriction found for ' + label);\n }\n }\n } else {\n throw new Error('Value must be an object');//No I18n\n }\n }\n const disposeRestrictions = function () {\n model._restrictionChangeListener.dispose();\n window.removeEventListener(\"error\", handleUnhandledPromiseRejection);\n delete model.editInRestrictedArea;\n delete model.disposeRestrictions;\n delete model.getValueInEditableRanges;\n delete model.updateValueInEditableRanges;\n delete model.updateRestrictions;\n delete model.getCurrentEditableRanges;\n delete model.toggleHighlightOfEditableAreas;\n delete model._hasHighlight;\n delete model._isRestrictedModel;\n delete model._isCursorAtCheckPoint;\n delete model._currentCursorPositions;\n delete model._editableRangeChangeListener;\n delete model._restrictionChangeListener;\n delete model._oldDecorations;\n delete model._oldDecorationsSource;\n return model;\n }\n const isCursorAtCheckPoint = function (positions) {\n positions.some(function (position) {\n const posLineNumber = position.lineNumber;\n const posCol = position.column;\n const length = restrictions.length;\n for (let i = 0; i < length; i++) {\n const range = restrictions[i].range;\n if (\n (range.startLineNumber === posLineNumber && range.startColumn === posCol) ||\n (range.endLineNumber === posLineNumber && range.endColumn === posCol)\n ) {\n model.pushStackElement();\n return true;\n }\n }\n });\n };\n const addEditableRangeListener = function (callback) {\n if (typeof callback === 'function') {\n model._editableRangeChangeListener.push(callback);\n }\n };\n const triggerChangeListenersWith = function (currentChanges, allChanges) {\n const currentRanges = getCurrentEditableRanges();\n model._editableRangeChangeListener.forEach(function (callback) {\n callback.call(model, currentChanges, allChanges, currentRanges);\n });\n };\n const doUndo = function () {\n return Promise.resolve().then(function () {\n model.editInRestrictedArea = true;\n model.undo();\n model.editInRestrictedArea = false;\n if (model._hasHighlight && model._oldDecorationsSource) {\n // id present in the decorations info will be omitted by monaco\n // So we don't need to remove the old decorations id\n model.deltaDecorations(model._oldDecorations, model._oldDecorationsSource);\n model._oldDecorationsSource.forEach(function (object) {\n object.range = model.getDecorationRange(object.id);\n });\n }\n });\n };\n const updateRange = function (restriction, range, finalLine, finalColumn, changes, changeIndex) {\n let oldRangeEndLineNumber = range.endLineNumber;\n let oldRangeEndColumn = range.endColumn;\n restriction.prevRange = range;\n restriction.range = range.setEndPosition(finalLine, finalColumn);\n const length = restrictions.length;\n let changesLength = changes.length;\n const diffInCol = finalColumn - oldRangeEndColumn;\n const diffInRow = finalLine - oldRangeEndLineNumber;\n\n const cursorPositions = model._currentCursorPositions || [];\n const noOfCursorPositions = cursorPositions.length;\n // if (noOfCursorPositions > 0) {\n if (changesLength !== noOfCursorPositions) {\n changes = changes.filter(function (change) {\n const range = change.range;\n for (let i = 0; i < noOfCursorPositions; i++) {\n const cursorPosition = cursorPositions[i];\n if (\n (range.startLineNumber === cursorPosition.startLineNumber) &&\n (range.endLineNumber === cursorPosition.endLineNumber) &&\n (range.startColumn === cursorPosition.startColumn) &&\n (range.endColumn === cursorPosition.endColumn)\n ) {\n return true;\n }\n }\n return false;\n });\n changesLength = changes.length;\n }\n if (diffInRow !== 0) {\n for (let i = restriction.index + 1; i < length; i++) {\n const nextRestriction = restrictions[i];\n const nextRange = nextRestriction.range;\n if (oldRangeEndLineNumber === nextRange.startLineNumber) {\n nextRange.startColumn += diffInCol;\n }\n if (oldRangeEndLineNumber === nextRange.endLineNumber) {\n nextRange.endColumn += diffInCol;\n }\n nextRange.startLineNumber += diffInRow;\n nextRange.endLineNumber += diffInRow;\n nextRestriction.range = nextRange;\n }\n for (let i = changeIndex + 1; i < changesLength; i++) {\n const nextChange = changes[i];\n const rangeInChange = nextChange.range;\n const rangeAsString = rangeInChange.toString();\n const rangeMapValue = rangeMap[rangeAsString];\n delete rangeMap[rangeAsString];\n if (oldRangeEndLineNumber === rangeInChange.startLineNumber) {\n rangeInChange.startColumn += diffInCol;\n }\n if (oldRangeEndLineNumber === rangeInChange.endLineNumber) {\n rangeInChange.endColumn += diffInCol;\n }\n rangeInChange.startLineNumber += diffInRow;\n rangeInChange.endLineNumber += diffInRow;\n nextChange.range = rangeInChange;\n rangeMap[rangeInChange.toString()] = rangeMapValue;\n }\n } else {\n // Only Column might have changed\n for (let i = restriction.index + 1; i < length; i++) {\n const nextRestriction = restrictions[i];\n const nextRange = nextRestriction.range;\n if (nextRange.startLineNumber > oldRangeEndLineNumber) {\n break;\n } else {\n nextRange.startColumn += diffInCol;\n nextRange.endColumn += diffInCol;\n nextRestriction.range = nextRange;\n }\n }\n for (let i = changeIndex + 1; i < changesLength; i++) {\n // rangeMap\n const nextChange = changes[i];\n const rangeInChange = nextChange.range;\n const rangeAsString = rangeInChange.toString();\n const rangeMapValue = rangeMap[rangeAsString];\n delete rangeMap[rangeAsString];\n if (rangeInChange.startLineNumber > oldRangeEndLineNumber) {\n rangeMap[rangeInChange.toString()] = rangeMapValue;\n break;\n } else {\n rangeInChange.startColumn += diffInCol;\n rangeInChange.endColumn += diffInCol;\n nextChange.range = rangeInChange;\n rangeMap[rangeInChange.toString()] = rangeMapValue;\n }\n }\n }\n // }\n };\n const getInfoFrom = function (change, editableRange) {\n const info = {};\n const range = change.range;\n // Get State\n if (change.text === '') {\n info.isDeletion = true;\n } else if (\n (range.startLineNumber === range.endLineNumber) &&\n (range.startColumn === range.endColumn)\n ) {\n info.isAddition = true;\n } else {\n info.isReplacement = true;\n }\n // Get Position Of Range\n info.startLineOfRange = range.startLineNumber === editableRange.startLineNumber;\n info.startColumnOfRange = range.startColumn === editableRange.startColumn;\n\n info.endLineOfRange = range.endLineNumber === editableRange.endLineNumber;\n info.endColumnOfRange = range.endColumn === editableRange.endColumn;\n\n info.middleLineOfRange = !info.startLineOfRange && !info.endLineOfRange;\n\n // Editable Range Span\n if (editableRange.startLineNumber === editableRange.endLineNumber) {\n info.rangeIsSingleLine = true;\n } else {\n info.rangeIsMultiLine = true;\n }\n return info;\n };\n const updateRestrictions = function (ranges) {\n restrictions = deepClone(ranges).sort(sortRangesInAscendingOrder);\n prepareRestrictions(restrictions);\n };\n const toggleHighlightOfEditableAreas = function () {\n if (!model._hasHighlight) {\n const decorations = restrictions.map(function (restriction) {\n const decoration = {\n range: restriction.range,\n options: {\n className: restriction.allowMultiline ?\n enums.MULTI_LINE_HIGHLIGHT_CLASS :\n enums.SINGLE_LINE_HIGHLIGHT_CLASS\n }\n }\n if (restriction.label) {\n decoration.hoverMessage = restriction.label;\n }\n return decoration;\n });\n model._oldDecorations = model.deltaDecorations([], decorations);\n model._oldDecorationsSource = decorations.map(function (decoration, index) {\n return Object.assign({}, decoration, { id: model._oldDecorations[index] });\n });\n model._hasHighlight = true;\n } else {\n model.deltaDecorations(model._oldDecorations, []);\n delete model._oldDecorations;\n delete model._oldDecorationsSource;\n model._hasHighlight = false;\n }\n }\n const handleUnhandledPromiseRejection = function () {\n console.debug('handler for unhandled promise rejection');\n };\n const setAllRangesToPrev = function (rangeMap) {\n for (let key in rangeMap) {\n const restriction = rangeMap[key];\n restriction.range = restriction.prevRange;\n }\n };\n const doesChangeHasMultilineConflict = function (restriction, text) {\n return !restriction.allowMultiline && text.includes('\\n');\n };\n const isChangeInvalidAsPerUser = function (restriction, value, range) {\n return restriction.validate && !restriction.validate(value, range, restriction.lastInfo);\n }\n\n const manipulatorApi = {\n _isRestrictedModel: true,\n _isRestrictedValueValid: true,\n _editableRangeChangeListener: [],\n _isCursorAtCheckPoint: isCursorAtCheckPoint,\n _currentCursorPositions: []\n }\n\n prepareRestrictions(restrictions);\n model._hasHighlight = false;\n manipulatorApi._restrictionChangeListener = model.onDidChangeContent(function (contentChangedEvent) {\n const isUndoing = contentChangedEvent.isUndoing;\n model._isRestrictedValueValid = true;\n if (!(isUndoing && model.editInRestrictedArea)) {\n const changes = contentChangedEvent.changes.sort(sortRangesInAscendingOrder);\n const rangeMap = {};\n const length = restrictions.length;\n const isAllChangesValid = changes.every(function (change) {\n const editedRange = change.range;\n const rangeAsString = editedRange.toString();\n rangeMap[rangeAsString] = null;\n for (let i = 0; i < length; i++) {\n const restriction = restrictions[i];\n const range = restriction.range;\n if (range.containsRange(editedRange)) {\n if (doesChangeHasMultilineConflict(restriction, change.text)) {\n return false;\n }\n rangeMap[rangeAsString] = restriction;\n return true;\n }\n }\n return false;\n })\n if (isAllChangesValid) {\n changes.forEach(function (change, changeIndex) {\n const changedRange = change.range;\n const restriction = rangeMap[changedRange.toString()];\n const editableRange = restriction.range;\n const text = change.text || '';\n /**\n * Things to check before implementing the change\n * - A | D | R => Addition | Deletion | Replacement\n * - MC | SC => MultiLineChange | SingleLineChange\n * - SOR | MOR | EOR => Change Occured in - Start Of Range | Middle Of Range | End Of Range\n * - SSL | SML => Editable Range - Spans Single Line | Spans Multiple Line\n */\n const noOfLinesAdded = (text.match(/\\n/g) || []).length;\n const noOfColsAddedAtLastLine = text.split(/\\n/g).pop().length;\n\n const lineDiffInRange = changedRange.endLineNumber - changedRange.startLineNumber;\n const colDiffInRange = changedRange.endColumn - changedRange.startColumn;\n\n let finalLine = editableRange.endLineNumber;\n let finalColumn = editableRange.endColumn;\n\n let columnsCarriedToEnd = 0;\n if (\n (editableRange.endLineNumber === changedRange.startLineNumber) ||\n (editableRange.endLineNumber === changedRange.endLineNumber)\n ) {\n columnsCarriedToEnd += (editableRange.endColumn - changedRange.startColumn) + 1;\n }\n\n const info = getInfoFrom(change, editableRange);\n restriction.lastInfo = info;\n if (info.isAddition || info.isReplacement) {\n if (info.rangeIsSingleLine) {\n /**\n * Only Column Change has occurred , so regardless of the position of the change\n * Addition of noOfCols is enough\n */\n if (noOfLinesAdded === 0) {\n finalColumn += noOfColsAddedAtLastLine;\n } else {\n finalLine += noOfLinesAdded;\n if (info.startColumnOfRange) {\n finalColumn += noOfColsAddedAtLastLine\n } else if (info.endColumnOfRange) {\n finalColumn = (noOfColsAddedAtLastLine + 1)\n } else {\n finalColumn = (noOfColsAddedAtLastLine + columnsCarriedToEnd)\n }\n }\n }\n if (info.rangeIsMultiLine) {\n // Handling for Start Of Range is not required\n finalLine += noOfLinesAdded;\n if (info.endLineOfRange) {\n if (noOfLinesAdded === 0) {\n finalColumn += noOfColsAddedAtLastLine;\n } else {\n finalColumn = (columnsCarriedToEnd + noOfColsAddedAtLastLine);\n }\n }\n }\n }\n if (info.isDeletion || info.isReplacement) {\n if (info.rangeIsSingleLine) {\n finalColumn -= colDiffInRange;\n }\n if (info.rangeIsMultiLine) {\n if (info.endLineOfRange) {\n finalLine -= lineDiffInRange;\n finalColumn -= colDiffInRange;\n } else {\n finalLine -= lineDiffInRange;\n }\n }\n }\n updateRange(restriction, editableRange, finalLine, finalColumn, changes, changeIndex);\n });\n const values = model.getValueInEditableRanges();\n const currentlyEditedRanges = {};\n for (let key in rangeMap) {\n const restriction = rangeMap[key];\n const range = restriction.range;\n const rangeString = restriction.label || range.toString();\n const value = values[rangeString];\n if (isChangeInvalidAsPerUser(restriction, value, range)) {\n setAllRangesToPrev(rangeMap);\n doUndo();\n return; // Breaks the loop and prevents the triggerChangeListener\n }\n currentlyEditedRanges[rangeString] = value;\n }\n if (model._hasHighlight) {\n model._oldDecorationsSource.forEach(function (object) {\n object.range = model.getDecorationRange(object.id);\n });\n }\n triggerChangeListenersWith(currentlyEditedRanges, values);\n } else {\n doUndo();\n }\n } else if (model.editInRestrictedArea) {\n model._isRestrictedValueValid = false;\n }\n });\n window.onerror = handleUnhandledPromiseRejection;\n const exposedApi = {\n editInRestrictedArea: false,\n getCurrentEditableRanges: getCurrentEditableRanges,\n getValueInEditableRanges: getValueInEditableRanges,\n disposeRestrictions: disposeRestrictions,\n onDidChangeContentInEditableRange: addEditableRangeListener,\n updateRestrictions: updateRestrictions,\n updateValueInEditableRanges: updateValueInEditableRanges,\n toggleHighlightOfEditableAreas: toggleHighlightOfEditableAreas\n }\n for (let funcName in manipulatorApi) {\n Object.defineProperty(model, funcName, {\n enumerable: false,\n configurable: true,\n writable: true,\n value: manipulatorApi[funcName]\n })\n }\n for (let apiName in exposedApi) {\n Object.defineProperty(model, apiName, {\n enumerable: false,\n configurable: true,\n writable: true,\n value: exposedApi[apiName]\n })\n }\n return model;\n}\nexport default constrainedModel;","export const deepClone = (function () {\n const byPassPrimitives = function (value, callback) {\n if (typeof value !== 'object' || value === null) {\n return this.freeze ? Object.freeze(value) : value;\n }\n if (value instanceof Date) {\n return this.freeze ? Object.freeze(new Date(value)) : new Date(value);\n }\n return callback.call(this, value);\n }\n const cloneArray = function (array, callback) {\n const keys = Object.keys(array);\n const arrayClone = new Array(keys.length)\n for (let i = 0; i < keys.length; i++) {\n arrayClone[keys[i]] = byPassPrimitives.call(this, array[keys[i]], callback);\n }\n return arrayClone;\n }\n const cloner = function (object) {\n return byPassPrimitives.call(this, object, function (object) {\n if (Array.isArray(object)) {\n return cloneArray.call(this, object, cloner)\n }\n const clone = {};\n for (let key in object) {\n if (!this.withProto && Object.hasOwnProperty.call(object, key) === false) {\n continue;\n }\n clone[key] = byPassPrimitives.call(this, object[key], cloner);\n }\n return clone;\n })\n }\n const config = (function () {\n const constructOptionForCode = function (value) {\n const options = [\n 'withProto',\n 'freeze'\n ]\n this[value] = options.reduce(function (acc, option) {\n if (acc[option] = (value >= this[option])) {\n value -= this[option]\n }\n return acc;\n }.bind(this), {})\n }\n const codes = Object.create(Object.defineProperties({}, {\n withProto: { value: 1 },\n freeze: { value: 2 }\n }));\n for (let i = 0; i <= 3; i++) {\n constructOptionForCode.call(codes, i);\n }\n return codes;\n }());\n const methods = {\n withProto: cloner.bind(config[1]),\n andFreeze: cloner.bind(config[2]),\n withProtoAndFreeze: cloner.bind(config[3])\n }\n const API = cloner.bind(config[0]);\n for (let methodName in methods) {\n Object.defineProperty(API, methodName, {\n enumerable: false,\n writable: false,\n configurable: false,\n value: methods[methodName]\n })\n }\n return API;\n}());\n\nexport default deepClone;","export const TypeMustBe = function (type, key, additional) {\n return 'The value for the ' + key + ' should be of type ' + (Array.isArray(type) ? type.join(' | ') : type) + '. ' + (additional || '')\n}\nconst definedErrors = {\n TypeMustBe : TypeMustBe\n};\nexport default definedErrors;","export const enums = {\n SINGLE_LINE_HIGHLIGHT_CLASS: 'editableArea--single-line',\n MULTI_LINE_HIGHLIGHT_CLASS: 'editableArea--multi-line'\n}\nexport default enums;","const validators = {\n initWith: function (monaco) {\n const dummyDiv = document.createElement('div');\n const dummyEditorInstance = monaco.editor.create(dummyDiv);\n const editorInstanceConstructorName = dummyEditorInstance.constructor.name;\n const editorModelConstructorName = dummyEditorInstance.getModel().constructor.name;\n const instanceCheck = function (valueToValidate) {\n return valueToValidate.constructor.name === editorInstanceConstructorName;\n }\n const modelCheck = function (valueToValidate) {\n return valueToValidate.constructor.name === editorModelConstructorName;\n }\n const rangesCheck = function (ranges) {\n if (Array.isArray(ranges)) {\n return ranges.every(function (rangeObj) {\n if (typeof rangeObj === 'object' && rangeObj.constructor.name === 'Object') {\n if (!rangeObj.hasOwnProperty('range')) return false;\n if (!Array.isArray(rangeObj.range)) return false;\n if (rangeObj.range.length !== 4) return false;\n if (!(rangeObj.range.every(num => num > 0 && parseInt(num) === num))) return false;\n if (rangeObj.hasOwnProperty('allowMultiline')) {\n if (typeof rangeObj.allowMultiline !== 'boolean') return false;\n }\n if (rangeObj.hasOwnProperty('label')) {\n if (typeof rangeObj.label !== 'string') return false;\n }\n if (rangeObj.hasOwnProperty('validate')) {\n if (typeof rangeObj.validate !== 'function') return false;\n }\n return true;\n }\n return false;\n });\n }\n return false;\n }\n return {\n isInstanceValid: instanceCheck,\n isModelValid: modelCheck,\n isRangesValid: rangesCheck\n }\n }\n}\nexport default validators;","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import validators from './utils/validators.js';\nimport { TypeMustBe } from './utils/definedErrors.js';\nimport constrainedModel from './constrainedModel.js';\n\nexport function constrainedEditor(monaco) {\n /**\n * Injected Dependencies\n */\n if (monaco === undefined) {\n throw new Error([\n \"Please pass the monaco global variable into function as\",\n \"(eg:)constrainedEditor({ range : monaco.range });\",\n ].join('\\n'));\n }\n /**\n * \n * @param {Object} editorInstance This should be the monaco editor instance.\n * @description This is the listener function to check whether the cursor is at checkpoints \n * (i.e) the point where editable and non editable portions meet\n */\n const listenerFn = function (editorInstance) {\n const model = editorInstance.getModel();\n if (model._isCursorAtCheckPoint) {\n const selections = editorInstance.getSelections();\n const positions = selections.map(function (selection) {\n return {\n lineNumber: selection.positionLineNumber,\n column: selection.positionColumn\n }\n });\n model._isCursorAtCheckPoint(positions);\n model._currentCursorPositions = selections;\n }\n }\n const _uriRestrictionMap = {};\n const { isInstanceValid, isModelValid, isRangesValid } = validators.initWith(monaco);\n /**\n * \n * @param {Object} editorInstance This should be the monaco editor instance\n * @returns {Boolean}\n */\n const initInEditorInstance = function (editorInstance) {\n if (isInstanceValid(editorInstance)) {\n const domNode = editorInstance.getDomNode();\n manipulator._listener = listenerFn.bind(API, editorInstance);\n manipulator._editorInstance = editorInstance;\n manipulator._editorInstance._isInDevMode = false;\n domNode.addEventListener('keydown', manipulator._listener, true);\n editorInstance.onDidChangeModel(function () {\n // domNode - refers old dom node\n domNode.removeEventListener('keydown', manipulator._listener, true)\n const newDomNode = editorInstance.getDomNode(); // Gets Current dom node\n newDomNode.addEventListener('keydown', manipulator._listener, true);\n domNode = newDomNode;\n })\n return true;\n } else {\n throw new Error(\n TypeMustBe(\n 'ICodeEditor',\n 'editorInstance',\n 'This type interface can be found in monaco editor documentation'\n )\n )\n }\n }\n /**\n * \n * @param {Object} model This should be the monaco editor model instance. Refer https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.itextmodel.html\n * @param {*} ranges This should be the array of range objects. Refer constrained editor plugin documentation\n * @returns model\n */\n const addRestrictionsTo = function (model, ranges) {\n if (isModelValid(model)) {\n if (isRangesValid(ranges)) {\n const modelToConstrain = constrainedModel(model, ranges, monaco, manipulator._editorInstance);\n _uriRestrictionMap[modelToConstrain.uri.toString()] = modelToConstrain;\n return modelToConstrain;\n } else {\n throw new Error(\n TypeMustBe(\n 'Array',\n 'ranges',\n 'Please refer constrained editor documentation for proper structure'\n )\n )\n }\n } else {\n throw new Error(\n TypeMustBe(\n 'ICodeEditor',\n 'editorInstance',\n 'This type interface can be found in monaco editor documentation'\n )\n )\n }\n }\n /**\n * \n * @param {Object} model This should be the monaco editor model instance. Refer https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.itextmodel.html\n * @returns {Boolean} True if the restrictions are removed\n */\n const removeRestrictionsIn = function (model) {\n if (isModelValid(model)) {\n const uri = model.uri.toString();\n const restrictedModel = _uriRestrictionMap[uri];\n if (restrictedModel) {\n return restrictedModel.disposeRestrictions();\n } else {\n console.warn('Current Model is not a restricted Model');\n return false;\n }\n } else {\n throw new Error(\n TypeMustBe(\n 'ICodeEditor',\n 'editorInstance',\n 'This type interface can be found in monaco editor documentation'\n )\n )\n }\n }\n /**\n * \n * @returns {Boolean} True if the constrainer is disposed\n */\n const disposeConstrainer = function () {\n if (manipulator._editorInstance) {\n const instance = manipulator._editorInstance;\n const domNode = instance.getDomNode();\n domNode.removeEventListener('keydown', manipulator._listener);\n delete manipulator._listener;\n delete manipulator._editorInstance._isInDevMode;\n delete manipulator._editorInstance._devModeAction;\n delete manipulator._editorInstance;\n for (let key in _uriRestrictionMap) {\n delete _uriRestrictionMap[key];\n }\n return true;\n }\n return false;\n }\n /**\n * @description This function used to make the developer to find the ranges of selected portions\n */\n const toggleDevMode = function () {\n if (manipulator._editorInstance._isInDevMode) {\n manipulator._editorInstance._isInDevMode = false;\n manipulator._editorInstance._devModeAction.dispose();\n delete manipulator._editorInstance._devModeAction;\n } else {\n manipulator._editorInstance._isInDevMode = true;\n manipulator._editorInstance._devModeAction = manipulator._editorInstance.addAction({\n id: 'showRange',\n label: 'Show Range in console',\n contextMenuGroupId: 'navigation',\n contextMenuOrder: 1.5,\n run: function (editor) {\n const selections = editor.getSelections();\n const ranges = selections.reduce(function (acc, { startLineNumber, endLineNumber, startColumn, endColumn }) {\n acc.push('range : ' + JSON.stringify([\n startLineNumber,\n startColumn,\n endLineNumber,\n endColumn\n ]));\n return acc;\n }, []).join('\\n');\n console.log(`Selected Ranges : \\n` + JSON.stringify(ranges, null, 2));\n }\n });\n }\n }\n\n /**\n * Main Function starts here\n */\n // @internal\n const manipulator = {\n /**\n * These variables should not be modified by external code\n * This has to be used for debugging and testing \n */\n _listener: null,\n _editorInstance: null,\n _uriRestrictionMap: _uriRestrictionMap,\n _injectedResources: monaco\n }\n const API = Object.create(manipulator);\n const exposedMethods = {\n /**\n * These functions are exposed to the user\n * These functions should be protected from editing\n */\n initializeIn: initInEditorInstance,\n addRestrictionsTo: addRestrictionsTo,\n removeRestrictionsIn: removeRestrictionsIn,\n disposeConstrainer: disposeConstrainer,\n toggleDevMode: toggleDevMode\n }\n for (let methodName in exposedMethods) {\n Object.defineProperty(API, methodName, {\n enumerable: false,\n writable: false,\n configurable: false,\n value: exposedMethods[methodName]\n })\n }\n return Object.freeze(API);\n}\n\nexport default constrainedEditor;"],"sourceRoot":""} \ No newline at end of file diff --git a/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.min.js b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.min.js new file mode 100644 index 0000000..51d0b6c --- /dev/null +++ b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.min.js @@ -0,0 +1,2 @@ +(()=>{"use strict";var e={d:(n,t)=>{for(var r in t)e.o(t,r)&&!e.o(n,r)&&Object.defineProperty(n,r,{enumerable:!0,get:t[r]})},o:(e,n)=>Object.prototype.hasOwnProperty.call(e,n)},n={};e.d(n,{default:()=>s});const t=function(e){const n=document.createElement("div"),t=e.editor.create(n),r=t.constructor.name,o=t.getModel().constructor.name;return{isInstanceValid:function(e){return e.constructor.name===r},isModelValid:function(e){return e.constructor.name===o},isRangesValid:function(e){return!!Array.isArray(e)&&e.every((function(e){return!("object"!=typeof e||"Object"!==e.constructor.name||!e.hasOwnProperty("range")||!Array.isArray(e.range)||4!==e.range.length||!e.range.every((e=>e>0&&parseInt(e)===e))||e.hasOwnProperty("allowMultiline")&&"boolean"!=typeof e.allowMultiline||e.hasOwnProperty("label")&&"string"!=typeof e.label||e.hasOwnProperty("validate")&&"function"!=typeof e.validate)}))}}},r=function(e,n,t){return"The value for the "+n+" should be of type "+(Array.isArray(e)?e.join(" | "):e)+". "+(t||"")},o=function(){const e=function(e,n){return"object"!=typeof e||null===e?this.freeze?Object.freeze(e):e:e instanceof Date?this.freeze?Object.freeze(new Date(e)):new Date(e):n.call(this,e)},n=function(n,t){const r=Object.keys(n),o=new Array(r.length);for(let i=0;i=this[t])&&(e-=this[t]),n}.bind(this),{})},n=Object.create(Object.defineProperties({},{withProto:{value:1},freeze:{value:2}}));for(let t=0;t<=3;t++)e.call(n,t);return n}(),o={withProto:t.bind(r[1]),andFreeze:t.bind(r[2]),withProtoAndFreeze:t.bind(r[3])},i=t.bind(r[0]);for(let e in o)Object.defineProperty(i,e,{enumerable:!1,writable:!1,configurable:!1,value:o[e]});return i}(),i="editableArea--single-line",a="editableArea--multi-line",s=function(e){if(void 0===e)throw new Error(["Please pass the monaco global variable into function as","(eg:)constrainedEditor({ range : monaco.range });"].join("\n"));const n=function(e){const n=e.getModel();if(n._isCursorAtCheckPoint){const t=e.getSelections(),r=t.map((function(e){return{lineNumber:e.positionLineNumber,column:e.positionColumn}}));n._isCursorAtCheckPoint(r),n._currentCursorPositions=t}},s={},{isInstanceValid:l,isModelValid:c,isRangesValid:u}=t(e),d={_listener:null,_editorInstance:null,_uriRestrictionMap:s,_injectedResources:e},g=Object.create(d),f={initializeIn:function(e){if(l(e)){const t=e.getDomNode();return d._listener=n.bind(g,e),d._editorInstance=e,d._editorInstance._isInDevMode=!1,t.addEventListener("keydown",d._listener,!0),e.onDidChangeModel((function(){t.removeEventListener("keydown",d._listener,!0);const n=e.getDomNode();n.addEventListener("keydown",d._listener,!0),t=n})),!0}throw new Error(r("ICodeEditor","editorInstance","This type interface can be found in monaco editor documentation"))},addRestrictionsTo:function(n,t){if(c(n)){if(u(t)){const r=function(e,n,t){const r=t.Range,s=function(e,n){const t=e.range,r=n.range;if(t[0]r)throw new Error("Provided Start Line("+e+") is out of bounds. Max Lines in content is "+r);o[n]=e;break;case 1:{let r=e;const i=o[0],a=t[i-1].length;if(r<0){if(r=a-Math.abs(r),r<0)throw new Error("Provided Start Column("+e+") is out of bounds. Max Column in line "+i+" is "+a)}else if(r>a+1)throw new Error("Provided Start Column("+e+") is out of bounds. Max Column in line "+i+" is "+a);o[n]=r}break;case 2:{let t=e;if(t<0){if(t=r-Math.abs(e),t<0)throw new Error("Provided End Line("+e+") is out of bounds. Max Lines in content is "+r);tr)throw new Error("Provided End Line("+e+") is out of bounds. Max Lines in content is "+r);o[n]=t}break;case 3:{let r=e;const i=o[2],a=t[i-1].length;if(r<0){if(r=a-Math.abs(r),r<0)throw new Error("Provided End Column("+e+") is out of bounds. Max Column in line "+i+" is "+a)}else if(r>a+1)throw new Error("Provided Start Column("+e+") is out of bounds. Max Column in line "+i+" is "+a);o[n]=r}}})),o}(e.range,t),i=o[0],a=o[1],s=o[2],l=o[3];e._originalRange=o.slice(),e.range=new r(i,a,s,l),e.index=n,e.allowMultiline||(e.allowMultiline=r.spansMultipleLines(e.range)),e.label||(e.label=`[${i},${a} -> ${s}${l}]`)}))},u=function(){return l.reduce((function(e,n){return e[n.label]={allowMultiline:n.allowMultiline||!1,index:n.index,range:Object.assign({},n.range),originalRange:n._originalRange.slice()},e}),{})},d=function(){return Promise.resolve().then((function(){e.editInRestrictedArea=!0,e.undo(),e.editInRestrictedArea=!1,e._hasHighlight&&e._oldDecorationsSource&&(e.deltaDecorations(e._oldDecorations,e._oldDecorationsSource),e._oldDecorationsSource.forEach((function(n){n.range=e.getDecorationRange(n.id)})))}))},g=function(n,t,r,o,i,a){let s=t.endLineNumber,c=t.endColumn;n.prevRange=t,n.range=t.setEndPosition(r,o);const u=l.length;let d=i.length;const g=o-c,f=r-s,b=e._currentCursorPositions||[],h=b.length;if(d!==h&&(i=i.filter((function(e){const n=e.range;for(let e=0;es)break;t.startColumn+=g,t.endColumn+=g,n.range=t}for(let e=a+1;es){rangeMap[t.toString()]=o;break}t.startColumn+=g,t.endColumn+=g,n.range=t,rangeMap[t.toString()]=o}}},f=function(){console.debug("handler for unhandled promise rejection")},b=function(e){for(let n in e){const t=e[n];t.range=t.prevRange}},h=function(e,n){return!e.allowMultiline&&n.includes("\n")},m=function(e,n,t){return e.validate&&!e.validate(n,t,e.lastInfo)},p={_isRestrictedModel:!0,_isRestrictedValueValid:!0,_editableRangeChangeListener:[],_isCursorAtCheckPoint:function(n){n.some((function(n){const t=n.lineNumber,r=n.column,o=l.length;for(let n=0;n","ranges","Please refer constrained editor documentation for proper structure"))}throw new Error(r("ICodeEditor","editorInstance","This type interface can be found in monaco editor documentation"))},removeRestrictionsIn:function(e){if(c(e)){const n=e.uri.toString(),t=s[n];return t?t.disposeRestrictions():(console.warn("Current Model is not a restricted Model"),!1)}throw new Error(r("ICodeEditor","editorInstance","This type interface can be found in monaco editor documentation"))},disposeConstrainer:function(){if(d._editorInstance){d._editorInstance.getDomNode().removeEventListener("keydown",d._listener),delete d._listener,delete d._editorInstance._isInDevMode,delete d._editorInstance._devModeAction,delete d._editorInstance;for(let e in s)delete s[e];return!0}return!1},toggleDevMode:function(){d._editorInstance._isInDevMode?(d._editorInstance._isInDevMode=!1,d._editorInstance._devModeAction.dispose(),delete d._editorInstance._devModeAction):(d._editorInstance._isInDevMode=!0,d._editorInstance._devModeAction=d._editorInstance.addAction({id:"showRange",label:"Show Range in console",contextMenuGroupId:"navigation",contextMenuOrder:1.5,run:function(e){const n=e.getSelections().reduce((function(e,{startLineNumber:n,endLineNumber:t,startColumn:r,endColumn:o}){return e.push("range : "+JSON.stringify([n,r,t,o])),e}),[]).join("\n");console.log("Selected Ranges : \n"+JSON.stringify(n,null,2))}}))}};for(let e in f)Object.defineProperty(g,e,{enumerable:!1,writable:!1,configurable:!1,value:f[e]});return Object.freeze(g)};window.constrainedEditor=n.default})(); +//# sourceMappingURL=constrainedEditorPlugin.min.js.map \ No newline at end of file diff --git a/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.min.js.map b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.min.js.map new file mode 100644 index 0000000..ec61846 --- /dev/null +++ b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/constrainedEditorPlugin.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack://constrainedEditor/webpack/bootstrap","webpack://constrainedEditor/webpack/runtime/define property getters","webpack://constrainedEditor/webpack/runtime/hasOwnProperty shorthand","webpack://constrainedEditor/./src/utils/validators.js","webpack://constrainedEditor/./src/utils/definedErrors.js","webpack://constrainedEditor/./src/utils/deepClone.js","webpack://constrainedEditor/./src/utils/enums.js","webpack://constrainedEditor/./src/constrainedEditor.js","webpack://constrainedEditor/./src/constrainedModel.js"],"names":["__webpack_require__","exports","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","monaco","dummyDiv","document","createElement","dummyEditorInstance","editor","create","editorInstanceConstructorName","constructor","name","editorModelConstructorName","getModel","isInstanceValid","valueToValidate","isModelValid","isRangesValid","ranges","Array","isArray","every","rangeObj","range","length","num","parseInt","allowMultiline","label","validate","TypeMustBe","type","additional","join","byPassPrimitives","value","callback","this","freeze","Date","cloneArray","array","keys","arrayClone","i","cloner","object","clone","withProto","config","constructOptionForCode","reduce","acc","option","bind","codes","defineProperties","methods","andFreeze","withProtoAndFreeze","API","methodName","writable","configurable","undefined","Error","listenerFn","editorInstance","model","_isCursorAtCheckPoint","selections","getSelections","positions","map","selection","lineNumber","positionLineNumber","column","positionColumn","_currentCursorPositions","_uriRestrictionMap","manipulator","_listener","_editorInstance","_injectedResources","exposedMethods","initializeIn","domNode","getDomNode","_isInDevMode","addEventListener","onDidChangeModel","removeEventListener","newDomNode","addRestrictionsTo","modelToConstrain","rangeConstructor","Range","sortRangesInAscendingOrder","rangeObject1","rangeObject2","rangeA","rangeB","restrictions","sort","prepareRestrictions","content","getValue","forEach","restriction","index","lines","split","noOfLines","normalizedRange","actualStartCol","startLineNo","maxCols","Math","abs","actualEndLine","console","warn","actualEndCol","endLineNo","normalizeRange","startLine","startCol","endLine","endCol","_originalRange","slice","spansMultipleLines","getCurrentEditableRanges","assign","originalRange","doUndo","Promise","resolve","then","editInRestrictedArea","undo","_hasHighlight","_oldDecorationsSource","deltaDecorations","_oldDecorations","getDecorationRange","id","updateRange","finalLine","finalColumn","changes","changeIndex","oldRangeEndLineNumber","endLineNumber","oldRangeEndColumn","endColumn","prevRange","setEndPosition","changesLength","diffInCol","diffInRow","cursorPositions","noOfCursorPositions","filter","change","cursorPosition","startLineNumber","startColumn","nextRestriction","nextRange","nextChange","rangeInChange","rangeAsString","toString","rangeMapValue","rangeMap","handleUnhandledPromiseRejection","debug","setAllRangesToPrev","doesChangeHasMultilineConflict","text","includes","isChangeInvalidAsPerUser","lastInfo","manipulatorApi","_isRestrictedModel","_isRestrictedValueValid","_editableRangeChangeListener","some","position","posLineNumber","posCol","pushStackElement","_restrictionChangeListener","onDidChangeContent","contentChangedEvent","isUndoing","editedRange","containsRange","changedRange","editableRange","noOfLinesAdded","match","noOfColsAddedAtLastLine","pop","lineDiffInRange","colDiffInRange","columnsCarriedToEnd","info","isDeletion","isAddition","isReplacement","startLineOfRange","startColumnOfRange","endLineOfRange","endColumnOfRange","middleLineOfRange","rangeIsSingleLine","rangeIsMultiLine","getInfoFrom","values","getValueInEditableRanges","currentlyEditedRanges","rangeString","currentChanges","allChanges","currentRanges","triggerChangeListenersWith","window","onerror","exposedApi","getValueInRange","disposeRestrictions","dispose","updateValueInEditableRanges","updateRestrictions","toggleHighlightOfEditableAreas","onDidChangeContentInEditableRange","push","forceMoveMarkers","restrictionsMap","newRange","applyEdits","error","decorations","decoration","options","className","hoverMessage","funcName","apiName","uri","removeRestrictionsIn","restrictedModel","disposeConstrainer","_devModeAction","toggleDevMode","addAction","contextMenuGroupId","contextMenuOrder","run","JSON","stringify","log"],"mappings":"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","file":"constrainedEditorPlugin.min.js","sourcesContent":["// The require scope\nvar __webpack_require__ = {};\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","const validators = {\n initWith: function (monaco) {\n const dummyDiv = document.createElement('div');\n const dummyEditorInstance = monaco.editor.create(dummyDiv);\n const editorInstanceConstructorName = dummyEditorInstance.constructor.name;\n const editorModelConstructorName = dummyEditorInstance.getModel().constructor.name;\n const instanceCheck = function (valueToValidate) {\n return valueToValidate.constructor.name === editorInstanceConstructorName;\n }\n const modelCheck = function (valueToValidate) {\n return valueToValidate.constructor.name === editorModelConstructorName;\n }\n const rangesCheck = function (ranges) {\n if (Array.isArray(ranges)) {\n return ranges.every(function (rangeObj) {\n if (typeof rangeObj === 'object' && rangeObj.constructor.name === 'Object') {\n if (!rangeObj.hasOwnProperty('range')) return false;\n if (!Array.isArray(rangeObj.range)) return false;\n if (rangeObj.range.length !== 4) return false;\n if (!(rangeObj.range.every(num => num > 0 && parseInt(num) === num))) return false;\n if (rangeObj.hasOwnProperty('allowMultiline')) {\n if (typeof rangeObj.allowMultiline !== 'boolean') return false;\n }\n if (rangeObj.hasOwnProperty('label')) {\n if (typeof rangeObj.label !== 'string') return false;\n }\n if (rangeObj.hasOwnProperty('validate')) {\n if (typeof rangeObj.validate !== 'function') return false;\n }\n return true;\n }\n return false;\n });\n }\n return false;\n }\n return {\n isInstanceValid: instanceCheck,\n isModelValid: modelCheck,\n isRangesValid: rangesCheck\n }\n }\n}\nexport default validators;","export const TypeMustBe = function (type, key, additional) {\n return 'The value for the ' + key + ' should be of type ' + (Array.isArray(type) ? type.join(' | ') : type) + '. ' + (additional || '')\n}\nconst definedErrors = {\n TypeMustBe : TypeMustBe\n};\nexport default definedErrors;","export const deepClone = (function () {\n const byPassPrimitives = function (value, callback) {\n if (typeof value !== 'object' || value === null) {\n return this.freeze ? Object.freeze(value) : value;\n }\n if (value instanceof Date) {\n return this.freeze ? Object.freeze(new Date(value)) : new Date(value);\n }\n return callback.call(this, value);\n }\n const cloneArray = function (array, callback) {\n const keys = Object.keys(array);\n const arrayClone = new Array(keys.length)\n for (let i = 0; i < keys.length; i++) {\n arrayClone[keys[i]] = byPassPrimitives.call(this, array[keys[i]], callback);\n }\n return arrayClone;\n }\n const cloner = function (object) {\n return byPassPrimitives.call(this, object, function (object) {\n if (Array.isArray(object)) {\n return cloneArray.call(this, object, cloner)\n }\n const clone = {};\n for (let key in object) {\n if (!this.withProto && Object.hasOwnProperty.call(object, key) === false) {\n continue;\n }\n clone[key] = byPassPrimitives.call(this, object[key], cloner);\n }\n return clone;\n })\n }\n const config = (function () {\n const constructOptionForCode = function (value) {\n const options = [\n 'withProto',\n 'freeze'\n ]\n this[value] = options.reduce(function (acc, option) {\n if (acc[option] = (value >= this[option])) {\n value -= this[option]\n }\n return acc;\n }.bind(this), {})\n }\n const codes = Object.create(Object.defineProperties({}, {\n withProto: { value: 1 },\n freeze: { value: 2 }\n }));\n for (let i = 0; i <= 3; i++) {\n constructOptionForCode.call(codes, i);\n }\n return codes;\n }());\n const methods = {\n withProto: cloner.bind(config[1]),\n andFreeze: cloner.bind(config[2]),\n withProtoAndFreeze: cloner.bind(config[3])\n }\n const API = cloner.bind(config[0]);\n for (let methodName in methods) {\n Object.defineProperty(API, methodName, {\n enumerable: false,\n writable: false,\n configurable: false,\n value: methods[methodName]\n })\n }\n return API;\n}());\n\nexport default deepClone;","export const enums = {\n SINGLE_LINE_HIGHLIGHT_CLASS: 'editableArea--single-line',\n MULTI_LINE_HIGHLIGHT_CLASS: 'editableArea--multi-line'\n}\nexport default enums;","import validators from './utils/validators.js';\nimport { TypeMustBe } from './utils/definedErrors.js';\nimport constrainedModel from './constrainedModel.js';\n\nexport function constrainedEditor(monaco) {\n /**\n * Injected Dependencies\n */\n if (monaco === undefined) {\n throw new Error([\n \"Please pass the monaco global variable into function as\",\n \"(eg:)constrainedEditor({ range : monaco.range });\",\n ].join('\\n'));\n }\n /**\n * \n * @param {Object} editorInstance This should be the monaco editor instance.\n * @description This is the listener function to check whether the cursor is at checkpoints \n * (i.e) the point where editable and non editable portions meet\n */\n const listenerFn = function (editorInstance) {\n const model = editorInstance.getModel();\n if (model._isCursorAtCheckPoint) {\n const selections = editorInstance.getSelections();\n const positions = selections.map(function (selection) {\n return {\n lineNumber: selection.positionLineNumber,\n column: selection.positionColumn\n }\n });\n model._isCursorAtCheckPoint(positions);\n model._currentCursorPositions = selections;\n }\n }\n const _uriRestrictionMap = {};\n const { isInstanceValid, isModelValid, isRangesValid } = validators.initWith(monaco);\n /**\n * \n * @param {Object} editorInstance This should be the monaco editor instance\n * @returns {Boolean}\n */\n const initInEditorInstance = function (editorInstance) {\n if (isInstanceValid(editorInstance)) {\n const domNode = editorInstance.getDomNode();\n manipulator._listener = listenerFn.bind(API, editorInstance);\n manipulator._editorInstance = editorInstance;\n manipulator._editorInstance._isInDevMode = false;\n domNode.addEventListener('keydown', manipulator._listener, true);\n editorInstance.onDidChangeModel(function () {\n // domNode - refers old dom node\n domNode.removeEventListener('keydown', manipulator._listener, true)\n const newDomNode = editorInstance.getDomNode(); // Gets Current dom node\n newDomNode.addEventListener('keydown', manipulator._listener, true);\n domNode = newDomNode;\n })\n return true;\n } else {\n throw new Error(\n TypeMustBe(\n 'ICodeEditor',\n 'editorInstance',\n 'This type interface can be found in monaco editor documentation'\n )\n )\n }\n }\n /**\n * \n * @param {Object} model This should be the monaco editor model instance. Refer https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.itextmodel.html\n * @param {*} ranges This should be the array of range objects. Refer constrained editor plugin documentation\n * @returns model\n */\n const addRestrictionsTo = function (model, ranges) {\n if (isModelValid(model)) {\n if (isRangesValid(ranges)) {\n const modelToConstrain = constrainedModel(model, ranges, monaco, manipulator._editorInstance);\n _uriRestrictionMap[modelToConstrain.uri.toString()] = modelToConstrain;\n return modelToConstrain;\n } else {\n throw new Error(\n TypeMustBe(\n 'Array',\n 'ranges',\n 'Please refer constrained editor documentation for proper structure'\n )\n )\n }\n } else {\n throw new Error(\n TypeMustBe(\n 'ICodeEditor',\n 'editorInstance',\n 'This type interface can be found in monaco editor documentation'\n )\n )\n }\n }\n /**\n * \n * @param {Object} model This should be the monaco editor model instance. Refer https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.itextmodel.html\n * @returns {Boolean} True if the restrictions are removed\n */\n const removeRestrictionsIn = function (model) {\n if (isModelValid(model)) {\n const uri = model.uri.toString();\n const restrictedModel = _uriRestrictionMap[uri];\n if (restrictedModel) {\n return restrictedModel.disposeRestrictions();\n } else {\n console.warn('Current Model is not a restricted Model');\n return false;\n }\n } else {\n throw new Error(\n TypeMustBe(\n 'ICodeEditor',\n 'editorInstance',\n 'This type interface can be found in monaco editor documentation'\n )\n )\n }\n }\n /**\n * \n * @returns {Boolean} True if the constrainer is disposed\n */\n const disposeConstrainer = function () {\n if (manipulator._editorInstance) {\n const instance = manipulator._editorInstance;\n const domNode = instance.getDomNode();\n domNode.removeEventListener('keydown', manipulator._listener);\n delete manipulator._listener;\n delete manipulator._editorInstance._isInDevMode;\n delete manipulator._editorInstance._devModeAction;\n delete manipulator._editorInstance;\n for (let key in _uriRestrictionMap) {\n delete _uriRestrictionMap[key];\n }\n return true;\n }\n return false;\n }\n /**\n * @description This function used to make the developer to find the ranges of selected portions\n */\n const toggleDevMode = function () {\n if (manipulator._editorInstance._isInDevMode) {\n manipulator._editorInstance._isInDevMode = false;\n manipulator._editorInstance._devModeAction.dispose();\n delete manipulator._editorInstance._devModeAction;\n } else {\n manipulator._editorInstance._isInDevMode = true;\n manipulator._editorInstance._devModeAction = manipulator._editorInstance.addAction({\n id: 'showRange',\n label: 'Show Range in console',\n contextMenuGroupId: 'navigation',\n contextMenuOrder: 1.5,\n run: function (editor) {\n const selections = editor.getSelections();\n const ranges = selections.reduce(function (acc, { startLineNumber, endLineNumber, startColumn, endColumn }) {\n acc.push('range : ' + JSON.stringify([\n startLineNumber,\n startColumn,\n endLineNumber,\n endColumn\n ]));\n return acc;\n }, []).join('\\n');\n console.log(`Selected Ranges : \\n` + JSON.stringify(ranges, null, 2));\n }\n });\n }\n }\n\n /**\n * Main Function starts here\n */\n // @internal\n const manipulator = {\n /**\n * These variables should not be modified by external code\n * This has to be used for debugging and testing \n */\n _listener: null,\n _editorInstance: null,\n _uriRestrictionMap: _uriRestrictionMap,\n _injectedResources: monaco\n }\n const API = Object.create(manipulator);\n const exposedMethods = {\n /**\n * These functions are exposed to the user\n * These functions should be protected from editing\n */\n initializeIn: initInEditorInstance,\n addRestrictionsTo: addRestrictionsTo,\n removeRestrictionsIn: removeRestrictionsIn,\n disposeConstrainer: disposeConstrainer,\n toggleDevMode: toggleDevMode\n }\n for (let methodName in exposedMethods) {\n Object.defineProperty(API, methodName, {\n enumerable: false,\n writable: false,\n configurable: false,\n value: exposedMethods[methodName]\n })\n }\n return Object.freeze(API);\n}\n\nexport default constrainedEditor;","import deepClone from './utils/deepClone.js';\nimport enums from './utils/enums.js';\nexport const constrainedModel = function (model, ranges, monaco) {\n const rangeConstructor = monaco.Range;\n const sortRangesInAscendingOrder = function (rangeObject1, rangeObject2) {\n const rangeA = rangeObject1.range;\n const rangeB = rangeObject2.range;\n if (\n rangeA[0] < rangeB[0] ||\n (rangeA[0] === rangeB[0] && rangeA[3] < rangeB[1])\n ) {\n return -1;\n }\n }\n const normalizeRange = function (range, content) {\n const lines = content.split('\\n');\n const noOfLines = lines.length;\n const normalizedRange = [];\n range.forEach(function (value, index) {\n if (value === 0) {\n throw new Error('Range values cannot be zero');//No I18n\n }\n switch (index) {\n case 0: {\n if (value < 0) {\n throw new Error('Start Line of Range cannot be negative');//No I18n\n } else if (value > noOfLines) {\n throw new Error('Provided Start Line(' + value + ') is out of bounds. Max Lines in content is ' + noOfLines);//No I18n\n }\n normalizedRange[index] = value;\n }\n break;\n case 1: {\n let actualStartCol = value;\n const startLineNo = normalizedRange[0];\n const maxCols = lines[startLineNo - 1].length\n if (actualStartCol < 0) {\n actualStartCol = maxCols - Math.abs(actualStartCol);\n if (actualStartCol < 0) {\n throw new Error('Provided Start Column(' + value + ') is out of bounds. Max Column in line ' + startLineNo + ' is ' + maxCols);//No I18n\n }\n } else if (actualStartCol > (maxCols + 1)) {\n throw new Error('Provided Start Column(' + value + ') is out of bounds. Max Column in line ' + startLineNo + ' is ' + maxCols);//No I18n\n }\n normalizedRange[index] = actualStartCol;\n }\n break;\n case 2: {\n let actualEndLine = value;\n if (actualEndLine < 0) {\n actualEndLine = noOfLines - Math.abs(value);\n if (actualEndLine < 0) {\n throw new Error('Provided End Line(' + value + ') is out of bounds. Max Lines in content is ' + noOfLines);//No I18n\n }\n if (actualEndLine < normalizedRange[0]) {\n console.warn('Provided End Line(' + value + ') is less than the start Line, the Restriction may not behave as expected');//No I18n\n }\n } else if (value > noOfLines) {\n throw new Error('Provided End Line(' + value + ') is out of bounds. Max Lines in content is ' + noOfLines);//No I18n\n }\n normalizedRange[index] = actualEndLine;\n }\n break;\n case 3: {\n let actualEndCol = value;\n const endLineNo = normalizedRange[2];\n const maxCols = lines[endLineNo - 1].length\n if (actualEndCol < 0) {\n actualEndCol = maxCols - Math.abs(actualEndCol);\n if (actualEndCol < 0) {\n throw new Error('Provided End Column(' + value + ') is out of bounds. Max Column in line ' + endLineNo + ' is ' + maxCols);//No I18n\n }\n } else if (actualEndCol > (maxCols + 1)) {\n throw new Error('Provided Start Column(' + value + ') is out of bounds. Max Column in line ' + endLineNo + ' is ' + maxCols);//No I18n\n }\n normalizedRange[index] = actualEndCol;\n }\n break;\n }\n })\n return normalizedRange;\n }\n let restrictions = deepClone(ranges).sort(sortRangesInAscendingOrder);\n const prepareRestrictions = function (restrictions) {\n const content = model.getValue();\n restrictions.forEach(function (restriction, index) {\n const range = normalizeRange(restriction.range, content);\n const startLine = range[0];\n const startCol = range[1];\n const endLine = range[2];\n const endCol = range[3];\n restriction._originalRange = range.slice();\n restriction.range = new rangeConstructor(startLine, startCol, endLine, endCol);\n restriction.index = index;\n if (!restriction.allowMultiline) {\n restriction.allowMultiline = rangeConstructor.spansMultipleLines(restriction.range)\n }\n if (!restriction.label) {\n restriction.label = `[${startLine},${startCol} -> ${endLine}${endCol}]`;\n }\n });\n }\n const getCurrentEditableRanges = function () {\n return restrictions.reduce(function (acc, restriction) {\n acc[restriction.label] = {\n allowMultiline: restriction.allowMultiline || false,\n index: restriction.index,\n range: Object.assign({}, restriction.range),\n originalRange: restriction._originalRange.slice()\n };\n return acc;\n }, {});\n }\n const getValueInEditableRanges = function () {\n return restrictions.reduce(function (acc, restriction) {\n acc[restriction.label] = model.getValueInRange(restriction.range);\n return acc;\n }, {});\n }\n const updateValueInEditableRanges = function (object, forceMoveMarkers) {\n if (typeof object === 'object' && !Array.isArray(object)) {\n forceMoveMarkers = typeof forceMoveMarkers === 'boolean' ? forceMoveMarkers : false;\n const restrictionsMap = restrictions.reduce(function (acc, restriction) {\n if (restriction.label) {\n acc[restriction.label] = restriction;\n }\n return acc;\n }, {});\n for (let label in object) {\n const restriction = restrictionsMap[label];\n if (restriction) {\n const value = object[label];\n if (doesChangeHasMultilineConflict(restriction, value)) {\n throw new Error('Multiline change is not allowed for ' + label);\n }\n const newRange = deepClone(restriction.range);\n newRange.endLine = newRange.startLine + value.split('\\n').length - 1;\n newRange.endColumn = value.split('\\n').pop().length;\n if (isChangeInvalidAsPerUser(restriction, value, newRange)) {\n throw new Error('Change is invalidated by validate function of ' + label);\n }\n model.applyEdits([{\n forceMoveMarkers: !!forceMoveMarkers,\n range: restriction.range,\n text: value\n }]);\n } else {\n console.error('No restriction found for ' + label);\n }\n }\n } else {\n throw new Error('Value must be an object');//No I18n\n }\n }\n const disposeRestrictions = function () {\n model._restrictionChangeListener.dispose();\n window.removeEventListener(\"error\", handleUnhandledPromiseRejection);\n delete model.editInRestrictedArea;\n delete model.disposeRestrictions;\n delete model.getValueInEditableRanges;\n delete model.updateValueInEditableRanges;\n delete model.updateRestrictions;\n delete model.getCurrentEditableRanges;\n delete model.toggleHighlightOfEditableAreas;\n delete model._hasHighlight;\n delete model._isRestrictedModel;\n delete model._isCursorAtCheckPoint;\n delete model._currentCursorPositions;\n delete model._editableRangeChangeListener;\n delete model._restrictionChangeListener;\n delete model._oldDecorations;\n delete model._oldDecorationsSource;\n return model;\n }\n const isCursorAtCheckPoint = function (positions) {\n positions.some(function (position) {\n const posLineNumber = position.lineNumber;\n const posCol = position.column;\n const length = restrictions.length;\n for (let i = 0; i < length; i++) {\n const range = restrictions[i].range;\n if (\n (range.startLineNumber === posLineNumber && range.startColumn === posCol) ||\n (range.endLineNumber === posLineNumber && range.endColumn === posCol)\n ) {\n model.pushStackElement();\n return true;\n }\n }\n });\n };\n const addEditableRangeListener = function (callback) {\n if (typeof callback === 'function') {\n model._editableRangeChangeListener.push(callback);\n }\n };\n const triggerChangeListenersWith = function (currentChanges, allChanges) {\n const currentRanges = getCurrentEditableRanges();\n model._editableRangeChangeListener.forEach(function (callback) {\n callback.call(model, currentChanges, allChanges, currentRanges);\n });\n };\n const doUndo = function () {\n return Promise.resolve().then(function () {\n model.editInRestrictedArea = true;\n model.undo();\n model.editInRestrictedArea = false;\n if (model._hasHighlight && model._oldDecorationsSource) {\n // id present in the decorations info will be omitted by monaco\n // So we don't need to remove the old decorations id\n model.deltaDecorations(model._oldDecorations, model._oldDecorationsSource);\n model._oldDecorationsSource.forEach(function (object) {\n object.range = model.getDecorationRange(object.id);\n });\n }\n });\n };\n const updateRange = function (restriction, range, finalLine, finalColumn, changes, changeIndex) {\n let oldRangeEndLineNumber = range.endLineNumber;\n let oldRangeEndColumn = range.endColumn;\n restriction.prevRange = range;\n restriction.range = range.setEndPosition(finalLine, finalColumn);\n const length = restrictions.length;\n let changesLength = changes.length;\n const diffInCol = finalColumn - oldRangeEndColumn;\n const diffInRow = finalLine - oldRangeEndLineNumber;\n\n const cursorPositions = model._currentCursorPositions || [];\n const noOfCursorPositions = cursorPositions.length;\n // if (noOfCursorPositions > 0) {\n if (changesLength !== noOfCursorPositions) {\n changes = changes.filter(function (change) {\n const range = change.range;\n for (let i = 0; i < noOfCursorPositions; i++) {\n const cursorPosition = cursorPositions[i];\n if (\n (range.startLineNumber === cursorPosition.startLineNumber) &&\n (range.endLineNumber === cursorPosition.endLineNumber) &&\n (range.startColumn === cursorPosition.startColumn) &&\n (range.endColumn === cursorPosition.endColumn)\n ) {\n return true;\n }\n }\n return false;\n });\n changesLength = changes.length;\n }\n if (diffInRow !== 0) {\n for (let i = restriction.index + 1; i < length; i++) {\n const nextRestriction = restrictions[i];\n const nextRange = nextRestriction.range;\n if (oldRangeEndLineNumber === nextRange.startLineNumber) {\n nextRange.startColumn += diffInCol;\n }\n if (oldRangeEndLineNumber === nextRange.endLineNumber) {\n nextRange.endColumn += diffInCol;\n }\n nextRange.startLineNumber += diffInRow;\n nextRange.endLineNumber += diffInRow;\n nextRestriction.range = nextRange;\n }\n for (let i = changeIndex + 1; i < changesLength; i++) {\n const nextChange = changes[i];\n const rangeInChange = nextChange.range;\n const rangeAsString = rangeInChange.toString();\n const rangeMapValue = rangeMap[rangeAsString];\n delete rangeMap[rangeAsString];\n if (oldRangeEndLineNumber === rangeInChange.startLineNumber) {\n rangeInChange.startColumn += diffInCol;\n }\n if (oldRangeEndLineNumber === rangeInChange.endLineNumber) {\n rangeInChange.endColumn += diffInCol;\n }\n rangeInChange.startLineNumber += diffInRow;\n rangeInChange.endLineNumber += diffInRow;\n nextChange.range = rangeInChange;\n rangeMap[rangeInChange.toString()] = rangeMapValue;\n }\n } else {\n // Only Column might have changed\n for (let i = restriction.index + 1; i < length; i++) {\n const nextRestriction = restrictions[i];\n const nextRange = nextRestriction.range;\n if (nextRange.startLineNumber > oldRangeEndLineNumber) {\n break;\n } else {\n nextRange.startColumn += diffInCol;\n nextRange.endColumn += diffInCol;\n nextRestriction.range = nextRange;\n }\n }\n for (let i = changeIndex + 1; i < changesLength; i++) {\n // rangeMap\n const nextChange = changes[i];\n const rangeInChange = nextChange.range;\n const rangeAsString = rangeInChange.toString();\n const rangeMapValue = rangeMap[rangeAsString];\n delete rangeMap[rangeAsString];\n if (rangeInChange.startLineNumber > oldRangeEndLineNumber) {\n rangeMap[rangeInChange.toString()] = rangeMapValue;\n break;\n } else {\n rangeInChange.startColumn += diffInCol;\n rangeInChange.endColumn += diffInCol;\n nextChange.range = rangeInChange;\n rangeMap[rangeInChange.toString()] = rangeMapValue;\n }\n }\n }\n // }\n };\n const getInfoFrom = function (change, editableRange) {\n const info = {};\n const range = change.range;\n // Get State\n if (change.text === '') {\n info.isDeletion = true;\n } else if (\n (range.startLineNumber === range.endLineNumber) &&\n (range.startColumn === range.endColumn)\n ) {\n info.isAddition = true;\n } else {\n info.isReplacement = true;\n }\n // Get Position Of Range\n info.startLineOfRange = range.startLineNumber === editableRange.startLineNumber;\n info.startColumnOfRange = range.startColumn === editableRange.startColumn;\n\n info.endLineOfRange = range.endLineNumber === editableRange.endLineNumber;\n info.endColumnOfRange = range.endColumn === editableRange.endColumn;\n\n info.middleLineOfRange = !info.startLineOfRange && !info.endLineOfRange;\n\n // Editable Range Span\n if (editableRange.startLineNumber === editableRange.endLineNumber) {\n info.rangeIsSingleLine = true;\n } else {\n info.rangeIsMultiLine = true;\n }\n return info;\n };\n const updateRestrictions = function (ranges) {\n restrictions = deepClone(ranges).sort(sortRangesInAscendingOrder);\n prepareRestrictions(restrictions);\n };\n const toggleHighlightOfEditableAreas = function () {\n if (!model._hasHighlight) {\n const decorations = restrictions.map(function (restriction) {\n const decoration = {\n range: restriction.range,\n options: {\n className: restriction.allowMultiline ?\n enums.MULTI_LINE_HIGHLIGHT_CLASS :\n enums.SINGLE_LINE_HIGHLIGHT_CLASS\n }\n }\n if (restriction.label) {\n decoration.hoverMessage = restriction.label;\n }\n return decoration;\n });\n model._oldDecorations = model.deltaDecorations([], decorations);\n model._oldDecorationsSource = decorations.map(function (decoration, index) {\n return Object.assign({}, decoration, { id: model._oldDecorations[index] });\n });\n model._hasHighlight = true;\n } else {\n model.deltaDecorations(model._oldDecorations, []);\n delete model._oldDecorations;\n delete model._oldDecorationsSource;\n model._hasHighlight = false;\n }\n }\n const handleUnhandledPromiseRejection = function () {\n console.debug('handler for unhandled promise rejection');\n };\n const setAllRangesToPrev = function (rangeMap) {\n for (let key in rangeMap) {\n const restriction = rangeMap[key];\n restriction.range = restriction.prevRange;\n }\n };\n const doesChangeHasMultilineConflict = function (restriction, text) {\n return !restriction.allowMultiline && text.includes('\\n');\n };\n const isChangeInvalidAsPerUser = function (restriction, value, range) {\n return restriction.validate && !restriction.validate(value, range, restriction.lastInfo);\n }\n\n const manipulatorApi = {\n _isRestrictedModel: true,\n _isRestrictedValueValid: true,\n _editableRangeChangeListener: [],\n _isCursorAtCheckPoint: isCursorAtCheckPoint,\n _currentCursorPositions: []\n }\n\n prepareRestrictions(restrictions);\n model._hasHighlight = false;\n manipulatorApi._restrictionChangeListener = model.onDidChangeContent(function (contentChangedEvent) {\n const isUndoing = contentChangedEvent.isUndoing;\n model._isRestrictedValueValid = true;\n if (!(isUndoing && model.editInRestrictedArea)) {\n const changes = contentChangedEvent.changes.sort(sortRangesInAscendingOrder);\n const rangeMap = {};\n const length = restrictions.length;\n const isAllChangesValid = changes.every(function (change) {\n const editedRange = change.range;\n const rangeAsString = editedRange.toString();\n rangeMap[rangeAsString] = null;\n for (let i = 0; i < length; i++) {\n const restriction = restrictions[i];\n const range = restriction.range;\n if (range.containsRange(editedRange)) {\n if (doesChangeHasMultilineConflict(restriction, change.text)) {\n return false;\n }\n rangeMap[rangeAsString] = restriction;\n return true;\n }\n }\n return false;\n })\n if (isAllChangesValid) {\n changes.forEach(function (change, changeIndex) {\n const changedRange = change.range;\n const restriction = rangeMap[changedRange.toString()];\n const editableRange = restriction.range;\n const text = change.text || '';\n /**\n * Things to check before implementing the change\n * - A | D | R => Addition | Deletion | Replacement\n * - MC | SC => MultiLineChange | SingleLineChange\n * - SOR | MOR | EOR => Change Occured in - Start Of Range | Middle Of Range | End Of Range\n * - SSL | SML => Editable Range - Spans Single Line | Spans Multiple Line\n */\n const noOfLinesAdded = (text.match(/\\n/g) || []).length;\n const noOfColsAddedAtLastLine = text.split(/\\n/g).pop().length;\n\n const lineDiffInRange = changedRange.endLineNumber - changedRange.startLineNumber;\n const colDiffInRange = changedRange.endColumn - changedRange.startColumn;\n\n let finalLine = editableRange.endLineNumber;\n let finalColumn = editableRange.endColumn;\n\n let columnsCarriedToEnd = 0;\n if (\n (editableRange.endLineNumber === changedRange.startLineNumber) ||\n (editableRange.endLineNumber === changedRange.endLineNumber)\n ) {\n columnsCarriedToEnd += (editableRange.endColumn - changedRange.startColumn) + 1;\n }\n\n const info = getInfoFrom(change, editableRange);\n restriction.lastInfo = info;\n if (info.isAddition || info.isReplacement) {\n if (info.rangeIsSingleLine) {\n /**\n * Only Column Change has occurred , so regardless of the position of the change\n * Addition of noOfCols is enough\n */\n if (noOfLinesAdded === 0) {\n finalColumn += noOfColsAddedAtLastLine;\n } else {\n finalLine += noOfLinesAdded;\n if (info.startColumnOfRange) {\n finalColumn += noOfColsAddedAtLastLine\n } else if (info.endColumnOfRange) {\n finalColumn = (noOfColsAddedAtLastLine + 1)\n } else {\n finalColumn = (noOfColsAddedAtLastLine + columnsCarriedToEnd)\n }\n }\n }\n if (info.rangeIsMultiLine) {\n // Handling for Start Of Range is not required\n finalLine += noOfLinesAdded;\n if (info.endLineOfRange) {\n if (noOfLinesAdded === 0) {\n finalColumn += noOfColsAddedAtLastLine;\n } else {\n finalColumn = (columnsCarriedToEnd + noOfColsAddedAtLastLine);\n }\n }\n }\n }\n if (info.isDeletion || info.isReplacement) {\n if (info.rangeIsSingleLine) {\n finalColumn -= colDiffInRange;\n }\n if (info.rangeIsMultiLine) {\n if (info.endLineOfRange) {\n finalLine -= lineDiffInRange;\n finalColumn -= colDiffInRange;\n } else {\n finalLine -= lineDiffInRange;\n }\n }\n }\n updateRange(restriction, editableRange, finalLine, finalColumn, changes, changeIndex);\n });\n const values = model.getValueInEditableRanges();\n const currentlyEditedRanges = {};\n for (let key in rangeMap) {\n const restriction = rangeMap[key];\n const range = restriction.range;\n const rangeString = restriction.label || range.toString();\n const value = values[rangeString];\n if (isChangeInvalidAsPerUser(restriction, value, range)) {\n setAllRangesToPrev(rangeMap);\n doUndo();\n return; // Breaks the loop and prevents the triggerChangeListener\n }\n currentlyEditedRanges[rangeString] = value;\n }\n if (model._hasHighlight) {\n model._oldDecorationsSource.forEach(function (object) {\n object.range = model.getDecorationRange(object.id);\n });\n }\n triggerChangeListenersWith(currentlyEditedRanges, values);\n } else {\n doUndo();\n }\n } else if (model.editInRestrictedArea) {\n model._isRestrictedValueValid = false;\n }\n });\n window.onerror = handleUnhandledPromiseRejection;\n const exposedApi = {\n editInRestrictedArea: false,\n getCurrentEditableRanges: getCurrentEditableRanges,\n getValueInEditableRanges: getValueInEditableRanges,\n disposeRestrictions: disposeRestrictions,\n onDidChangeContentInEditableRange: addEditableRangeListener,\n updateRestrictions: updateRestrictions,\n updateValueInEditableRanges: updateValueInEditableRanges,\n toggleHighlightOfEditableAreas: toggleHighlightOfEditableAreas\n }\n for (let funcName in manipulatorApi) {\n Object.defineProperty(model, funcName, {\n enumerable: false,\n configurable: true,\n writable: true,\n value: manipulatorApi[funcName]\n })\n }\n for (let apiName in exposedApi) {\n Object.defineProperty(model, apiName, {\n enumerable: false,\n configurable: true,\n writable: true,\n value: exposedApi[apiName]\n })\n }\n return model;\n}\nexport default constrainedModel;"],"sourceRoot":""} \ No newline at end of file diff --git a/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/constrainedEditor.css b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/constrainedEditor.css new file mode 100644 index 0000000..0ddb0d4 --- /dev/null +++ b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/constrainedEditor.css @@ -0,0 +1,7 @@ +.editableArea--single-line { + background: #dde969; +} + +.editableArea--multi-line { + background: #ffb74e; +} \ No newline at end of file diff --git a/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/constrainedEditor.js b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/constrainedEditor.js new file mode 100644 index 0000000..37a2b90 --- /dev/null +++ b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/constrainedEditor.js @@ -0,0 +1,212 @@ +import validators from './utils/validators.js'; +import { TypeMustBe } from './utils/definedErrors.js'; +import constrainedModel from './constrainedModel.js'; + +export function constrainedEditor(monaco) { + /** + * Injected Dependencies + */ + if (monaco === undefined) { + throw new Error([ + "Please pass the monaco global variable into function as", + "(eg:)constrainedEditor({ range : monaco.range });", + ].join('\n')); + } + /** + * + * @param {Object} editorInstance This should be the monaco editor instance. + * @description This is the listener function to check whether the cursor is at checkpoints + * (i.e) the point where editable and non editable portions meet + */ + const listenerFn = function (editorInstance) { + const model = editorInstance.getModel(); + if (model._isCursorAtCheckPoint) { + const selections = editorInstance.getSelections(); + const positions = selections.map(function (selection) { + return { + lineNumber: selection.positionLineNumber, + column: selection.positionColumn + } + }); + model._isCursorAtCheckPoint(positions); + model._currentCursorPositions = selections; + } + } + const _uriRestrictionMap = {}; + const { isInstanceValid, isModelValid, isRangesValid } = validators.initWith(monaco); + /** + * + * @param {Object} editorInstance This should be the monaco editor instance + * @returns {Boolean} + */ + const initInEditorInstance = function (editorInstance) { + if (isInstanceValid(editorInstance)) { + const domNode = editorInstance.getDomNode(); + manipulator._listener = listenerFn.bind(API, editorInstance); + manipulator._editorInstance = editorInstance; + manipulator._editorInstance._isInDevMode = false; + domNode.addEventListener('keydown', manipulator._listener, true); + editorInstance.onDidChangeModel(function () { + // domNode - refers old dom node + domNode.removeEventListener('keydown', manipulator._listener, true) + const newDomNode = editorInstance.getDomNode(); // Gets Current dom node + newDomNode.addEventListener('keydown', manipulator._listener, true); + domNode = newDomNode; + }) + return true; + } else { + throw new Error( + TypeMustBe( + 'ICodeEditor', + 'editorInstance', + 'This type interface can be found in monaco editor documentation' + ) + ) + } + } + /** + * + * @param {Object} model This should be the monaco editor model instance. Refer https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.itextmodel.html + * @param {*} ranges This should be the array of range objects. Refer constrained editor plugin documentation + * @returns model + */ + const addRestrictionsTo = function (model, ranges) { + if (isModelValid(model)) { + if (isRangesValid(ranges)) { + const modelToConstrain = constrainedModel(model, ranges, monaco, manipulator._editorInstance); + _uriRestrictionMap[modelToConstrain.uri.toString()] = modelToConstrain; + return modelToConstrain; + } else { + throw new Error( + TypeMustBe( + 'Array', + 'ranges', + 'Please refer constrained editor documentation for proper structure' + ) + ) + } + } else { + throw new Error( + TypeMustBe( + 'ICodeEditor', + 'editorInstance', + 'This type interface can be found in monaco editor documentation' + ) + ) + } + } + /** + * + * @param {Object} model This should be the monaco editor model instance. Refer https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.itextmodel.html + * @returns {Boolean} True if the restrictions are removed + */ + const removeRestrictionsIn = function (model) { + if (isModelValid(model)) { + const uri = model.uri.toString(); + const restrictedModel = _uriRestrictionMap[uri]; + if (restrictedModel) { + return restrictedModel.disposeRestrictions(); + } else { + console.warn('Current Model is not a restricted Model'); + return false; + } + } else { + throw new Error( + TypeMustBe( + 'ICodeEditor', + 'editorInstance', + 'This type interface can be found in monaco editor documentation' + ) + ) + } + } + /** + * + * @returns {Boolean} True if the constrainer is disposed + */ + const disposeConstrainer = function () { + if (manipulator._editorInstance) { + const instance = manipulator._editorInstance; + const domNode = instance.getDomNode(); + domNode.removeEventListener('keydown', manipulator._listener); + delete manipulator._listener; + delete manipulator._editorInstance._isInDevMode; + delete manipulator._editorInstance._devModeAction; + delete manipulator._editorInstance; + for (let key in _uriRestrictionMap) { + delete _uriRestrictionMap[key]; + } + return true; + } + return false; + } + /** + * @description This function used to make the developer to find the ranges of selected portions + */ + const toggleDevMode = function () { + if (manipulator._editorInstance._isInDevMode) { + manipulator._editorInstance._isInDevMode = false; + manipulator._editorInstance._devModeAction.dispose(); + delete manipulator._editorInstance._devModeAction; + } else { + manipulator._editorInstance._isInDevMode = true; + manipulator._editorInstance._devModeAction = manipulator._editorInstance.addAction({ + id: 'showRange', + label: 'Show Range in console', + contextMenuGroupId: 'navigation', + contextMenuOrder: 1.5, + run: function (editor) { + const selections = editor.getSelections(); + const ranges = selections.reduce(function (acc, { startLineNumber, endLineNumber, startColumn, endColumn }) { + acc.push('range : ' + JSON.stringify([ + startLineNumber, + startColumn, + endLineNumber, + endColumn + ])); + return acc; + }, []).join('\n'); + console.log(`Selected Ranges : \n` + JSON.stringify(ranges, null, 2)); + } + }); + } + } + + /** + * Main Function starts here + */ + // @internal + const manipulator = { + /** + * These variables should not be modified by external code + * This has to be used for debugging and testing + */ + _listener: null, + _editorInstance: null, + _uriRestrictionMap: _uriRestrictionMap, + _injectedResources: monaco + } + const API = Object.create(manipulator); + const exposedMethods = { + /** + * These functions are exposed to the user + * These functions should be protected from editing + */ + initializeIn: initInEditorInstance, + addRestrictionsTo: addRestrictionsTo, + removeRestrictionsIn: removeRestrictionsIn, + disposeConstrainer: disposeConstrainer, + toggleDevMode: toggleDevMode + } + for (let methodName in exposedMethods) { + Object.defineProperty(API, methodName, { + enumerable: false, + writable: false, + configurable: false, + value: exposedMethods[methodName] + }) + } + return Object.freeze(API); +} + +export default constrainedEditor; \ No newline at end of file diff --git a/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/constrainedModel.js b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/constrainedModel.js new file mode 100644 index 0000000..4c7fa2b --- /dev/null +++ b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/constrainedModel.js @@ -0,0 +1,560 @@ +import deepClone from './utils/deepClone.js'; +import enums from './utils/enums.js'; +export const constrainedModel = function (model, ranges, monaco) { + const rangeConstructor = monaco.Range; + const sortRangesInAscendingOrder = function (rangeObject1, rangeObject2) { + const rangeA = rangeObject1.range; + const rangeB = rangeObject2.range; + if ( + rangeA[0] < rangeB[0] || + (rangeA[0] === rangeB[0] && rangeA[3] < rangeB[1]) + ) { + return -1; + } + } + const normalizeRange = function (range, content) { + const lines = content.split('\n'); + const noOfLines = lines.length; + const normalizedRange = []; + range.forEach(function (value, index) { + if (value === 0) { + throw new Error('Range values cannot be zero');//No I18n + } + switch (index) { + case 0: { + if (value < 0) { + throw new Error('Start Line of Range cannot be negative');//No I18n + } else if (value > noOfLines) { + throw new Error('Provided Start Line(' + value + ') is out of bounds. Max Lines in content is ' + noOfLines);//No I18n + } + normalizedRange[index] = value; + } + break; + case 1: { + let actualStartCol = value; + const startLineNo = normalizedRange[0]; + const maxCols = lines[startLineNo - 1].length + if (actualStartCol < 0) { + actualStartCol = maxCols - Math.abs(actualStartCol); + if (actualStartCol < 0) { + throw new Error('Provided Start Column(' + value + ') is out of bounds. Max Column in line ' + startLineNo + ' is ' + maxCols);//No I18n + } + } else if (actualStartCol > (maxCols + 1)) { + throw new Error('Provided Start Column(' + value + ') is out of bounds. Max Column in line ' + startLineNo + ' is ' + maxCols);//No I18n + } + normalizedRange[index] = actualStartCol; + } + break; + case 2: { + let actualEndLine = value; + if (actualEndLine < 0) { + actualEndLine = noOfLines - Math.abs(value); + if (actualEndLine < 0) { + throw new Error('Provided End Line(' + value + ') is out of bounds. Max Lines in content is ' + noOfLines);//No I18n + } + if (actualEndLine < normalizedRange[0]) { + console.warn('Provided End Line(' + value + ') is less than the start Line, the Restriction may not behave as expected');//No I18n + } + } else if (value > noOfLines) { + throw new Error('Provided End Line(' + value + ') is out of bounds. Max Lines in content is ' + noOfLines);//No I18n + } + normalizedRange[index] = actualEndLine; + } + break; + case 3: { + let actualEndCol = value; + const endLineNo = normalizedRange[2]; + const maxCols = lines[endLineNo - 1].length + if (actualEndCol < 0) { + actualEndCol = maxCols - Math.abs(actualEndCol); + if (actualEndCol < 0) { + throw new Error('Provided End Column(' + value + ') is out of bounds. Max Column in line ' + endLineNo + ' is ' + maxCols);//No I18n + } + } else if (actualEndCol > (maxCols + 1)) { + throw new Error('Provided Start Column(' + value + ') is out of bounds. Max Column in line ' + endLineNo + ' is ' + maxCols);//No I18n + } + normalizedRange[index] = actualEndCol; + } + break; + } + }) + return normalizedRange; + } + let restrictions = deepClone(ranges).sort(sortRangesInAscendingOrder); + const prepareRestrictions = function (restrictions) { + const content = model.getValue(); + restrictions.forEach(function (restriction, index) { + const range = normalizeRange(restriction.range, content); + const startLine = range[0]; + const startCol = range[1]; + const endLine = range[2]; + const endCol = range[3]; + restriction._originalRange = range.slice(); + restriction.range = new rangeConstructor(startLine, startCol, endLine, endCol); + restriction.index = index; + if (!restriction.allowMultiline) { + restriction.allowMultiline = rangeConstructor.spansMultipleLines(restriction.range) + } + if (!restriction.label) { + restriction.label = `[${startLine},${startCol} -> ${endLine}${endCol}]`; + } + }); + } + const getCurrentEditableRanges = function () { + return restrictions.reduce(function (acc, restriction) { + acc[restriction.label] = { + allowMultiline: restriction.allowMultiline || false, + index: restriction.index, + range: Object.assign({}, restriction.range), + originalRange: restriction._originalRange.slice() + }; + return acc; + }, {}); + } + const getValueInEditableRanges = function () { + return restrictions.reduce(function (acc, restriction) { + acc[restriction.label] = model.getValueInRange(restriction.range); + return acc; + }, {}); + } + const updateValueInEditableRanges = function (object, forceMoveMarkers) { + if (typeof object === 'object' && !Array.isArray(object)) { + forceMoveMarkers = typeof forceMoveMarkers === 'boolean' ? forceMoveMarkers : false; + const restrictionsMap = restrictions.reduce(function (acc, restriction) { + if (restriction.label) { + acc[restriction.label] = restriction; + } + return acc; + }, {}); + for (let label in object) { + const restriction = restrictionsMap[label]; + if (restriction) { + const value = object[label]; + if (doesChangeHasMultilineConflict(restriction, value)) { + throw new Error('Multiline change is not allowed for ' + label); + } + const newRange = deepClone(restriction.range); + newRange.endLine = newRange.startLine + value.split('\n').length - 1; + newRange.endColumn = value.split('\n').pop().length; + if (isChangeInvalidAsPerUser(restriction, value, newRange)) { + throw new Error('Change is invalidated by validate function of ' + label); + } + model.applyEdits([{ + forceMoveMarkers: !!forceMoveMarkers, + range: restriction.range, + text: value + }]); + } else { + console.error('No restriction found for ' + label); + } + } + } else { + throw new Error('Value must be an object');//No I18n + } + } + const disposeRestrictions = function () { + model._restrictionChangeListener.dispose(); + window.removeEventListener("error", handleUnhandledPromiseRejection); + delete model.editInRestrictedArea; + delete model.disposeRestrictions; + delete model.getValueInEditableRanges; + delete model.updateValueInEditableRanges; + delete model.updateRestrictions; + delete model.getCurrentEditableRanges; + delete model.toggleHighlightOfEditableAreas; + delete model._hasHighlight; + delete model._isRestrictedModel; + delete model._isCursorAtCheckPoint; + delete model._currentCursorPositions; + delete model._editableRangeChangeListener; + delete model._restrictionChangeListener; + delete model._oldDecorations; + delete model._oldDecorationsSource; + return model; + } + const isCursorAtCheckPoint = function (positions) { + positions.some(function (position) { + const posLineNumber = position.lineNumber; + const posCol = position.column; + const length = restrictions.length; + for (let i = 0; i < length; i++) { + const range = restrictions[i].range; + if ( + (range.startLineNumber === posLineNumber && range.startColumn === posCol) || + (range.endLineNumber === posLineNumber && range.endColumn === posCol) + ) { + model.pushStackElement(); + return true; + } + } + }); + }; + const addEditableRangeListener = function (callback) { + if (typeof callback === 'function') { + model._editableRangeChangeListener.push(callback); + } + }; + const triggerChangeListenersWith = function (currentChanges, allChanges) { + const currentRanges = getCurrentEditableRanges(); + model._editableRangeChangeListener.forEach(function (callback) { + callback.call(model, currentChanges, allChanges, currentRanges); + }); + }; + const doUndo = function () { + return Promise.resolve().then(function () { + model.editInRestrictedArea = true; + model.undo(); + model.editInRestrictedArea = false; + if (model._hasHighlight && model._oldDecorationsSource) { + // id present in the decorations info will be omitted by monaco + // So we don't need to remove the old decorations id + model.deltaDecorations(model._oldDecorations, model._oldDecorationsSource); + model._oldDecorationsSource.forEach(function (object) { + object.range = model.getDecorationRange(object.id); + }); + } + }); + }; + const updateRange = function (restriction, range, finalLine, finalColumn, changes, changeIndex) { + let oldRangeEndLineNumber = range.endLineNumber; + let oldRangeEndColumn = range.endColumn; + restriction.prevRange = range; + restriction.range = range.setEndPosition(finalLine, finalColumn); + const length = restrictions.length; + let changesLength = changes.length; + const diffInCol = finalColumn - oldRangeEndColumn; + const diffInRow = finalLine - oldRangeEndLineNumber; + + const cursorPositions = model._currentCursorPositions || []; + const noOfCursorPositions = cursorPositions.length; + // if (noOfCursorPositions > 0) { + if (changesLength !== noOfCursorPositions) { + changes = changes.filter(function (change) { + const range = change.range; + for (let i = 0; i < noOfCursorPositions; i++) { + const cursorPosition = cursorPositions[i]; + if ( + (range.startLineNumber === cursorPosition.startLineNumber) && + (range.endLineNumber === cursorPosition.endLineNumber) && + (range.startColumn === cursorPosition.startColumn) && + (range.endColumn === cursorPosition.endColumn) + ) { + return true; + } + } + return false; + }); + changesLength = changes.length; + } + if (diffInRow !== 0) { + for (let i = restriction.index + 1; i < length; i++) { + const nextRestriction = restrictions[i]; + const nextRange = nextRestriction.range; + if (oldRangeEndLineNumber === nextRange.startLineNumber) { + nextRange.startColumn += diffInCol; + } + if (oldRangeEndLineNumber === nextRange.endLineNumber) { + nextRange.endColumn += diffInCol; + } + nextRange.startLineNumber += diffInRow; + nextRange.endLineNumber += diffInRow; + nextRestriction.range = nextRange; + } + for (let i = changeIndex + 1; i < changesLength; i++) { + const nextChange = changes[i]; + const rangeInChange = nextChange.range; + const rangeAsString = rangeInChange.toString(); + const rangeMapValue = rangeMap[rangeAsString]; + delete rangeMap[rangeAsString]; + if (oldRangeEndLineNumber === rangeInChange.startLineNumber) { + rangeInChange.startColumn += diffInCol; + } + if (oldRangeEndLineNumber === rangeInChange.endLineNumber) { + rangeInChange.endColumn += diffInCol; + } + rangeInChange.startLineNumber += diffInRow; + rangeInChange.endLineNumber += diffInRow; + nextChange.range = rangeInChange; + rangeMap[rangeInChange.toString()] = rangeMapValue; + } + } else { + // Only Column might have changed + for (let i = restriction.index + 1; i < length; i++) { + const nextRestriction = restrictions[i]; + const nextRange = nextRestriction.range; + if (nextRange.startLineNumber > oldRangeEndLineNumber) { + break; + } else { + nextRange.startColumn += diffInCol; + nextRange.endColumn += diffInCol; + nextRestriction.range = nextRange; + } + } + for (let i = changeIndex + 1; i < changesLength; i++) { + // rangeMap + const nextChange = changes[i]; + const rangeInChange = nextChange.range; + const rangeAsString = rangeInChange.toString(); + const rangeMapValue = rangeMap[rangeAsString]; + delete rangeMap[rangeAsString]; + if (rangeInChange.startLineNumber > oldRangeEndLineNumber) { + rangeMap[rangeInChange.toString()] = rangeMapValue; + break; + } else { + rangeInChange.startColumn += diffInCol; + rangeInChange.endColumn += diffInCol; + nextChange.range = rangeInChange; + rangeMap[rangeInChange.toString()] = rangeMapValue; + } + } + } + // } + }; + const getInfoFrom = function (change, editableRange) { + const info = {}; + const range = change.range; + // Get State + if (change.text === '') { + info.isDeletion = true; + } else if ( + (range.startLineNumber === range.endLineNumber) && + (range.startColumn === range.endColumn) + ) { + info.isAddition = true; + } else { + info.isReplacement = true; + } + // Get Position Of Range + info.startLineOfRange = range.startLineNumber === editableRange.startLineNumber; + info.startColumnOfRange = range.startColumn === editableRange.startColumn; + + info.endLineOfRange = range.endLineNumber === editableRange.endLineNumber; + info.endColumnOfRange = range.endColumn === editableRange.endColumn; + + info.middleLineOfRange = !info.startLineOfRange && !info.endLineOfRange; + + // Editable Range Span + if (editableRange.startLineNumber === editableRange.endLineNumber) { + info.rangeIsSingleLine = true; + } else { + info.rangeIsMultiLine = true; + } + return info; + }; + const updateRestrictions = function (ranges) { + restrictions = deepClone(ranges).sort(sortRangesInAscendingOrder); + prepareRestrictions(restrictions); + }; + const toggleHighlightOfEditableAreas = function () { + if (!model._hasHighlight) { + const decorations = restrictions.map(function (restriction) { + const decoration = { + range: restriction.range, + options: { + className: restriction.allowMultiline ? + enums.MULTI_LINE_HIGHLIGHT_CLASS : + enums.SINGLE_LINE_HIGHLIGHT_CLASS + } + } + if (restriction.label) { + decoration.hoverMessage = restriction.label; + } + return decoration; + }); + model._oldDecorations = model.deltaDecorations([], decorations); + model._oldDecorationsSource = decorations.map(function (decoration, index) { + return Object.assign({}, decoration, { id: model._oldDecorations[index] }); + }); + model._hasHighlight = true; + } else { + model.deltaDecorations(model._oldDecorations, []); + delete model._oldDecorations; + delete model._oldDecorationsSource; + model._hasHighlight = false; + } + } + const handleUnhandledPromiseRejection = function () { + console.debug('handler for unhandled promise rejection'); + }; + const setAllRangesToPrev = function (rangeMap) { + for (let key in rangeMap) { + const restriction = rangeMap[key]; + restriction.range = restriction.prevRange; + } + }; + const doesChangeHasMultilineConflict = function (restriction, text) { + return !restriction.allowMultiline && text.includes('\n'); + }; + const isChangeInvalidAsPerUser = function (restriction, value, range) { + return restriction.validate && !restriction.validate(value, range, restriction.lastInfo); + } + + const manipulatorApi = { + _isRestrictedModel: true, + _isRestrictedValueValid: true, + _editableRangeChangeListener: [], + _isCursorAtCheckPoint: isCursorAtCheckPoint, + _currentCursorPositions: [] + } + + prepareRestrictions(restrictions); + model._hasHighlight = false; + manipulatorApi._restrictionChangeListener = model.onDidChangeContent(function (contentChangedEvent) { + const isUndoing = contentChangedEvent.isUndoing; + model._isRestrictedValueValid = true; + if (!(isUndoing && model.editInRestrictedArea)) { + const changes = contentChangedEvent.changes.sort(sortRangesInAscendingOrder); + const rangeMap = {}; + const length = restrictions.length; + const isAllChangesValid = changes.every(function (change) { + const editedRange = change.range; + const rangeAsString = editedRange.toString(); + rangeMap[rangeAsString] = null; + for (let i = 0; i < length; i++) { + const restriction = restrictions[i]; + const range = restriction.range; + if (range.containsRange(editedRange)) { + if (doesChangeHasMultilineConflict(restriction, change.text)) { + return false; + } + rangeMap[rangeAsString] = restriction; + return true; + } + } + return false; + }) + if (isAllChangesValid) { + changes.forEach(function (change, changeIndex) { + const changedRange = change.range; + const restriction = rangeMap[changedRange.toString()]; + const editableRange = restriction.range; + const text = change.text || ''; + /** + * Things to check before implementing the change + * - A | D | R => Addition | Deletion | Replacement + * - MC | SC => MultiLineChange | SingleLineChange + * - SOR | MOR | EOR => Change Occured in - Start Of Range | Middle Of Range | End Of Range + * - SSL | SML => Editable Range - Spans Single Line | Spans Multiple Line + */ + const noOfLinesAdded = (text.match(/\n/g) || []).length; + const noOfColsAddedAtLastLine = text.split(/\n/g).pop().length; + + const lineDiffInRange = changedRange.endLineNumber - changedRange.startLineNumber; + const colDiffInRange = changedRange.endColumn - changedRange.startColumn; + + let finalLine = editableRange.endLineNumber; + let finalColumn = editableRange.endColumn; + + let columnsCarriedToEnd = 0; + if ( + (editableRange.endLineNumber === changedRange.startLineNumber) || + (editableRange.endLineNumber === changedRange.endLineNumber) + ) { + columnsCarriedToEnd += (editableRange.endColumn - changedRange.startColumn) + 1; + } + + const info = getInfoFrom(change, editableRange); + restriction.lastInfo = info; + if (info.isAddition || info.isReplacement) { + if (info.rangeIsSingleLine) { + /** + * Only Column Change has occurred , so regardless of the position of the change + * Addition of noOfCols is enough + */ + if (noOfLinesAdded === 0) { + finalColumn += noOfColsAddedAtLastLine; + } else { + finalLine += noOfLinesAdded; + if (info.startColumnOfRange) { + finalColumn += noOfColsAddedAtLastLine + } else if (info.endColumnOfRange) { + finalColumn = (noOfColsAddedAtLastLine + 1) + } else { + finalColumn = (noOfColsAddedAtLastLine + columnsCarriedToEnd) + } + } + } + if (info.rangeIsMultiLine) { + // Handling for Start Of Range is not required + finalLine += noOfLinesAdded; + if (info.endLineOfRange) { + if (noOfLinesAdded === 0) { + finalColumn += noOfColsAddedAtLastLine; + } else { + finalColumn = (columnsCarriedToEnd + noOfColsAddedAtLastLine); + } + } + } + } + if (info.isDeletion || info.isReplacement) { + if (info.rangeIsSingleLine) { + finalColumn -= colDiffInRange; + } + if (info.rangeIsMultiLine) { + if (info.endLineOfRange) { + finalLine -= lineDiffInRange; + finalColumn -= colDiffInRange; + } else { + finalLine -= lineDiffInRange; + } + } + } + updateRange(restriction, editableRange, finalLine, finalColumn, changes, changeIndex); + }); + const values = model.getValueInEditableRanges(); + const currentlyEditedRanges = {}; + for (let key in rangeMap) { + const restriction = rangeMap[key]; + const range = restriction.range; + const rangeString = restriction.label || range.toString(); + const value = values[rangeString]; + if (isChangeInvalidAsPerUser(restriction, value, range)) { + setAllRangesToPrev(rangeMap); + doUndo(); + return; // Breaks the loop and prevents the triggerChangeListener + } + currentlyEditedRanges[rangeString] = value; + } + if (model._hasHighlight) { + model._oldDecorationsSource.forEach(function (object) { + object.range = model.getDecorationRange(object.id); + }); + } + triggerChangeListenersWith(currentlyEditedRanges, values); + } else { + doUndo(); + } + } else if (model.editInRestrictedArea) { + model._isRestrictedValueValid = false; + } + }); + window.onerror = handleUnhandledPromiseRejection; + const exposedApi = { + editInRestrictedArea: false, + getCurrentEditableRanges: getCurrentEditableRanges, + getValueInEditableRanges: getValueInEditableRanges, + disposeRestrictions: disposeRestrictions, + onDidChangeContentInEditableRange: addEditableRangeListener, + updateRestrictions: updateRestrictions, + updateValueInEditableRanges: updateValueInEditableRanges, + toggleHighlightOfEditableAreas: toggleHighlightOfEditableAreas + } + for (let funcName in manipulatorApi) { + Object.defineProperty(model, funcName, { + enumerable: false, + configurable: true, + writable: true, + value: manipulatorApi[funcName] + }) + } + for (let apiName in exposedApi) { + Object.defineProperty(model, apiName, { + enumerable: false, + configurable: true, + writable: true, + value: exposedApi[apiName] + }) + } + return model; +} +export default constrainedModel; \ No newline at end of file diff --git a/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/utils/deepClone.js b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/utils/deepClone.js new file mode 100644 index 0000000..fe60560 --- /dev/null +++ b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/utils/deepClone.js @@ -0,0 +1,73 @@ +export const deepClone = (function () { + const byPassPrimitives = function (value, callback) { + if (typeof value !== 'object' || value === null) { + return this.freeze ? Object.freeze(value) : value; + } + if (value instanceof Date) { + return this.freeze ? Object.freeze(new Date(value)) : new Date(value); + } + return callback.call(this, value); + } + const cloneArray = function (array, callback) { + const keys = Object.keys(array); + const arrayClone = new Array(keys.length) + for (let i = 0; i < keys.length; i++) { + arrayClone[keys[i]] = byPassPrimitives.call(this, array[keys[i]], callback); + } + return arrayClone; + } + const cloner = function (object) { + return byPassPrimitives.call(this, object, function (object) { + if (Array.isArray(object)) { + return cloneArray.call(this, object, cloner) + } + const clone = {}; + for (let key in object) { + if (!this.withProto && Object.hasOwnProperty.call(object, key) === false) { + continue; + } + clone[key] = byPassPrimitives.call(this, object[key], cloner); + } + return clone; + }) + } + const config = (function () { + const constructOptionForCode = function (value) { + const options = [ + 'withProto', + 'freeze' + ] + this[value] = options.reduce(function (acc, option) { + if (acc[option] = (value >= this[option])) { + value -= this[option] + } + return acc; + }.bind(this), {}) + } + const codes = Object.create(Object.defineProperties({}, { + withProto: { value: 1 }, + freeze: { value: 2 } + })); + for (let i = 0; i <= 3; i++) { + constructOptionForCode.call(codes, i); + } + return codes; + }()); + const methods = { + withProto: cloner.bind(config[1]), + andFreeze: cloner.bind(config[2]), + withProtoAndFreeze: cloner.bind(config[3]) + } + const API = cloner.bind(config[0]); + for (let methodName in methods) { + Object.defineProperty(API, methodName, { + enumerable: false, + writable: false, + configurable: false, + value: methods[methodName] + }) + } + return API; +}()); + +export default deepClone; \ No newline at end of file diff --git a/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/utils/definedErrors.js b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/utils/definedErrors.js new file mode 100644 index 0000000..27c317d --- /dev/null +++ b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/utils/definedErrors.js @@ -0,0 +1,7 @@ +export const TypeMustBe = function (type, key, additional) { + return 'The value for the ' + key + ' should be of type ' + (Array.isArray(type) ? type.join(' | ') : type) + '. ' + (additional || '') +} +const definedErrors = { + TypeMustBe : TypeMustBe +}; +export default definedErrors; \ No newline at end of file diff --git a/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/utils/enums.js b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/utils/enums.js new file mode 100644 index 0000000..bafe3af --- /dev/null +++ b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/utils/enums.js @@ -0,0 +1,5 @@ +export const enums = { + SINGLE_LINE_HIGHLIGHT_CLASS: 'editableArea--single-line', + MULTI_LINE_HIGHLIGHT_CLASS: 'editableArea--multi-line' +} +export default enums; \ No newline at end of file diff --git a/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/utils/validators.js b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/utils/validators.js new file mode 100644 index 0000000..3f0d1db --- /dev/null +++ b/src/main/resources/static/plugins/vs/plugin/constrained-editor-plugin/esm/utils/validators.js @@ -0,0 +1,44 @@ +const validators = { + initWith: function (monaco) { + const dummyDiv = document.createElement('div'); + const dummyEditorInstance = monaco.editor.create(dummyDiv); + const editorInstanceConstructorName = dummyEditorInstance.constructor.name; + const editorModelConstructorName = dummyEditorInstance.getModel().constructor.name; + const instanceCheck = function (valueToValidate) { + return valueToValidate.constructor.name === editorInstanceConstructorName; + } + const modelCheck = function (valueToValidate) { + return valueToValidate.constructor.name === editorModelConstructorName; + } + const rangesCheck = function (ranges) { + if (Array.isArray(ranges)) { + return ranges.every(function (rangeObj) { + if (typeof rangeObj === 'object' && rangeObj.constructor.name === 'Object') { + if (!rangeObj.hasOwnProperty('range')) return false; + if (!Array.isArray(rangeObj.range)) return false; + if (rangeObj.range.length !== 4) return false; + if (!(rangeObj.range.every(num => num > 0 && parseInt(num) === num))) return false; + if (rangeObj.hasOwnProperty('allowMultiline')) { + if (typeof rangeObj.allowMultiline !== 'boolean') return false; + } + if (rangeObj.hasOwnProperty('label')) { + if (typeof rangeObj.label !== 'string') return false; + } + if (rangeObj.hasOwnProperty('validate')) { + if (typeof rangeObj.validate !== 'function') return false; + } + return true; + } + return false; + }); + } + return false; + } + return { + isInstanceValid: instanceCheck, + isModelValid: modelCheck, + isRangesValid: rangesCheck + } + } +} +export default validators; \ No newline at end of file