TiddlyWiki5/plugins/tiddlywiki/codemirror/edit-codemirror.js

211 wiersze
5.7 KiB
JavaScript

/*\
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;
})();