1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

merge dev

This commit is contained in:
Hiroyasu Nishiyama 2018-12-11 19:02:49 +09:00
commit 0e2d0e1b6f
22 changed files with 241 additions and 159 deletions

View File

@ -445,7 +445,17 @@ module.exports = function(grunt) {
destination: 'docs', destination: 'docs',
configure: './jsdoc.json' configure: './jsdoc.json'
} }
},
editor: {
src: [
'packages/node_modules/@node-red/editor-client/src/js'
],
options: {
destination: 'packages/node_modules/@node-red/editor-client/docs',
configure: './jsdoc.json'
}
} }
}, },
jsdoc2md: { jsdoc2md: {
runtimeAPI: { runtimeAPI: {

View File

@ -27,8 +27,7 @@
"status": "Status", "status": "Status",
"enabled": "Enabled", "enabled": "Enabled",
"disabled":"Disabled", "disabled":"Disabled",
"info": "Description", "info": "Description"
"tip": "Description accepts Markdown and will appear in the Info tab."
}, },
"menu": { "menu": {
"label": { "label": {
@ -279,7 +278,6 @@
"deleteSubflow": "delete subflow", "deleteSubflow": "delete subflow",
"info": "Description", "info": "Description",
"category": "Category", "category": "Category",
"format":"markdown format",
"errors": { "errors": {
"noNodesSelected": "<strong>Cannot create subflow</strong>: no nodes selected", "noNodesSelected": "<strong>Cannot create subflow</strong>: no nodes selected",
"multipleInputsToSelection": "<strong>Cannot create subflow</strong>: multiple inputs to selection" "multipleInputsToSelection": "<strong>Cannot create subflow</strong>: multiple inputs to selection"
@ -719,7 +717,8 @@
"format": "format JSON" "format": "format JSON"
}, },
"markdownEditor": { "markdownEditor": {
"title": "Markdown editor" "title": "Markdown editor",
"format": "Formatted with markdown"
}, },
"bufferEditor": { "bufferEditor": {
"title": "Buffer editor", "title": "Buffer editor",

View File

@ -27,8 +27,7 @@
"status": "状態", "status": "状態",
"enabled": "有効", "enabled": "有効",
"disabled": "無効", "disabled": "無効",
"info": "詳細", "info": "詳細"
"tip": "マークダウン形式で記述した「詳細」は「情報タブ」に表示されます。"
}, },
"menu": { "menu": {
"label": { "label": {
@ -278,7 +277,6 @@
"deleteSubflow": "サブフローを削除", "deleteSubflow": "サブフローを削除",
"info": "詳細", "info": "詳細",
"category": "カテゴリ", "category": "カテゴリ",
"format": "マークダウン形式",
"errors": { "errors": {
"noNodesSelected": "<strong>サブフローを作成できません</strong>: ノードが選択されていません", "noNodesSelected": "<strong>サブフローを作成できません</strong>: ノードが選択されていません",
"multipleInputsToSelection": "<strong>サブフローを作成できません</strong>: 複数の入力が選択されています" "multipleInputsToSelection": "<strong>サブフローを作成できません</strong>: 複数の入力が選択されています"

View File

@ -22,8 +22,7 @@
"status": "状态", "status": "状态",
"enabled": "有效", "enabled": "有效",
"disabled": "无效", "disabled": "无效",
"info": "详细描述", "info": "详细描述"
"tip": "详细描述支持Markdown轻量级标记语言并将出现在信息标签中。"
}, },
"menu": { "menu": {
"label": { "label": {
@ -191,7 +190,6 @@
"output": "输出:", "output": "输出:",
"deleteSubflow": "删除子流程", "deleteSubflow": "删除子流程",
"info": "详细描述", "info": "详细描述",
"format": "标记格式",
"errors": { "errors": {
"noNodesSelected": "<strong>无法创建子流程</strong>: 未选择节点", "noNodesSelected": "<strong>无法创建子流程</strong>: 未选择节点",
"multipleInputsToSelection": "<strong>无法创建子流程</strong>: 多个输入到了选择" "multipleInputsToSelection": "<strong>无法创建子流程</strong>: 多个输入到了选择"

View File

@ -1242,7 +1242,7 @@ RED.text.format = (function() {
element.dispatchEvent(event); element.dispatchEvent(event);
return; return;
} }
var range = selection.getRangeAt(0); var range = selection.getRangeAt(0);
var tempRange = range.cloneRange(), startNode, startOffset; var tempRange = range.cloneRange(), startNode, startOffset;
startNode = range.startContainer; startNode = range.startContainer;
@ -1304,7 +1304,7 @@ RED.text.format = (function() {
} }
return { return {
/** /*!
* Returns the HTML representation of a given structured text * Returns the HTML representation of a given structured text
* @param text - the structured text * @param text - the structured text
* @param type - could be one of filepath, url, email * @param type - could be one of filepath, url, email
@ -1315,7 +1315,7 @@ RED.text.format = (function() {
getHtml: function (text, type, args, isRtl, locale) { getHtml: function (text, type, args, isRtl, locale) {
return getHandler(type).format(text, args, isRtl, true, locale); return getHandler(type).format(text, args, isRtl, true, locale);
}, },
/** /*!
* Handle Structured text correct display for a given HTML element. * Handle Structured text correct display for a given HTML element.
* @param element - the element : should be of type div contenteditable=true * @param element - the element : should be of type div contenteditable=true
* @param type - could be one of filepath, url, email * @param type - could be one of filepath, url, email

View File

@ -38,7 +38,7 @@ RED.popover = (function() {
var direction = options.direction || "right"; var direction = options.direction || "right";
var trigger = options.trigger; var trigger = options.trigger;
var content = options.content; var content = options.content;
var delay = options.delay; var delay = options.delay || { show: 750, hide: 50 };
var autoClose = options.autoClose; var autoClose = options.autoClose;
var width = options.width||"auto"; var width = options.width||"auto";
var size = options.size||"default"; var size = options.size||"default";
@ -172,6 +172,18 @@ RED.popover = (function() {
openPopup(); openPopup();
} }
}); });
if (autoClose) {
target.on('mouseleave disabled', function(e) {
if (timer) {
clearTimeout(timer);
}
if (active) {
active = false;
setTimeout(closePopup,autoClose);
}
});
}
} else if (trigger === 'modal') { } else if (trigger === 'modal') {
$(document).on('mousedown.modal-popover-close', function (event) { $(document).on('mousedown.modal-popover-close', function (event) {
var target = event.target; var target = event.target;

View File

@ -340,7 +340,7 @@ RED.deploy = (function() {
var unusedConfigNodes = []; var unusedConfigNodes = [];
RED.nodes.eachConfig(function(node) { RED.nodes.eachConfig(function(node) {
if (node.users.length === 0 && (node._def.hasUsers !== false)) { if ((node._def.hasUsers !== false) && (node.users.length === 0)) {
unusedConfigNodes.push(getNodeInfo(node)); unusedConfigNodes.push(getNodeInfo(node));
hasUnusedConfig = true; hasUnusedConfig = true;
} }

View File

@ -13,6 +13,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
**/ **/
/**
* @namespace RED.editor
*/
RED.editor = (function() { RED.editor = (function() {
@ -21,6 +25,8 @@ RED.editor = (function() {
var editing_config_node = null; var editing_config_node = null;
var subflowEditor; var subflowEditor;
var customEditTypes = {};
var editTrayWidthCache = {}; var editTrayWidthCache = {};
function getCredentialsURL(nodeType, nodeID) { function getCredentialsURL(nodeType, nodeID) {
@ -929,7 +935,7 @@ RED.editor = (function() {
function buildDescriptionForm(container,node) { function buildDescriptionForm(container,node) {
var dialogForm = $('<form class="dialog-form form-horizontal" autocomplete="off"></form>').appendTo(container); var dialogForm = $('<form class="dialog-form form-horizontal" autocomplete="off"></form>').appendTo(container);
var toolbarRow = $('<div></div>').appendTo(dialogForm); var toolbarRow = $('<div></div>').appendTo(dialogForm);
var row = $('<div class="form-row node-text-editor-row" style="position:relative; padding-top: 4px; height: calc(100% - 36px);"></div>').appendTo(dialogForm); var row = $('<div class="form-row node-text-editor-row" style="position:relative; padding-top: 4px; height: 100%"></div>').appendTo(dialogForm);
$('<div style="height: 100%" class="node-text-editor" id="node-info-input-info-editor" ></div>').appendTo(row); $('<div style="height: 100%" class="node-text-editor" id="node-info-input-info-editor" ></div>').appendTo(row);
var nodeInfoEditor = RED.editor.createEditor({ var nodeInfoEditor = RED.editor.createEditor({
id: "node-info-input-info-editor", id: "node-info-input-info-editor",
@ -939,26 +945,6 @@ RED.editor = (function() {
if (node.info) { if (node.info) {
nodeInfoEditor.getSession().setValue(node.info, -1); nodeInfoEditor.getSession().setValue(node.info, -1);
} }
var toolbar = RED.editor.types._markdown.buildToolbar(toolbarRow,nodeInfoEditor);
$('<button id="node-info-input-info-expand" class="editor-button" style="float: right;"><i class="fa fa-expand"></i></button>').appendTo(toolbar);
$('#node-info-input-info-expand').click(function(e) {
e.preventDefault();
var value = nodeInfoEditor.getValue();
RED.editor.editMarkdown({
value: value,
width: "Infinity",
cursor: nodeInfoEditor.getCursorPosition(),
complete: function(v,cursor) {
nodeInfoEditor.setValue(v, -1);
nodeInfoEditor.gotoLine(cursor.row+1,cursor.column,false);
setTimeout(function() {
nodeInfoEditor.focus();
},300);
}
})
});
return nodeInfoEditor; return nodeInfoEditor;
} }
@ -2157,7 +2143,7 @@ RED.editor = (function() {
} }
function showTypeEditor(type, options) { function showTypeEditor(type, options) {
if (RED.editor.types.hasOwnProperty(type)) { if (customEditTypes.hasOwnProperty(type)) {
if (editStack.length > 0) { if (editStack.length > 0) {
options.parent = editStack[editStack.length-1].id; options.parent = editStack[editStack.length-1].id;
} }
@ -2166,12 +2152,99 @@ RED.editor = (function() {
options.onclose = function() { options.onclose = function() {
editStack.pop(); editStack.pop();
} }
RED.editor.types[type].show(options); customEditTypes[type].show(options);
} else { } else {
console.log("Unknown type editor:",type); console.log("Unknown type editor:",type);
} }
} }
function createEditor(options) {
var el = options.element || $("#"+options.id)[0];
var toolbarRow = $("<div>").appendTo(el);
el = $("<div>").appendTo(el).addClass("node-text-editor-container")[0];
var editor = ace.edit(el);
editor.setTheme("ace/theme/tomorrow");
var session = editor.getSession();
session.on("changeAnnotation", function () {
var annotations = session.getAnnotations() || [];
var i = annotations.length;
var len = annotations.length;
while (i--) {
if (/doctype first\. Expected/.test(annotations[i].text)) { annotations.splice(i, 1); }
else if (/Unexpected End of file\. Expected/.test(annotations[i].text)) { annotations.splice(i, 1); }
}
if (len > annotations.length) { session.setAnnotations(annotations); }
});
if (options.mode) {
session.setMode(options.mode);
}
if (options.foldStyle) {
session.setFoldStyle(options.foldStyle);
} else {
session.setFoldStyle('markbeginend');
}
if (options.options) {
editor.setOptions(options.options);
} else {
editor.setOptions({
enableBasicAutocompletion:true,
enableSnippets:true,
tooltipFollowsMouse: false
});
}
if (options.readOnly) {
editor.setOption('readOnly',options.readOnly);
editor.container.classList.add("ace_read-only");
}
if (options.hasOwnProperty('lineNumbers')) {
editor.renderer.setOption('showGutter',options.lineNumbers);
}
editor.$blockScrolling = Infinity;
if (options.value) {
session.setValue(options.value,-1);
}
if (options.globals) {
setTimeout(function() {
if (!!session.$worker) {
session.$worker.send("setOptions", [{globals: options.globals, esversion:6, sub:true, asi:true, maxerr:1000}]);
}
},100);
}
if (options.mode === 'ace/mode/markdown') {
$(el).addClass("node-text-editor-container-toolbar");
editor.toolbar = customEditTypes['_markdown'].buildToolbar(toolbarRow,editor);
if (options.expandable !== false) {
var expandButton = $('<button class="editor-button" style="float: right;"><i class="fa fa-expand"></i></button>').appendTo(editor.toolbar);
expandButton.click(function(e) {
e.preventDefault();
var value = editor.getValue();
RED.editor.editMarkdown({
value: value,
width: "Infinity",
cursor: editor.getCursorPosition(),
complete: function(v,cursor) {
editor.setValue(v, -1);
editor.gotoLine(cursor.row+1,cursor.column,false);
setTimeout(function() {
editor.focus();
},300);
}
})
});
}
var helpButton = $('<button class="node-text-editor-help editor-button editor-button-small"><i class="fa fa-question"></i></button>').appendTo($(el).parent());
RED.popover.create({
target: helpButton,
trigger: 'click',
size: "small",
direction: "left",
content: RED._("markdownEditor.format"),
autoClose: 50
});
}
return editor;
}
return { return {
init: function() { init: function() {
@ -2184,14 +2257,7 @@ RED.editor = (function() {
$("#node-dialog-cancel").click(); $("#node-dialog-cancel").click();
$("#node-config-dialog-cancel").click(); $("#node-config-dialog-cancel").click();
}); });
for (var type in RED.editor.types) {
if (RED.editor.types.hasOwnProperty(type)) {
RED.editor.types[type].init();
}
}
}, },
types: {},
edit: showEditDialog, edit: showEditDialog,
editConfig: showEditConfigNodeDialog, editConfig: showEditConfigNodeDialog,
editSubflow: showEditSubflowDialog, editSubflow: showEditSubflowDialog,
@ -2204,57 +2270,32 @@ RED.editor = (function() {
validateNode: validateNode, validateNode: validateNode,
updateNodeProperties: updateNodeProperties, // TODO: only exposed for edit-undo updateNodeProperties: updateNodeProperties, // TODO: only exposed for edit-undo
/**
* Show a type editor.
* @param {string} type - the type to display
* @param {object} options - options for the editor
* @function
* @memberof RED.editor
*/
showTypeEditor: showTypeEditor,
createEditor: function(options) { /**
var editor = ace.edit(options.id||options.element); * Register a type editor.
editor.setTheme("ace/theme/tomorrow"); * @param {string} type - the type name
var session = editor.getSession(); * @param {object} options - the editor definition
session.on("changeAnnotation", function () { * @function
var annotations = session.getAnnotations() || []; * @memberof RED.editor
var i = annotations.length; */
var len = annotations.length; registerTypeEditor: function(type, definition) {
while (i--) { customEditTypes[type] = definition;
if (/doctype first\. Expected/.test(annotations[i].text)) { annotations.splice(i, 1); } },
else if (/Unexpected End of file\. Expected/.test(annotations[i].text)) { annotations.splice(i, 1); }
} /**
if (len > annotations.length) { session.setAnnotations(annotations); } * Create a editor ui component
}); * @param {object} options - the editor options
if (options.mode) { * @function
session.setMode(options.mode); * @memberof RED.editor
} */
if (options.foldStyle) { createEditor: createEditor
session.setFoldStyle(options.foldStyle);
} else {
session.setFoldStyle('markbeginend');
}
if (options.options) {
editor.setOptions(options.options);
} else {
editor.setOptions({
enableBasicAutocompletion:true,
enableSnippets:true,
tooltipFollowsMouse: false
});
}
if (options.readOnly) {
editor.setOption('readOnly',options.readOnly);
editor.container.classList.add("ace_read-only");
}
if (options.hasOwnProperty('lineNumbers')) {
editor.renderer.setOption('showGutter',options.lineNumbers);
}
editor.$blockScrolling = Infinity;
if (options.value) {
session.setValue(options.value,-1);
}
if (options.globals) {
setTimeout(function() {
if (!!session.$worker) {
session.$worker.send("setOptions", [{globals: options.globals, esversion:6, sub:true, asi:true, maxerr:1000}]);
}
},100);
}
return editor;
}
} }
})(); })();

View File

@ -13,8 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
**/ **/
RED.editor.types._buffer = (function() { (function() {
var template = '<script type="text/x-red" data-template-name="_buffer"><div id="node-input-buffer-panels"><div id="node-input-buffer-panel-str" class="red-ui-panel"><div class="form-row" style="margin-bottom: 3px; text-align: right;"><span class="node-input-buffer-type"><i class="fa fa-exclamation-circle"></i> <span id="node-input-buffer-type-string" data-i18n="bufferEditor.modeString"></span><span id="node-input-buffer-type-array" data-i18n="bufferEditor.modeArray"></span></span></div><div class="form-row node-text-editor-row"><div class="node-text-editor" id="node-input-buffer-str"></div></div></div><div id="node-input-buffer-panel-bin" class="red-ui-panel"><div class="form-row node-text-editor-row" style="margin-top: 10px"><div class="node-text-editor" id="node-input-buffer-bin"></div></div></div></div></script>'; var template = '<script type="text/x-red" data-template-name="_buffer"><div id="node-input-buffer-panels"><div id="node-input-buffer-panel-str" class="red-ui-panel"><div class="form-row" style="margin-bottom: 3px; text-align: right;"><span class="node-input-buffer-type"><i class="fa fa-exclamation-circle"></i> <span id="node-input-buffer-type-string" data-i18n="bufferEditor.modeString"></span><span id="node-input-buffer-type-array" data-i18n="bufferEditor.modeArray"></span></span></div><div class="form-row node-text-editor-row"><div class="node-text-editor" id="node-input-buffer-str"></div></div></div><div id="node-input-buffer-panel-bin" class="red-ui-panel"><div class="form-row node-text-editor-row" style="margin-top: 10px"><div class="node-text-editor" id="node-input-buffer-bin"></div></div></div></div></script>';
@ -45,10 +44,7 @@ RED.editor.types._buffer = (function() {
} }
return { var definition = {
init: function() {
$(template).appendTo(document.body);
},
show: function(options) { show: function(options) {
var value = options.value; var value = options.value;
var onComplete = options.complete; var onComplete = options.complete;
@ -206,4 +202,7 @@ RED.editor.types._buffer = (function() {
RED.tray.show(trayOptions); RED.tray.show(trayOptions);
} }
} }
$(template).appendTo(document.body);
RED.editor.registerTypeEditor("_buffer", definition);
})(); })();

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
**/ **/
RED.editor.types._expression = (function() { (function() {
var template = '<script type="text/x-red" data-template-name="_expression">'+ var template = '<script type="text/x-red" data-template-name="_expression">'+
@ -46,10 +46,7 @@ RED.editor.types._expression = (function() {
'</script>'; '</script>';
var expressionTestCache = {}; var expressionTestCache = {};
return { var definition = {
init: function() {
$(template).appendTo(document.body);
},
show: function(options) { show: function(options) {
var expressionTestCacheId = options.parent||"_"; var expressionTestCacheId = options.parent||"_";
var value = options.value; var value = options.value;
@ -349,4 +346,6 @@ RED.editor.types._expression = (function() {
RED.tray.show(trayOptions); RED.tray.show(trayOptions);
} }
} }
$(template).appendTo(document.body);
RED.editor.registerTypeEditor("_expression", definition);
})(); })();

View File

@ -13,15 +13,12 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
**/ **/
RED.editor.types._js = (function() { (function() {
var template = '<script type="text/x-red" data-template-name="_js"><div class="form-row node-text-editor-row"><div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-js"></div></div></script>'; var template = '<script type="text/x-red" data-template-name="_js"><div class="form-row node-text-editor-row"><div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-js"></div></div></script>';
return { var definition = {
init: function() {
$(template).appendTo(document.body);
},
show: function(options) { show: function(options) {
var value = options.value; var value = options.value;
var onComplete = options.complete; var onComplete = options.complete;
@ -99,4 +96,7 @@ RED.editor.types._js = (function() {
RED.tray.show(trayOptions); RED.tray.show(trayOptions);
} }
} }
$(template).appendTo(document.body);
RED.editor.registerTypeEditor("_js", definition);
})(); })();

View File

@ -13,15 +13,12 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
**/ **/
RED.editor.types._json = (function() { (function() {
var template = '<script type="text/x-red" data-template-name="_json"><div class="form-row" style="margin-bottom: 3px; text-align: right;"><button id="node-input-json-reformat" class="editor-button editor-button-small"><span data-i18n="jsonEditor.format"></span></button></div><div class="form-row node-text-editor-row"><div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-json"></div></div></script>'; var template = '<script type="text/x-red" data-template-name="_json"><div class="form-row" style="margin-bottom: 3px; text-align: right;"><button id="node-input-json-reformat" class="editor-button editor-button-small"><span data-i18n="jsonEditor.format"></span></button></div><div class="form-row node-text-editor-row"><div style="height: 200px;min-height: 150px;" class="node-text-editor" id="node-input-json"></div></div></script>';
return { var definition = {
init: function() {
$(template).appendTo(document.body);
},
show: function(options) { show: function(options) {
var value = options.value; var value = options.value;
var onComplete = options.complete; var onComplete = options.complete;
@ -115,4 +112,6 @@ RED.editor.types._json = (function() {
RED.tray.show(trayOptions); RED.tray.show(trayOptions);
} }
} }
$(template).appendTo(document.body);
RED.editor.registerTypeEditor("_json", definition);
})(); })();

View File

@ -13,8 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
**/ **/
RED.editor.types._markdown = (function() { (function() {
var toolbarTemplate = '<div style="margin-bottom: 5px">'+ var toolbarTemplate = '<div style="margin-bottom: 5px">'+
'<span class="button-group">'+ '<span class="button-group">'+
@ -41,7 +40,7 @@ RED.editor.types._markdown = (function() {
'<div id="node-input-markdown-panel-editor" class="red-ui-panel">'+ '<div id="node-input-markdown-panel-editor" class="red-ui-panel">'+
'<div style="height: 100%; margin: auto; max-width: 1000px;">'+ '<div style="height: 100%; margin: auto; max-width: 1000px;">'+
'<div id="node-input-markdown-toolbar"></div>'+ '<div id="node-input-markdown-toolbar"></div>'+
'<div class="node-text-editor" style="height: calc(100% - 50px)" id="node-input-markdown"></div>'+ '<div class="node-text-editor" style="height: 100%" id="node-input-markdown"></div>'+
'</div>'+ '</div>'+
'</div>'+ '</div>'+
'<div class="red-ui-panel">'+ '<div class="red-ui-panel">'+
@ -66,10 +65,7 @@ RED.editor.types._markdown = (function() {
'hr': { before:"\n---\n\n", tooltip: "Horizontal rule" } 'hr': { before:"\n---\n\n", tooltip: "Horizontal rule" }
} }
return { var definition = {
init: function() {
$(template).appendTo(document.body);
},
show: function(options) { show: function(options) {
var value = options.value; var value = options.value;
var onComplete = options.complete; var onComplete = options.complete;
@ -112,7 +108,8 @@ RED.editor.types._markdown = (function() {
expressionEditor = RED.editor.createEditor({ expressionEditor = RED.editor.createEditor({
id: 'node-input-markdown', id: 'node-input-markdown',
value: value, value: value,
mode:"ace/mode/markdown" mode:"ace/mode/markdown",
expandable: false
}); });
var changeTimer; var changeTimer;
expressionEditor.getSession().on("change", function() { expressionEditor.getSession().on("change", function() {
@ -138,11 +135,10 @@ RED.editor.types._markdown = (function() {
} }
}); });
panels.ratio(1); panels.ratio(1);
var toolbar = RED.editor.types._markdown.buildToolbar($("#node-input-markdown-toolbar"), expressionEditor);
$('<span class="button-group" style="float:right">'+ $('<span class="button-group" style="float:right">'+
'<button id="node-btn-markdown-preview" class="editor-button toggle single"><i class="fa fa-eye"></i></button>'+ '<button id="node-btn-markdown-preview" class="editor-button toggle single"><i class="fa fa-eye"></i></button>'+
'</span>').appendTo(toolbar); '</span>').appendTo(expressionEditor.toolbar);
$("#node-btn-markdown-preview").click(function(e) { $("#node-btn-markdown-preview").click(function(e) {
e.preventDefault(); e.preventDefault();
@ -212,4 +208,6 @@ RED.editor.types._markdown = (function() {
return toolbar; return toolbar;
} }
} }
$(template).appendTo(document.body);
RED.editor.registerTypeEditor("_markdown", definition);
})(); })();

View File

@ -146,7 +146,6 @@ RED.workspaces = (function() {
height -= $(rows[i]).outerHeight(true); height -= $(rows[i]).outerHeight(true);
} }
height -= (parseInt($("#dialog-form").css("marginTop"))+parseInt($("#dialog-form").css("marginBottom"))); height -= (parseInt($("#dialog-form").css("marginTop"))+parseInt($("#dialog-form").css("marginBottom")));
height -= 28;
$(".node-text-editor").css("height",height+"px"); $(".node-text-editor").css("height",height+"px");
tabflowEditor.resize(); tabflowEditor.resize();
}, },
@ -166,7 +165,6 @@ RED.workspaces = (function() {
var row = $('<div class="form-row node-text-editor-row">'+ var row = $('<div class="form-row node-text-editor-row">'+
'<label for="node-input-info" data-i18n="editor:workspace.info" style="width:300px;"></label>'+ '<label for="node-input-info" data-i18n="editor:workspace.info" style="width:300px;"></label>'+
'<div class="node-text-editor-toolbar"></div>'+
'<div style="min-height:250px;" class="node-text-editor" id="node-input-info"></div>'+ '<div style="min-height:250px;" class="node-text-editor" id="node-input-info"></div>'+
'</div>').appendTo(dialogForm); '</div>').appendTo(dialogForm);
tabflowEditor = RED.editor.createEditor({ tabflowEditor = RED.editor.createEditor({
@ -175,10 +173,6 @@ RED.workspaces = (function() {
value: "" value: ""
}); });
var toolbar = RED.editor.types._markdown.buildToolbar(row.find(".node-text-editor-toolbar"),tabflowEditor);
$('<button id="node-info-input-info-expand" class="editor-button" style="float: right;"><i class="fa fa-expand"></i></button>').appendTo(toolbar);
$('#node-info-input-info-expand').click(function(e) { $('#node-info-input-info-expand').click(function(e) {
e.preventDefault(); e.preventDefault();
var value = tabflowEditor.getValue(); var value = tabflowEditor.getValue();

View File

@ -209,11 +209,28 @@
} }
.node-text-editor { .node-text-editor {
position: relative;
.node-text-editor-help {
position: absolute;
bottom: 0px;
right: 1px;
border-bottom-right-radius: 5px;
z-Index: 8;
border-bottom: none;
border-right: none;
}
}
.node-text-editor-container {
border:1px solid #ccc; border:1px solid #ccc;
border-radius:5px; border-radius:5px;
overflow: hidden; overflow: hidden;
font-size: 14px !important; font-size: 14px !important;
font-family: Menlo, Consolas, 'DejaVu Sans Mono', Courier, monospace !important; font-family: Menlo, Consolas, 'DejaVu Sans Mono', Courier, monospace !important;
height: 100%;
&.node-text-editor-container-toolbar {
height: calc(100% - 40px);
}
} }
.editor-button { .editor-button {
@ -333,7 +350,7 @@
padding: 10px; padding: 10px;
border:1px solid #ccc; border:1px solid #ccc;
border-radius:5px; border-radius:5px;
height: calc(100% - 31px); height: calc(100% - 21px);
overflow-y: scroll; overflow-y: scroll;
background: #fff; background: #fff;
} }

View File

@ -1,17 +1,13 @@
<script type="text/x-red" data-template-name="comment"> <script type="text/x-red" data-template-name="comment">
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-comment"></i> <span data-i18n="comment.label.title"></span></label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name"> <input type="text" id="node-input-name">
</div> </div>
<div class="form-row" style="margin-bottom: 0px;">
<label for="node-input-info" style="width: 100% !important;"><i class="fa fa-comments"></i> <span data-i18n="comment.label.body"></span></label>
<input type="hidden" id="node-input-info" autofocus="autofocus">
</div>
<div class="form-row node-text-editor-row"> <div class="form-row node-text-editor-row">
<input type="hidden" id="node-input-info" autofocus="autofocus">
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-info-editor"></div> <div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-info-editor"></div>
</div> </div>
<div class="form-tips" data-i18n="[html]comment.tip"></div>
</script> </script>
<script type="text/javascript"> <script type="text/javascript">
@ -32,7 +28,7 @@
return this.name?"node_label_italic":""; return this.name?"node_label_italic":"";
}, },
info: function() { info: function() {
return (this.name?"# "+this.name+"\n":"")+(this.info||""); return this.name?"# "+this.name+"\n\n---\n\n":"";
}, },
oneditprepare: function() { oneditprepare: function() {
var that = this; var that = this;

View File

@ -56,6 +56,7 @@ module.exports = function(RED) {
RED.util.setMessageProperty(msg,node.property,JSON.parse(value)); RED.util.setMessageProperty(msg,node.property,JSON.parse(value));
if (validate) { if (validate) {
if (this.compiledSchema(msg[node.property])) { if (this.compiledSchema(msg[node.property])) {
delete msg.schema;
node.send(msg); node.send(msg);
} else { } else {
msg.schemaError = this.compiledSchema.errors; msg.schemaError = this.compiledSchema.errors;
@ -70,6 +71,7 @@ module.exports = function(RED) {
// If node.action is str and value is str // If node.action is str and value is str
if (validate) { if (validate) {
if (this.compiledSchema(JSON.parse(msg[node.property]))) { if (this.compiledSchema(JSON.parse(msg[node.property]))) {
delete msg.schema;
node.send(msg); node.send(msg);
} else { } else {
msg.schemaError = this.compiledSchema.errors; msg.schemaError = this.compiledSchema.errors;
@ -87,6 +89,7 @@ module.exports = function(RED) {
if (validate) { if (validate) {
if (this.compiledSchema(value)) { if (this.compiledSchema(value)) {
RED.util.setMessageProperty(msg,node.property,JSON.stringify(value,null,node.indent)); RED.util.setMessageProperty(msg,node.property,JSON.stringify(value,null,node.indent));
delete msg.schema;
node.send(msg); node.send(msg);
} else { } else {
msg.schemaError = this.compiledSchema.errors; msg.schemaError = this.compiledSchema.errors;
@ -104,6 +107,7 @@ module.exports = function(RED) {
// If node.action is obj and value is object // If node.action is obj and value is object
if (validate) { if (validate) {
if (this.compiledSchema(value)) { if (this.compiledSchema(value)) {
delete msg.schema;
node.send(msg); node.send(msg);
} else { } else {
msg.schemaError = this.compiledSchema.errors; msg.schemaError = this.compiledSchema.errors;

View File

@ -309,12 +309,7 @@
} }
}, },
"comment": { "comment": {
"comment": "comment", "comment": "comment"
"label": {
"title": "Title",
"body": "Body"
},
"tip": "Tip: The body text can be styled as <a href=\"https://help.github.com/articles/markdown-basics/\" target=\"_blank\">GitHub flavoured Markdown</a>"
}, },
"unknown": { "unknown": {
"label": { "label": {

View File

@ -21,7 +21,8 @@
<dt>payload<span class="property-type">object | string</span></dt> <dt>payload<span class="property-type">object | string</span></dt>
<dd>A JavaScript object or JSON string.</dd> <dd>A JavaScript object or JSON string.</dd>
<dt>schema<span class="property-type">object</span></dt> <dt>schema<span class="property-type">object</span></dt>
<dd>An optional JSON Schema object to validate the payload against.</dd> <dd>An optional JSON Schema object to validate the payload against.
The property will be deleted before the <code>msg</code> is sent to the next node.</dd>
</dl> </dl>
<h3>Outputs</h3> <h3>Outputs</h3>
<dl class="message-properties"> <dl class="message-properties">

View File

@ -309,12 +309,7 @@
} }
}, },
"comment": { "comment": {
"comment": "comment", "comment": "comment"
"label": {
"title": "タイトル",
"body": "本文"
},
"tip": "注釈: 本文は<a href=\"https://help.github.com/articles/markdown-basics/\" target=\"_blank\">GitHubのMarkdown形式</a>として整形されます。"
}, },
"unknown": { "unknown": {
"label": { "label": {

View File

@ -297,11 +297,6 @@
} }
}, },
"comment": { "comment": {
"label": {
"title": "标题",
"body": "主体"
},
"tip": "提示: 主题内容可被格式化为 <a href=\"https://help.github.com/articles/markdown-basics/\" target=\"_blank\">GitHub风格的Markdown</a>"
}, },
"unknown": { "unknown": {
"label": { "label": {

View File

@ -433,4 +433,36 @@ describe('JSON node', function() {
} }
}); });
}); });
it('msg.schema property should be deleted before sending to next node (string input)', function(done) {
var flow = [{id:"jn1",type:"json",action:"str",wires:[["jn2"]]},
{id:"jn2", type:"helper"}];
helper.load(jsonNode, flow, function() {
var jn1 = helper.getNode("jn1");
var jn2 = helper.getNode("jn2");
jn2.on("input", function(msg) {
should.equal(msg.schema, undefined);
done();
});
var jsonString = '{"number":3,"string":"allo"}';
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
jn1.receive({payload:jsonString, schema:schema});
});
});
it('msg.schema property should be deleted before sending to next node (object input)', function(done) {
var flow = [{id:"jn1",type:"json",action:"str",wires:[["jn2"]]},
{id:"jn2", type:"helper"}];
helper.load(jsonNode, flow, function() {
var jn1 = helper.getNode("jn1");
var jn2 = helper.getNode("jn2");
jn2.on("input", function(msg) {
should.equal(msg.schema, undefined);
done();
});
var jsonObject = {"number":3,"string":"allo"};
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
jn1.receive({payload:jsonObject, schema:schema});
});
});
}); });