UNPKG

webgme-bip

Version:

Design studio for component-based modeling with BIP.

307 lines (264 loc) 11.9 kB
/*globals define, WebGMEGlobal, $*/ /*jshint browser: true*/ /** * Generated by VisualizerGenerator 1.7.0 from webgme on Wed Apr 12 2017 11:41:59 GMT-0500 (Central Daylight Time). */ define(['bipsrc/bower_components/codemirror/lib/codemirror', 'bipsrc/bower_components/codemirror/mode/clike/clike', 'css!./styles/BIPCodeEditorWidget.css', 'css!bipsrc/bower_components/codemirror/lib/codemirror.css', 'css!bipsrc/bower_components/codemirror/theme/monokai.css' ], function (CodeMirror) { 'use strict'; var BIPCodeEditorWidget, WIDGET_CLASS = 'b-i-p-code-editor', SYNTAX_GUTTER = 'code-syntax'; BIPCodeEditorWidget = function (logger, container) { this._logger = logger.fork('Widget'); this._el = container; this._segmentedDocument = { composition: [], segments: {} }; this._wholeDocument = null; this._autoSaveTimer = null; this._autoSaveInterval = 20000; this._initialize(); this._logger.debug('ctor finished'); }; BIPCodeEditorWidget.prototype._initialize = function () { var self = this, saving = function () { self._autoSave(); }; // set widget class this._el.addClass(WIDGET_CLASS); //handling the ctrl+S / cmd+S key pressing CodeMirror.commands.save = function (editor) { if (self._autoSaveTimer) { clearTimeout(self._autoSaveTimer); saving(); } }; // The code editor. this.editor = CodeMirror(this._el[0], { readOnly: false, lineNumbers: true, matchBrackets: true, lint: false, path: './bower_components/codemirror/lib/', theme: 'monokai', mode: 'text/x-java', autofocus: true, dragDrop: false, gutters: [SYNTAX_GUTTER, "CodeMirror-linenumbers"] }); $(this.editor.getWrapperElement()).addClass('code-editor'); this._wholeDocument = this.editor.getDoc(); this._wholeDocument.on('change', function (/*doc,changeObj*/) { self.editor.clearGutter(SYNTAX_GUTTER); if (self._autoSaveTimer) { clearTimeout(self._autoSaveTimer); self._autoSaveTimer = setTimeout(saving, self._autoSaveInterval); } self._autoSaveTimer = setTimeout(saving, self._autoSaveInterval); }); }; BIPCodeEditorWidget.prototype._setSyntaxError = function (lineNumber, message) { var marker = document.createElement("i"); marker.className = "glyphicon glyphicon-exclamation-sign"; marker.style.color = "#822"; marker.title = message; this.editor.setGutterMarker(lineNumber - 1, SYNTAX_GUTTER, marker); }; BIPCodeEditorWidget.prototype.onWidgetContainerResize = function (width, height) { this._el.width(width); this._el.height(height); this._logger.debug('Widget is resizing...'); }; /* * * * * * * * Visualizer event handlers * * * * * * * */ BIPCodeEditorWidget.prototype.onSave = function (/*segmentedDocumentObject*/) { this._logger.info('The onSave event is not overwritten!'); }; /* * * * * * * * Complex document management services * * * * */ BIPCodeEditorWidget.prototype.setDocumentSegment = function (segmentName, segmentValue) { if (this._segmentedDocument.segments[segmentName]) { this._segmentedDocument.segments[segmentName].value = segmentValue; this._rebuildCompleteDocument(); } else { this._logger.error('unknown segment [' + segmentName + '] cannot be changed'); } }; BIPCodeEditorWidget.prototype.setSegmentedDocument = function (segmentedDocumentObject) { // we do not have to worry about cleaning, as setting the main document allegedly does it var newDocument = {segments: {}}, i; newDocument.composition = JSON.parse(JSON.stringify(segmentedDocumentObject.composition)); if (Array.isArray(newDocument.composition) !== true) { this._logger.error('Invalid segmentedDocumentObject [should have a composition array tag]'); return; } if (typeof segmentedDocumentObject.segments !== 'object' || segmentedDocumentObject.segments === null) { this._logger.error('Invalid segmentedDocumentObject ' + '[should have a segments tag that is the collection of the segments]'); return; } for (i = 0; i < newDocument.composition.length; i += 1) { if (typeof newDocument.composition[i] !== 'string') { this._logger.error('Invalid segmentedDocumentObject [segment identification should be string based]'); return; } if (segmentedDocumentObject.segments.hasOwnProperty(newDocument.composition[i]) !== true) { this._logger.error('Invalid segmentedDocumentObject [segment \'' + newDocument.composition[i] + '\' is missing]'); return; } if (segmentedDocumentObject.segments[newDocument.composition[i]].options && typeof segmentedDocumentObject.segments[newDocument.composition[i]].options !== 'object') { this._logger.error('Invalid segmentedDocumentObject [segment \'' + newDocument.composition[i] + '\' has an invalid options field]'); return; } if (typeof segmentedDocumentObject.segments[newDocument.composition[i]].value !== 'string') { this._logger.error('All document segment value has to be a string.'); return; } newDocument.segments[newDocument.composition[i]] = { options: JSON.parse( JSON.stringify(segmentedDocumentObject.segments[newDocument.composition[i]].options || {})), value: segmentedDocumentObject.segments[newDocument.composition[i]].value }; } this._segmentedDocument = newDocument; this._rebuildCompleteDocument(); if (segmentedDocumentObject.errors) { for (i = 0; i < segmentedDocumentObject.errors.length; i += 1) { this._setSyntaxError(segmentedDocumentObject.errors[i].line, segmentedDocumentObject.errors[i].message); } } if (this._autoSaveTimer) { clearTimeout(this._autoSaveTimer); this._autoSaveTimer = null; } }; BIPCodeEditorWidget.prototype.getDocument = function () { return this._wholeDocument.getValue(); }; BIPCodeEditorWidget.prototype.getDocumentSegment = function (segmentName) { if (this._segmentedDocument.segments[segmentName]) { return this._segmentedDocument.segments[segmentName].value; } else { this._logger.error('unknown segment [' + segmentName + ']'); return null; } }; BIPCodeEditorWidget.prototype.getChangedSegments = function () { var segments = {}, segment, doc; for (segment in this._segmentedDocument.segments) { doc = this._segmentedDocument.segments[segment].doc.getValue(); if (doc !== this._segmentedDocument.segments[segment].value) { segments[segment] = doc; } } return segments; }; BIPCodeEditorWidget.prototype._getNumberOfLinesOfSegment = function (segmentName) { //TODO: check if this is enough or we need some more sophisticated thing return this._segmentedDocument.segments[segmentName].value.split('\n').length; }; BIPCodeEditorWidget.prototype._rebuildCompleteDocument = function () { var i, segment, wholeDocument = '', oldCursorPosition = this._wholeDocument.getCursor(), oldScrollInfo = this.editor.getScrollInfo(), lineIndex, segmentLines; this.editor.clearGutter(SYNTAX_GUTTER); for (i = 0; i < this._segmentedDocument.composition.length; i += 1) { segment = this._segmentedDocument.segments[this._segmentedDocument.composition[i]]; if (segment.doc) { this._wholeDocument.unlinkDoc(segment.doc); delete segment.doc; if (segment.readOnlyMarker) { segment.readOnlyMarker.clear(); delete segment.readOnlyMarker; } } wholeDocument += segment.value + '\n'; } this._wholeDocument.setValue(wholeDocument); lineIndex = 0; for (i = 0; i < this._segmentedDocument.composition.length; i += 1) { segment = this._segmentedDocument.segments[this._segmentedDocument.composition[i]]; segmentLines = this._getNumberOfLinesOfSegment(this._segmentedDocument.composition[i]); segment.doc = this._wholeDocument.linkedDoc({ sharedHist: true, from: lineIndex, to: lineIndex + segmentLines }); lineIndex += segmentLines; if (segment.options.readonly === true) { this._setSegmentReadOnly(this._segmentedDocument.composition[i], true); } } this.editor.focus(); this.editor.refresh(); this._wholeDocument.setCursor(oldCursorPosition); this.editor.scrollTo(oldScrollInfo.left, oldScrollInfo.top); }; BIPCodeEditorWidget.prototype._setSegmentReadOnly = function (segmentName, readOnly) { var segmentInfo, fromLine, toLine; if (this._segmentedDocument.segments[segmentName]) { segmentInfo = this._segmentedDocument.segments[segmentName]; if (segmentInfo.readOnlyMarker) { segmentInfo.readOnlyMarker.clear(); delete segmentInfo.readOnlyMarker; } if (readOnly) { fromLine = segmentInfo.doc.firstLine(); toLine = segmentInfo.doc.lastLine() + 1; segmentInfo.readOnlyMarker = this._wholeDocument.markText( {line: fromLine, ch: 0}, {line: toLine, ch: 0}, { readonly: true, atomic: true, inclusiveLeft: true, inclusiveRight: false, className: 'read-only-code' } ); } } else { this._logger.error('unknown segment [' + segmentName + '] cannot be changed'); } }; BIPCodeEditorWidget.prototype._autoSave = function () { var changedSegments = this.getChangedSegments(), segment; this._autoSaveTimer = null; if (Object.keys(changedSegments).length > 0) { for (segment in changedSegments) { this._segmentedDocument.segments[segment].value = changedSegments[segment]; } this.onSave(changedSegments); } }; /* * * * * * * * Visualizer life cycle callbacks * * * * * * * */ BIPCodeEditorWidget.prototype.destroy = function () { if (this._autoSaveTimer) { this._autoSave(); } }; BIPCodeEditorWidget.prototype.onActivate = function () { this._logger.debug('BIPCodeEditorWidget has been activated'); }; BIPCodeEditorWidget.prototype.onDeactivate = function () { this._logger.debug('BIPCodeEditorWidget has been deactivated'); if (this._autoSaveTimer) { this._autoSave(); } }; return BIPCodeEditorWidget; });