blob: f8f952207d9c4bb39e4d2ddc91e3b68e9f2a7afc [file] [log] [blame]
// Copyright (c) 2000-2017 Ericsson Telecom AB //
// All rights reserved. This program and the accompanying materials are made available under the //
// terms of the Eclipse Public License v2.0 which accompanies this distribution, and is available at //
// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html //
///////////////////////////////////////////////////////////////////////////////////////////////////////
function CView_CodeEditor(p_viewmodels, p_viewId, p_parentId, p_options) {
if (p_options.editorType == "html") {
return new CView_HtmlEditor(p_viewmodels, p_viewId, p_parentId, p_options);
} else if (p_options.editorType == "css") {
return new CView_CssEditor(p_viewmodels, p_viewId, p_parentId, p_options);
} else if (p_options.editorType == "javascript") {
return new CView_JavascriptEditor(p_viewmodels, p_viewId, p_parentId, p_options);
} else if (p_options.editorType == "json") {
return new CView_JSONCodeEditor(p_viewmodels, p_viewId, p_parentId, p_options);
} else {
return new CView_BaseCodeEditor(p_viewmodels, p_viewId, p_parentId, p_options);
}
}
CView_CodeEditor.getHelp = function() {
return "A code editor view that supports validation and formatting.";
};
CView_CodeEditor.expectsInterface = function() {
return [
{
"mandatory": ["setTextData", "getTextData"]
}
];
};
CView_CodeEditor.getCustomDataSchema = function() {
var schema = {
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Custom data for CView_CodeEditor",
"type": "object",
"properties": {
"editorType": {
"description": "The type of the editor used for syntax highlighting and formaatting.",
"type": "string",
"enum": ["html", "css", "javascript", "json"]
},
"readOnly": {
"description": "Whether we want to allow editing.",
"type": "boolean",
"format": "checkbox",
"default": true
},
"headerText": {
"description": "The title of the editor.",
"type": "string"
},
"formatAllowed": {
"description": "Whether we want to allow formatting.",
"type": "boolean",
"format": "checkbox",
"default": true
},
"manualSaveRequired": {
"description": "Whether we must press the save button to save the data.",
"type": "boolean",
"format": "checkbox",
"default": true
},
"closeable": {
"description": "Whether we want to allow closing the editor.",
"type": "boolean",
"format": "checkbox",
"default": true
},
"alwaysRefresh": {
"description": "Always refresh the editor, not only on full refresh.",
"type": "boolean",
"format": "checkbox",
"default": true
},
"disableRefreshOnFocus": {
"description": "Disables refresh when focused.",
"type": "boolean",
"format": "checkbox",
"default": true
},
"focusEditorOnOpen": {
"description": "Whether we want to focus the editor when opening it.",
"type": "boolean",
"format": "checkbox",
"default": true
},
"draggable": {
"description": "Whether we want the editor to be draggable.",
"type": "boolean",
"format": "checkbox",
"default": true
},
"offset": {
"description": "The offset of the editor. Only works with draggable.",
"type": "object",
"properties": {
"top": {
"type": "integer"
},
"left": {
"type": "integer"
}
}
}
},
"additionalProperties": false
};
$.extend(true, schema, ViewUtils.commonViewSchema);
return schema;
};
function CView_BaseCodeEditor(p_viewmodels, p_viewId, p_parentId, p_options) {
"use strict";
var v_parentId = p_parentId;
var v_viewId = p_viewId;
var v_viewmodel = ViewUtils.getViewmodelsFromExpectedInterface(p_viewmodels, CView_CodeEditor)[0];
var v_options = p_options;
var v_callback_onDataChanged;
var v_editor;
var v_editorDiv;
var v_name = "";
var v_enabled = true;
if (v_options.headerText != undefined) {
v_name = v_options.headerText;
}
var v_this = this;
this.EDITOROPTIONS = {
lineNumbers: true,
smartIndent: true,
indentUnit: 4,
lineWrapping: false,
foldGutter: true,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
matchBrackets: true,
autoCloseBrackets: true,
highlightSelectionMatches: true,
styleActiveLine: true,
readOnly: v_options.readOnly
};
this.isValid = function() {
return true;
};
this.format = function(text) {
return text;
};
this.applicationCreated = function() {
createHtml();
setupCallbacks();
open();
};
this.onDataChanged = function(callback) {
v_callback_onDataChanged = callback;
}
function createHtml() {
$("#" + v_parentId).append('<div id="' + v_viewId + '" class="CodeEditor"></div>');
v_editorDiv = $("#" + v_viewId);
v_editorDiv.append(
'<div id="' + v_viewId + '_Header" class="CodeEditor_Header">' +
'<h3>' + v_name + '</h3>' +
'<button id="' + v_viewId + '_Format" class="CodeEditor_Format">Format</button>' +
'<button id="' + v_viewId + '_Save" class="CodeEditor_Save">Save</button>' +
'<button id="' + v_viewId + '_Close" class="CodeEditor_Close">X</button>' +
'</div>' +
'<div id="' + v_viewId + '_Editor" class="CodeEditor_Editor"></div>'
);
v_editor = new CodeMirror(document.getElementById(v_viewId + "_Editor"), v_this.EDITOROPTIONS);
if (!v_options.closeable) {
$('#' + v_viewId + '_Close').hide();
}
if (!v_options.formatAllowed) {
$('#' + v_viewId + '_Format').hide();
}
if (!v_options.manualSaveRequired) {
$('#' + v_viewId + '_Save').hide();
}
v_editor.setSize("100%", "100%");
}
function onChanges() {
var currentValue = v_editor.getValue();
if (v_callback_onDataChanged) {
var newValue = v_callback_onDataChanged(currentValue);
if (currentValue !== newValue) {
currentValue = newValue;
v_editor.setValue(currentValue);
return;
}
}
var isValidJSON = v_this.isValid(currentValue);
refreshBorder(isValidJSON);
if (!v_options.manualSaveRequired && isValidJSON) {
v_viewmodel.setTextData(currentValue);
}
}
function setupCallbacks() {
v_editor.on('changes', onChanges);
v_editor.on('focus', function() {
v_editorDiv.addClass('EditorFocused')
if (v_options.disableRefreshOnFocus){
v_enabled = false;
}
});
v_editor.on('blur', function() {
v_editorDiv.removeClass('EditorFocused')
v_enabled = true;
});
if (v_options.formatAllowed) {
$("#" + v_viewId + "_Format").click(function() {
if (v_this.isValid(v_editor.getValue())) {
v_editor.setValue(v_this.format(v_editor.getValue()));
}
});
}
if (v_options.manualSaveRequired) {
$("#" + v_viewId + "_Save").click(function() {
v_viewmodel.setTextData(v_editor.getValue());
});
}
if (v_options.closeable) {
$("#" + v_viewId + "_Close").click(function() {
v_editorDiv.remove();
});
}
if (v_options.draggable) {
var handle = $("#" + v_viewId + "_Header");
handle.css("cursor", "move");
v_editorDiv.css("position", "absolute");
v_editorDiv.draggable({
containment: [$("#" + v_parentId).offset().left, $("#" + v_parentId).offset().top, 20000, 20000],
scroll: true,
handle: handle
}).resizable({
handles: "se",
resize: function() {}
});
v_editorDiv.on({
dragstop: function(event) {
v_editor.focus();
},
click: function(event) {
v_editor.focus();
},
keydown: function(event) {
if (event.keyCode == 27) {
v_editorDiv.remove();
}
event.stopPropagation();
}
});
}
}
function changeEditor(text, color, border) {
$("#" + v_viewId + "_Header > label").text(text);
$("#" + v_viewId + "_Header").css("color", color);
$("#" + v_viewId).css("border-color", border);
}
function open() {
changeEditor(v_name, "black", "#DDDDDD");
if (v_options.draggable && v_options.offset != undefined) {
v_editorDiv.offset(v_options.offset);
// in IE and chrome we need to set the offset twice so it gets calculated correctly
v_editorDiv.offset(v_options.offset);
}
if (v_options.focusEditorOnOpen) {
v_editor.focus();
}
};
function refreshBorder(valid) {
if (!valid) {
changeEditor("INVALID DATA: " + v_name, "red", "red");
} else {
changeEditor(v_name, "black", "#DDDDDD");
}
}
this.refresh = function(p_fullRefresh) {
function valueArrived(value) {
var scrollInfo = v_editor.getScrollInfo();
v_editor.off('changes', onChanges);
v_editor.setValue(value);
v_editor.on('changes', onChanges);
v_editor.scrollTo(scrollInfo.left, scrollInfo.top);
refreshBorder(v_this.isValid(value));
}
if (v_enabled && (p_fullRefresh || v_options.alwaysRefresh)) {
v_viewmodel.getTextData(valueArrived);
}
};
}
function CView_JSONCodeEditor(p_viewmodels, p_mainId, p_parentId, p_options) {
"use strict";
var editor = new CView_BaseCodeEditor(p_viewmodels, p_mainId, p_parentId, p_options);
editor.EDITOROPTIONS.mode = "javascript";
editor.format = function(text) {
var rawData = JSON.parse(text);
var formattedText = JSON.stringify(rawData, null, 4);
return formattedText;
};
editor.isValid = function(text) {
try {
JSON.parse(text);
return true;
} catch (e) {
return false;
}
};
return editor;
}
function CView_HtmlEditor(p_viewmodels, p_mainId, p_parentId, p_options) {
"use strict";
var editor = new CView_BaseCodeEditor(p_viewmodels, p_mainId, p_parentId, p_options);
editor.EDITOROPTIONS.mode = "xml";
editor.format = function(text) {
var parser = new DOMParser();
var doc = parser.parseFromString('<DIV>' + text + '</DIV>', "text/xml");
return doc.documentElement.innerHTML;
};
editor.isValid = function(text) {
function hasUniqueIds(doc) {
var result = true;
var elements_with_id = doc.querySelectorAll("*[id]");
for (var i = 0; result && (i < elements_with_id.length); i++) {
if (!/\S/.test(elements_with_id[i].getAttribute("id"))) { // There is an ID that is empty.
return false;
}
for (var j = i+1; result && (j < elements_with_id.length); j++) {
result = (elements_with_id[i].getAttribute("id") !== elements_with_id[j].getAttribute("id"));
}
}
return result;
}
try {
var parser = new DOMParser();
var doc = parser.parseFromString('<DIV>' + text + '</DIV>', "text/xml");
return hasUniqueIds(doc) && doc.getElementsByTagName("parsererror").length === 0;
} catch (e) {
return false;
}
};
return editor;
}
function CView_CssEditor(p_viewmodels, p_mainId, p_parentId, p_options) {
"use strict";
var editor = new CView_BaseCodeEditor(p_viewmodels, p_mainId, p_parentId, p_options);
editor.EDITOROPTIONS.mode = "css";
return editor;
}
function CView_JavascriptEditor(p_viewmodels, p_mainId, p_parentId, p_options) {
"use strict";
var editor = new CView_BaseCodeEditor(p_viewmodels, p_mainId, p_parentId, p_options);
editor.EDITOROPTIONS.mode = "javascript";
return editor;
}
//# sourceURL=WebApplicationFramework\Views\View_CodeEditor.js