mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-23 18:17:20 +00:00
Refactor codemirror plugin
It no longer overrides the edit-text widget. Instead we use the editor type mappings to select which content types should be handled by which editor.
This commit is contained in:
parent
0bdc5b5c70
commit
1717c93d00
10
plugins/tiddlywiki/codemirror/EditorTypeMappings.multids
Normal file
10
plugins/tiddlywiki/codemirror/EditorTypeMappings.multids
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
title: $:/config/EditorTypeMappings/
|
||||||
|
|
||||||
|
application/javascript: codemirror
|
||||||
|
application/json: codemirror
|
||||||
|
application/x-tiddler-dictionary: codemirror
|
||||||
|
text/css: codemirror
|
||||||
|
text/html: codemirror
|
||||||
|
text/plain: codemirror
|
||||||
|
text/vnd.tiddlywiki: codemirror
|
||||||
|
text/x-tiddlywiki: codemirror
|
@ -1,92 +0,0 @@
|
|||||||
/*\
|
|
||||||
title: $:/core/modules/widgets/edit-text-codemirror.js
|
|
||||||
type: application/javascript
|
|
||||||
module-type: widget
|
|
||||||
|
|
||||||
Extend the edit-text widget to use CodeMirror
|
|
||||||
|
|
||||||
\*/
|
|
||||||
(function(){
|
|
||||||
|
|
||||||
/*jslint node: true, browser: true */
|
|
||||||
/*global $tw: false */
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
var CODEMIRROR_OPTIONS = "$:/config/CodeMirror", configOptions;
|
|
||||||
/*
|
|
||||||
e.g. to allow vim key bindings
|
|
||||||
{
|
|
||||||
"require": [
|
|
||||||
"$:/plugins/tiddlywiki/codemirror/addon/dialog/dialog.js",
|
|
||||||
"$:/plugins/tiddlywiki/codemirror/addon/search/searchcursor.js",
|
|
||||||
"$:/plugins/tiddlywiki/codemirror/keymap/vim.js"
|
|
||||||
],
|
|
||||||
"configuration": {
|
|
||||||
"keyMap": "vim",
|
|
||||||
"showCursorWhenSelecting": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
var EditTextWidget = require("$:/core/modules/widgets/edit-text.js")["edit-text"];
|
|
||||||
|
|
||||||
if($tw.browser) {
|
|
||||||
window.CodeMirror = require("$:/plugins/tiddlywiki/codemirror/lib/codemirror.js");
|
|
||||||
|
|
||||||
configOptions = $tw.wiki.getTiddlerData(CODEMIRROR_OPTIONS,{});
|
|
||||||
|
|
||||||
if(configOptions) {
|
|
||||||
if(configOptions["require"]) {
|
|
||||||
if($tw.utils.isArray(configOptions["require"])) {
|
|
||||||
for (var index=0; index < configOptions["require"].length; index++) {
|
|
||||||
require(configOptions["require"][index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
require(configOptions["require"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EditTextWidget.configuration = configOptions["configuration"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
The edit-text widget calls this method just after inserting its dom nodes
|
|
||||||
*/
|
|
||||||
EditTextWidget.prototype.postRender = function() {
|
|
||||||
var self = this,
|
|
||||||
cm, config, cv, cm_opts = {
|
|
||||||
lineWrapping: true,
|
|
||||||
lineNumbers: true
|
|
||||||
},
|
|
||||||
tid = this.wiki.getTiddler(this.editTitle);
|
|
||||||
if(tid && tid.fields.type) {
|
|
||||||
cm_opts.mode = tid.fields.type
|
|
||||||
};
|
|
||||||
|
|
||||||
if($tw.browser && window.CodeMirror && this.editTag === "textarea") {
|
|
||||||
if(EditTextWidget.configuration) {
|
|
||||||
for (cv in EditTextWidget.configuration) { cm_opts[cv] = EditTextWidget.configuration[cv]; }
|
|
||||||
}
|
|
||||||
cm = window.CodeMirror.fromTextArea(this.domNodes[0], cm_opts);
|
|
||||||
cm.on("change",function() {
|
|
||||||
self.saveChanges(cm.getValue());
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
cm = undefined;
|
|
||||||
}
|
|
||||||
this.codemirrorInstance = cm;
|
|
||||||
};
|
|
||||||
|
|
||||||
EditTextWidget.prototype.updateEditor = function(text) {
|
|
||||||
// Replace the edit value if the tiddler we're editing has changed
|
|
||||||
if(this.codemirrorInstance) {
|
|
||||||
if(!this.codemirrorInstance.hasFocus()) {
|
|
||||||
this.codemirrorInstance.setValue(text);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.updateEditorDomNode(this.getEditInfo().value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
})();
|
|
210
plugins/tiddlywiki/codemirror/edit-codemirror.js
Normal file
210
plugins/tiddlywiki/codemirror/edit-codemirror.js
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/widgets/edit-codemirror.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: widget
|
||||||
|
|
||||||
|
Codemirror-based text editor widget
|
||||||
|
|
||||||
|
Config options "$:/config/CodeMirror" e.g. to allow vim key bindings
|
||||||
|
{
|
||||||
|
"require": [
|
||||||
|
"$:/plugins/tiddlywiki/codemirror/addon/dialog/dialog.js",
|
||||||
|
"$:/plugins/tiddlywiki/codemirror/addon/search/searchcursor.js",
|
||||||
|
"$:/plugins/tiddlywiki/codemirror/keymap/vim.js"
|
||||||
|
],
|
||||||
|
"configuration": {
|
||||||
|
"keyMap": "vim",
|
||||||
|
"showCursorWhenSelecting": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var CODEMIRROR_OPTIONS = "$:/config/CodeMirror"
|
||||||
|
|
||||||
|
// Install CodeMirror
|
||||||
|
if($tw.browser && !window.CodeMirror) {
|
||||||
|
window.CodeMirror = require("$:/plugins/tiddlywiki/codemirror/lib/codemirror.js");
|
||||||
|
// Install required CodeMirror plugins
|
||||||
|
var configOptions = $tw.wiki.getTiddlerData(CODEMIRROR_OPTIONS,{}),
|
||||||
|
req = configOptions["require"];
|
||||||
|
if(req) {
|
||||||
|
if($tw.utils.isArray(req)) {
|
||||||
|
for(var index=0; index<req.length; index++) {
|
||||||
|
require(req[index]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
require(req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var MIN_TEXT_AREA_HEIGHT = 100; // Minimum height of textareas in pixels
|
||||||
|
|
||||||
|
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||||
|
|
||||||
|
var EditCodeMirrorWidget = function(parseTreeNode,options) {
|
||||||
|
this.initialise(parseTreeNode,options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Inherit from the base widget class
|
||||||
|
*/
|
||||||
|
EditCodeMirrorWidget.prototype = new Widget();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Render this widget into the DOM
|
||||||
|
*/
|
||||||
|
EditCodeMirrorWidget.prototype.render = function(parent,nextSibling) {
|
||||||
|
var self = this;
|
||||||
|
// Save the parent dom node
|
||||||
|
this.parentDomNode = parent;
|
||||||
|
// Compute our attributes
|
||||||
|
this.computeAttributes();
|
||||||
|
// Execute our logic
|
||||||
|
this.execute();
|
||||||
|
// Get the configuration options for the CodeMirror object
|
||||||
|
var config = $tw.wiki.getTiddlerData(CODEMIRROR_OPTIONS,{}).configuration || {},
|
||||||
|
editInfo = this.getEditInfo();
|
||||||
|
if(!("lineWrapping" in config)) {
|
||||||
|
config.lineWrapping = true;
|
||||||
|
}
|
||||||
|
if(!("lineNumbers" in config)) {
|
||||||
|
config.lineNumbers = true;
|
||||||
|
}
|
||||||
|
config.mode = editInfo.type;
|
||||||
|
config.value = editInfo.value;
|
||||||
|
// Create the CodeMirror instance
|
||||||
|
var cm = window.CodeMirror(function(domNode) {
|
||||||
|
parent.insertBefore(domNode,nextSibling);
|
||||||
|
self.domNodes.push(domNode);
|
||||||
|
},config);
|
||||||
|
// Set up a change event handler
|
||||||
|
cm.on("change",function() {
|
||||||
|
self.saveChanges(cm.getValue());
|
||||||
|
});
|
||||||
|
this.codeMirrorInstance = cm;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get the tiddler being edited and current value
|
||||||
|
*/
|
||||||
|
EditCodeMirrorWidget.prototype.getEditInfo = function() {
|
||||||
|
// Get the edit value
|
||||||
|
var self = this,
|
||||||
|
value,
|
||||||
|
type = "text/plain",
|
||||||
|
update;
|
||||||
|
if(this.editIndex) {
|
||||||
|
value = this.wiki.extractTiddlerDataItem(this.editTitle,this.editIndex,this.editDefault);
|
||||||
|
update = function(value) {
|
||||||
|
var data = self.wiki.getTiddlerData(self.editTitle,{});
|
||||||
|
if(data[self.editIndex] !== value) {
|
||||||
|
data[self.editIndex] = value;
|
||||||
|
self.wiki.setTiddlerData(self.editTitle,data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// Get the current tiddler and the field name
|
||||||
|
var tiddler = this.wiki.getTiddler(this.editTitle);
|
||||||
|
if(tiddler) {
|
||||||
|
// If we've got a tiddler, the value to display is the field string value
|
||||||
|
value = tiddler.getFieldString(this.editField);
|
||||||
|
if(this.editField === "text") {
|
||||||
|
type = tiddler.fields.type || "text/vnd.tiddlywiki";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Otherwise, we need to construct a default value for the editor
|
||||||
|
switch(this.editField) {
|
||||||
|
case "text":
|
||||||
|
value = "Type the text for the tiddler '" + this.editTitle + "'";
|
||||||
|
type = "text/vnd.tiddlywiki";
|
||||||
|
break;
|
||||||
|
case "title":
|
||||||
|
value = this.editTitle;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
value = "";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(this.editDefault !== undefined) {
|
||||||
|
value = this.editDefault;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update = function(value) {
|
||||||
|
var tiddler = self.wiki.getTiddler(self.editTitle),
|
||||||
|
updateFields = {
|
||||||
|
title: self.editTitle
|
||||||
|
};
|
||||||
|
updateFields[self.editField] = value;
|
||||||
|
self.wiki.addTiddler(new $tw.Tiddler(self.wiki.getCreationFields(),tiddler,updateFields,self.wiki.getModificationFields()));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if(this.editType) {
|
||||||
|
type = this.editType;
|
||||||
|
}
|
||||||
|
return {value: value, type: type, update: update};
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Compute the internal state of the widget
|
||||||
|
*/
|
||||||
|
EditCodeMirrorWidget.prototype.execute = function() {
|
||||||
|
// Get our parameters
|
||||||
|
this.editTitle = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
|
||||||
|
this.editField = this.getAttribute("field","text");
|
||||||
|
this.editIndex = this.getAttribute("index");
|
||||||
|
this.editDefault = this.getAttribute("default");
|
||||||
|
this.editType = this.getAttribute("type");
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||||
|
*/
|
||||||
|
EditCodeMirrorWidget.prototype.refresh = function(changedTiddlers) {
|
||||||
|
var changedAttributes = this.computeAttributes();
|
||||||
|
// Completely rerender if any of our attributes have changed
|
||||||
|
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index) {
|
||||||
|
this.refreshSelf();
|
||||||
|
return true;
|
||||||
|
} else if(changedTiddlers[this.editTitle]) {
|
||||||
|
this.updateEditor(this.getEditInfo().value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Update the editor with new text. This method is separate from updateEditorDomNode()
|
||||||
|
so that subclasses can override updateEditor() and still use updateEditorDomNode()
|
||||||
|
*/
|
||||||
|
EditCodeMirrorWidget.prototype.updateEditor = function(text) {
|
||||||
|
this.updateEditorDomNode(text);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Update the editor dom node with new text
|
||||||
|
*/
|
||||||
|
EditCodeMirrorWidget.prototype.updateEditorDomNode = function(text) {
|
||||||
|
if(this.codeMirrorInstance) {
|
||||||
|
if(!this.codeMirrorInstance.hasFocus()) {
|
||||||
|
this.codeMirrorInstance.setValue(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EditCodeMirrorWidget.prototype.saveChanges = function(text) {
|
||||||
|
var editInfo = this.getEditInfo();
|
||||||
|
if(text !== editInfo.value) {
|
||||||
|
editInfo.update(text);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports["edit-codemirror"] = EditCodeMirrorWidget;
|
||||||
|
|
||||||
|
})();
|
@ -1,9 +1,16 @@
|
|||||||
title: $:/plugins/tiddlywiki/codemirror/instructions
|
title: $:/plugins/tiddlywiki/codemirror/instructions
|
||||||
|
|
||||||
! Configuration
|
! Setting ~CodeMirror Content Types
|
||||||
|
|
||||||
* You can configure the CodeMirror plugin by creating a tiddler called [[$:/config/CodeMirror]] containing a JSON configuration object.
|
You can determine which tiddler content types are edited by the ~CodeMirror widget by creating or modifying special tiddlers whose prefix is comprised of the string `$:/config/EditorTypeMappings/` concatenated with the content type. The text of that tiddler gives the editor type to be used (eg, ''text'', ''bitmap'', ''codemirror'').
|
||||||
* The configuration tiddler needs to be `type: application/json`, to take effect.
|
|
||||||
|
The current editor type mappings are shown in [[$:/ControlPanel]] under the "Advanced" tab.
|
||||||
|
|
||||||
|
! ~CodeMirror Configuration
|
||||||
|
|
||||||
|
You can configure the ~CodeMirror plugin by creating a tiddler called [[$:/config/CodeMirror]] containing a JSON configuration object. The configuration tiddler must have its type field set to `application/json` to take effect.
|
||||||
|
|
||||||
|
See http://codemirror.net/ for details of available configuration options.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user