mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-09-20 16:42:02 +00:00
@@ -13,16 +13,22 @@ Edit-bitmap widget
|
||||
"use strict";
|
||||
|
||||
// Default image sizes
|
||||
var DEFAULT_IMAGE_WIDTH = 300,
|
||||
DEFAULT_IMAGE_HEIGHT = 185;
|
||||
var DEFAULT_IMAGE_WIDTH = 600,
|
||||
DEFAULT_IMAGE_HEIGHT = 370;
|
||||
|
||||
// Configuration tiddlers
|
||||
var LINE_WIDTH_TITLE = "$:/config/BitmapEditor/LineWidth",
|
||||
LINE_COLOUR_TITLE = "$:/config/BitmapEditor/Colour";
|
||||
LINE_COLOUR_TITLE = "$:/config/BitmapEditor/Colour",
|
||||
LINE_OPACITY_TITLE = "$:/config/BitmapEditor/Opacity";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var EditBitmapWidget = function(parseTreeNode,options) {
|
||||
// Initialise the editor operations if they've not been done already
|
||||
if(!this.editorOperations) {
|
||||
EditBitmapWidget.prototype.editorOperations = {};
|
||||
$tw.modules.applyMethods("bitmapeditoroperation",this.editorOperations);
|
||||
}
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
@@ -42,7 +48,12 @@ EditBitmapWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.computeAttributes();
|
||||
// Execute our logic
|
||||
this.execute();
|
||||
// Create our element
|
||||
// Create the wrapper for the toolbar and render its content
|
||||
this.toolbarNode = this.document.createElement("div");
|
||||
this.toolbarNode.className = "tc-editor-toolbar";
|
||||
parent.insertBefore(this.toolbarNode,nextSibling);
|
||||
this.domNodes.push(this.toolbarNode);
|
||||
// Create the on-screen canvas
|
||||
this.canvasDomNode = $tw.utils.domMaker("canvas",{
|
||||
document: this.document,
|
||||
"class":"tc-edit-bitmapeditor",
|
||||
@@ -60,29 +71,33 @@ EditBitmapWidget.prototype.render = function(parent,nextSibling) {
|
||||
name: "mouseup", handlerObject: this, handlerMethod: "handleMouseUpEvent"
|
||||
}]
|
||||
});
|
||||
this.widthDomNode = $tw.utils.domMaker("input",{
|
||||
document: this.document,
|
||||
"class":"tc-edit-bitmapeditor-width",
|
||||
eventListeners: [{
|
||||
name: "change", handlerObject: this, handlerMethod: "handleWidthChangeEvent"
|
||||
}]
|
||||
});
|
||||
this.heightDomNode = $tw.utils.domMaker("input",{
|
||||
document: this.document,
|
||||
"class":"tc-edit-bitmapeditor-height",
|
||||
eventListeners: [{
|
||||
name: "change", handlerObject: this, handlerMethod: "handleHeightChangeEvent"
|
||||
}]
|
||||
});
|
||||
// Insert the elements into the DOM
|
||||
// Set the width and height variables
|
||||
this.setVariable("tv-bitmap-editor-width",this.canvasDomNode.width + "px");
|
||||
this.setVariable("tv-bitmap-editor-height",this.canvasDomNode.height + "px");
|
||||
// Render toolbar child widgets
|
||||
this.renderChildren(this.toolbarNode,null);
|
||||
// // Insert the elements into the DOM
|
||||
parent.insertBefore(this.canvasDomNode,nextSibling);
|
||||
parent.insertBefore(this.widthDomNode,nextSibling);
|
||||
parent.insertBefore(this.heightDomNode,nextSibling);
|
||||
this.domNodes.push(this.canvasDomNode,this.widthDomNode,this.heightDomNode);
|
||||
this.domNodes.push(this.canvasDomNode);
|
||||
// Load the image into the canvas
|
||||
if($tw.browser) {
|
||||
this.loadCanvas();
|
||||
}
|
||||
// Add widget message listeners
|
||||
this.addEventListeners([
|
||||
{type: "tm-edit-bitmap-operation", handler: "handleEditBitmapOperationMessage"}
|
||||
]);
|
||||
};
|
||||
|
||||
/*
|
||||
Handle an edit bitmap operation message from the toolbar
|
||||
*/
|
||||
EditBitmapWidget.prototype.handleEditBitmapOperationMessage = function(event) {
|
||||
// Invoke the handler
|
||||
var handler = this.editorOperations[event.param];
|
||||
if(handler) {
|
||||
handler.call(this,event);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -91,13 +106,28 @@ Compute the internal state of the widget
|
||||
EditBitmapWidget.prototype.execute = function() {
|
||||
// Get our parameters
|
||||
this.editTitle = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
|
||||
// Make the child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
/*
|
||||
Note that the bitmap editor intentionally doesn't try to refresh itself because it would be confusing to have the image changing spontaneously while editting it
|
||||
Just refresh the toolbar
|
||||
*/
|
||||
EditBitmapWidget.prototype.refresh = function(changedTiddlers) {
|
||||
return false;
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
/*
|
||||
Set the bitmap size variables and refresh the toolbar
|
||||
*/
|
||||
EditBitmapWidget.prototype.refreshToolbar = function() {
|
||||
// Set the width and height variables
|
||||
this.setVariable("tv-bitmap-editor-width",this.canvasDomNode.width + "px");
|
||||
this.setVariable("tv-bitmap-editor-height",this.canvasDomNode.height + "px");
|
||||
// Refresh each of our child widgets
|
||||
$tw.utils.each(this.children,function(childWidget) {
|
||||
childWidget.refreshSelf();
|
||||
});
|
||||
};
|
||||
|
||||
EditBitmapWidget.prototype.loadCanvas = function() {
|
||||
@@ -112,7 +142,7 @@ EditBitmapWidget.prototype.loadCanvas = function() {
|
||||
self.currCanvas = self.document.createElement("canvas");
|
||||
self.initCanvas(self.currCanvas,currImage.width,currImage.height,currImage);
|
||||
// Set the width and height input boxes
|
||||
self.updateSize();
|
||||
self.refreshToolbar();
|
||||
};
|
||||
currImage.onerror = function() {
|
||||
// Set the on-screen canvas size and clear it
|
||||
@@ -121,7 +151,7 @@ EditBitmapWidget.prototype.loadCanvas = function() {
|
||||
self.currCanvas = self.document.createElement("canvas");
|
||||
self.initCanvas(self.currCanvas,DEFAULT_IMAGE_WIDTH,DEFAULT_IMAGE_HEIGHT);
|
||||
// Set the width and height input boxes
|
||||
self.updateSize();
|
||||
self.refreshToolbar();
|
||||
};
|
||||
// Get the current bitmap into an image object
|
||||
currImage.src = "data:" + tiddler.fields.type + ";base64," + tiddler.fields.text;
|
||||
@@ -139,14 +169,6 @@ EditBitmapWidget.prototype.initCanvas = function(canvas,width,height,image) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
** Update the input boxes with the actual size of the canvas
|
||||
*/
|
||||
EditBitmapWidget.prototype.updateSize = function() {
|
||||
this.widthDomNode.value = this.currCanvas.width;
|
||||
this.heightDomNode.value = this.currCanvas.height;
|
||||
};
|
||||
|
||||
/*
|
||||
** Change the size of the canvas, preserving the current image
|
||||
*/
|
||||
@@ -167,28 +189,6 @@ EditBitmapWidget.prototype.changeCanvasSize = function(newWidth,newHeight) {
|
||||
ctx.drawImage(this.currCanvas,0,0);
|
||||
};
|
||||
|
||||
EditBitmapWidget.prototype.handleWidthChangeEvent = function(event) {
|
||||
// Get the new width
|
||||
var newWidth = parseInt(this.widthDomNode.value,10);
|
||||
// Update if necessary
|
||||
if(newWidth > 0 && newWidth !== this.currCanvas.width) {
|
||||
this.changeCanvasSize(newWidth,this.currCanvas.height);
|
||||
}
|
||||
// Update the input controls
|
||||
this.updateSize();
|
||||
};
|
||||
|
||||
EditBitmapWidget.prototype.handleHeightChangeEvent = function(event) {
|
||||
// Get the new width
|
||||
var newHeight = parseInt(this.heightDomNode.value,10);
|
||||
// Update if necessary
|
||||
if(newHeight > 0 && newHeight !== this.currCanvas.height) {
|
||||
this.changeCanvasSize(this.currCanvas.width,newHeight);
|
||||
}
|
||||
// Update the input controls
|
||||
this.updateSize();
|
||||
};
|
||||
|
||||
EditBitmapWidget.prototype.handleTouchStartEvent = function(event) {
|
||||
this.brushDown = true;
|
||||
this.strokeStart(event.touches[0].clientX,event.touches[0].clientY);
|
||||
@@ -264,8 +264,9 @@ EditBitmapWidget.prototype.strokeMove = function(x,y) {
|
||||
// Redraw the previous image
|
||||
ctx.drawImage(this.currCanvas,0,0);
|
||||
// Render the stroke
|
||||
ctx.globalAlpha = parseFloat(this.wiki.getTiddlerText(LINE_OPACITY_TITLE,"1.0"));
|
||||
ctx.strokeStyle = this.wiki.getTiddlerText(LINE_COLOUR_TITLE,"#ff0");
|
||||
ctx.lineWidth = parseInt(this.wiki.getTiddlerText(LINE_WIDTH_TITLE,"3"),10);
|
||||
ctx.lineWidth = parseFloat(this.wiki.getTiddlerText(LINE_WIDTH_TITLE,"3"));
|
||||
ctx.lineCap = "round";
|
||||
ctx.lineJoin = "round";
|
||||
ctx.beginPath();
|
||||
@@ -292,7 +293,7 @@ EditBitmapWidget.prototype.saveChanges = function() {
|
||||
var tiddler = this.wiki.getTiddler(this.editTitle);
|
||||
if(tiddler) {
|
||||
// data URIs look like "data:<type>;base64,<text>"
|
||||
var dataURL = this.canvasDomNode.toDataURL(tiddler.fields.type,1.0),
|
||||
var dataURL = this.canvasDomNode.toDataURL(tiddler.fields.type),
|
||||
posColon = dataURL.indexOf(":"),
|
||||
posSemiColon = dataURL.indexOf(";"),
|
||||
posComma = dataURL.indexOf(","),
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/edit-shortcut.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Widget to display an editable keyboard shortcut
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var EditShortcutWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
EditShortcutWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
EditShortcutWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
this.inputNode = this.document.createElement("input");
|
||||
// Assign classes
|
||||
if(this.shortcutClass) {
|
||||
this.inputNode.className = this.shortcutClass;
|
||||
}
|
||||
// Assign other attributes
|
||||
if(this.shortcutStyle) {
|
||||
this.inputNode.setAttribute("style",this.shortcutStyle);
|
||||
}
|
||||
if(this.shortcutTooltip) {
|
||||
this.inputNode.setAttribute("title",this.shortcutTooltip);
|
||||
}
|
||||
if(this.shortcutPlaceholder) {
|
||||
this.inputNode.setAttribute("placeholder",this.shortcutPlaceholder);
|
||||
}
|
||||
if(this.shortcutAriaLabel) {
|
||||
this.inputNode.setAttribute("aria-label",this.shortcutAriaLabel);
|
||||
}
|
||||
// Assign the current shortcut
|
||||
this.updateInputNode();
|
||||
// Add event handlers
|
||||
$tw.utils.addEventListeners(this.inputNode,[
|
||||
{name: "keydown", handlerObject: this, handlerMethod: "handleKeydownEvent"}
|
||||
]);
|
||||
// Link into the DOM
|
||||
parent.insertBefore(this.inputNode,nextSibling);
|
||||
this.domNodes.push(this.inputNode);
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
EditShortcutWidget.prototype.execute = function() {
|
||||
this.shortcutTiddler = this.getAttribute("tiddler");
|
||||
this.shortcutField = this.getAttribute("field");
|
||||
this.shortcutIndex = this.getAttribute("index");
|
||||
this.shortcutPlaceholder = this.getAttribute("placeholder");
|
||||
this.shortcutDefault = this.getAttribute("default","");
|
||||
this.shortcutClass = this.getAttribute("class");
|
||||
this.shortcutStyle = this.getAttribute("style");
|
||||
this.shortcutTooltip = this.getAttribute("tooltip");
|
||||
this.shortcutAriaLabel = this.getAttribute("aria-label");
|
||||
};
|
||||
|
||||
/*
|
||||
Update the value of the input node
|
||||
*/
|
||||
EditShortcutWidget.prototype.updateInputNode = function() {
|
||||
if(this.shortcutField) {
|
||||
var tiddler = this.wiki.getTiddler(this.shortcutTiddler);
|
||||
if(tiddler && $tw.utils.hop(tiddler.fields,this.shortcutField)) {
|
||||
this.inputNode.value = tiddler.getFieldString(this.shortcutField);
|
||||
} else {
|
||||
this.inputNode.value = this.shortcutDefault;
|
||||
}
|
||||
} else if(this.shortcutIndex) {
|
||||
this.inputNode.value = this.wiki.extractTiddlerDataItem(this.shortcutTiddler,this.shortcutIndex,this.shortcutDefault);
|
||||
} else {
|
||||
this.inputNode.value = this.wiki.getTiddlerText(this.shortcutTiddler,this.shortcutDefault);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Handle a dom "keydown" event
|
||||
*/
|
||||
EditShortcutWidget.prototype.handleKeydownEvent = function(event) {
|
||||
// Ignore shift, ctrl, meta, alt
|
||||
if(event.keyCode && $tw.keyboardManager.getModifierKeys().indexOf(event.keyCode) === -1) {
|
||||
// Get the shortcut text representation
|
||||
var value = $tw.keyboardManager.getPrintableShortcuts([{
|
||||
ctrlKey: event.ctrlKey,
|
||||
shiftKey: event.shiftKey,
|
||||
altKey: event.altKey,
|
||||
metaKey: event.metaKey,
|
||||
keyCode: event.keyCode
|
||||
}]);
|
||||
if(value.length > 0) {
|
||||
this.wiki.setText(this.shortcutTiddler,this.shortcutField,this.shortcutIndex,value[0]);
|
||||
}
|
||||
// Ignore the keydown if it was already handled
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget needed re-rendering
|
||||
*/
|
||||
EditShortcutWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.placeholder || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.style || changedAttributes.tooltip || changedAttributes["aria-label"]) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else if(changedTiddlers[this.shortcutTiddler]) {
|
||||
this.updateInputNode();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
exports["edit-shortcut"] = EditShortcutWidget;
|
||||
|
||||
})();
|
||||
@@ -12,280 +12,10 @@ Edit-text widget
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var DEFAULT_MIN_TEXT_AREA_HEIGHT = "100px"; // Minimum height of textareas in pixels
|
||||
var editTextWidgetFactory = require("$:/core/modules/editor/factory.js").editTextWidgetFactory,
|
||||
FramedEngine = require("$:/core/modules/editor/engines/framed.js").FramedEngine,
|
||||
SimpleEngine = require("$:/core/modules/editor/engines/simple.js").SimpleEngine;
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var EditTextWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
EditTextWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
EditTextWidget.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();
|
||||
// Create our element
|
||||
var editInfo = this.getEditInfo(),
|
||||
tag = this.editTag;
|
||||
if($tw.config.htmlUnsafeElements.indexOf(tag) !== -1) {
|
||||
tag = "input";
|
||||
}
|
||||
var domNode = this.document.createElement(tag);
|
||||
if(this.editType) {
|
||||
domNode.setAttribute("type",this.editType);
|
||||
}
|
||||
if(editInfo.value === "" && this.editPlaceholder) {
|
||||
domNode.setAttribute("placeholder",this.editPlaceholder);
|
||||
}
|
||||
if(this.editSize) {
|
||||
domNode.setAttribute("size",this.editSize);
|
||||
}
|
||||
if(this.editRows) {
|
||||
domNode.setAttribute("rows",this.editRows);
|
||||
}
|
||||
// Assign classes
|
||||
if(this.editClass) {
|
||||
domNode.className = this.editClass;
|
||||
}
|
||||
// Set the text
|
||||
if(this.editTag === "textarea") {
|
||||
domNode.appendChild(this.document.createTextNode(editInfo.value));
|
||||
} else {
|
||||
domNode.value = editInfo.value;
|
||||
}
|
||||
// Add an input event handler
|
||||
$tw.utils.addEventListeners(domNode,[
|
||||
{name: "focus", handlerObject: this, handlerMethod: "handleFocusEvent"},
|
||||
{name: "input", handlerObject: this, handlerMethod: "handleInputEvent"}
|
||||
]);
|
||||
// Insert the element into the DOM
|
||||
parent.insertBefore(domNode,nextSibling);
|
||||
this.domNodes.push(domNode);
|
||||
if(this.postRender) {
|
||||
this.postRender();
|
||||
}
|
||||
// Fix height
|
||||
this.fixHeight();
|
||||
// Focus field
|
||||
if(this.editFocus === "true") {
|
||||
if(domNode.focus && domNode.select) {
|
||||
domNode.focus();
|
||||
domNode.select();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Get the tiddler being edited and current value
|
||||
*/
|
||||
EditTextWidget.prototype.getEditInfo = function() {
|
||||
// Get the edit value
|
||||
var self = this,
|
||||
value,
|
||||
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);
|
||||
} 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 + "'";
|
||||
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()));
|
||||
};
|
||||
}
|
||||
return {value: value, update: update};
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
EditTextWidget.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.editClass = this.getAttribute("class");
|
||||
this.editPlaceholder = this.getAttribute("placeholder");
|
||||
this.editSize = this.getAttribute("size");
|
||||
this.editRows = this.getAttribute("rows");
|
||||
this.editAutoHeight = this.getAttribute("autoHeight","yes") === "yes";
|
||||
this.editMinHeight = this.getAttribute("minHeight",DEFAULT_MIN_TEXT_AREA_HEIGHT);
|
||||
this.editFocusPopup = this.getAttribute("focusPopup");
|
||||
this.editFocus = this.getAttribute("focus");
|
||||
// Get the editor element tag and type
|
||||
var tag,type;
|
||||
if(this.editField === "text") {
|
||||
tag = "textarea";
|
||||
} else {
|
||||
tag = "input";
|
||||
var fieldModule = $tw.Tiddler.fieldModules[this.editField];
|
||||
if(fieldModule && fieldModule.editTag) {
|
||||
tag = fieldModule.editTag;
|
||||
}
|
||||
if(fieldModule && fieldModule.editType) {
|
||||
type = fieldModule.editType;
|
||||
}
|
||||
type = type || "text";
|
||||
}
|
||||
// Get the rest of our parameters
|
||||
this.editTag = this.getAttribute("tag",tag);
|
||||
this.editType = this.getAttribute("type",type);
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
EditTextWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
// Completely rerender if any of our attributes have changed
|
||||
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else if(changedTiddlers[this.editTitle]) {
|
||||
this.updateEditor(this.getEditInfo().value);
|
||||
return true;
|
||||
}
|
||||
// Fix the height anyway in case there has been a reflow
|
||||
this.fixHeight();
|
||||
return false;
|
||||
};
|
||||
|
||||
/*
|
||||
Update the editor with new text. This method is separate from updateEditorDomNode()
|
||||
so that subclasses can override updateEditor() and still use updateEditorDomNode()
|
||||
*/
|
||||
EditTextWidget.prototype.updateEditor = function(text) {
|
||||
this.updateEditorDomNode(text);
|
||||
};
|
||||
|
||||
/*
|
||||
Update the editor dom node with new text
|
||||
*/
|
||||
EditTextWidget.prototype.updateEditorDomNode = function(text) {
|
||||
// Replace the edit value if the tiddler we're editing has changed
|
||||
var domNode = this.domNodes[0];
|
||||
if(!domNode.isTiddlyWikiFakeDom) {
|
||||
if(this.document.activeElement !== domNode) {
|
||||
domNode.value = text;
|
||||
}
|
||||
// Fix the height if needed
|
||||
this.fixHeight();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Get the first parent element that has scrollbars or use the body as fallback.
|
||||
*/
|
||||
EditTextWidget.prototype.getScrollContainer = function(el) {
|
||||
while(el.parentNode) {
|
||||
el = el.parentNode;
|
||||
if(el.scrollTop) {
|
||||
return el;
|
||||
}
|
||||
}
|
||||
return this.document.body;
|
||||
};
|
||||
|
||||
/*
|
||||
Fix the height of textareas to fit their content
|
||||
*/
|
||||
EditTextWidget.prototype.fixHeight = function() {
|
||||
var domNode = this.domNodes[0];
|
||||
if(this.editAutoHeight && domNode && !domNode.isTiddlyWikiFakeDom && this.editTag === "textarea") {
|
||||
// Resize the textarea to fit its content, preserving scroll position
|
||||
// Get the scroll container and register the current scroll position
|
||||
var container = this.getScrollContainer(domNode),
|
||||
scrollTop = container.scrollTop;
|
||||
// Measure the specified minimum height
|
||||
domNode.style.height = this.editMinHeight;
|
||||
var minHeight = domNode.offsetHeight;
|
||||
// Set its height to auto so that it snaps to the correct height
|
||||
domNode.style.height = "auto";
|
||||
// Calculate the revised height
|
||||
var newHeight = Math.max(domNode.scrollHeight + domNode.offsetHeight - domNode.clientHeight,minHeight);
|
||||
// Only try to change the height if it has changed
|
||||
if(newHeight !== domNode.offsetHeight) {
|
||||
domNode.style.height = newHeight + "px";
|
||||
// Make sure that the dimensions of the textarea are recalculated
|
||||
$tw.utils.forceLayout(domNode);
|
||||
// Set the container to the position we registered at the beginning
|
||||
container.scrollTop = scrollTop;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Handle a dom "input" event
|
||||
*/
|
||||
EditTextWidget.prototype.handleInputEvent = function(event) {
|
||||
this.saveChanges(this.domNodes[0].value);
|
||||
this.fixHeight();
|
||||
return true;
|
||||
};
|
||||
|
||||
EditTextWidget.prototype.handleFocusEvent = function(event) {
|
||||
if(this.editFocusPopup) {
|
||||
$tw.popup.triggerPopup({
|
||||
domNode: this.domNodes[0],
|
||||
title: this.editFocusPopup,
|
||||
wiki: this.wiki,
|
||||
force: true
|
||||
});
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
EditTextWidget.prototype.saveChanges = function(text) {
|
||||
var editInfo = this.getEditInfo();
|
||||
if(text !== editInfo.value) {
|
||||
editInfo.update(text);
|
||||
}
|
||||
};
|
||||
|
||||
exports["edit-text"] = EditTextWidget;
|
||||
exports["edit-text"] = editTextWidgetFactory(FramedEngine,SimpleEngine);
|
||||
|
||||
})();
|
||||
|
||||
@@ -57,7 +57,8 @@ EditWidget.prototype.execute = function() {
|
||||
index: {type: "string", value: this.editIndex},
|
||||
"class": {type: "string", value: this.editClass},
|
||||
"placeholder": {type: "string", value: this.editPlaceholder}
|
||||
}
|
||||
},
|
||||
children: this.parseTreeNode.children
|
||||
}]);
|
||||
};
|
||||
|
||||
|
||||
@@ -29,7 +29,8 @@ Render this widget into the DOM
|
||||
EntityWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.parentDomNode = parent;
|
||||
this.execute();
|
||||
var textNode = this.document.createTextNode($tw.utils.entityDecode(this.parseTreeNode.entity));
|
||||
var entityString = this.getAttribute("entity",this.parseTreeNode.entity || ""),
|
||||
textNode = this.document.createTextNode($tw.utils.entityDecode(entityString));
|
||||
parent.insertBefore(textNode,nextSibling);
|
||||
this.domNodes.push(textNode);
|
||||
};
|
||||
@@ -44,7 +45,13 @@ EntityWidget.prototype.execute = function() {
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
EntityWidget.prototype.refresh = function(changedTiddlers) {
|
||||
return false;
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.entity) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
exports.entity = EntityWidget;
|
||||
|
||||
@@ -41,7 +41,7 @@ KeyboardWidget.prototype.render = function(parent,nextSibling) {
|
||||
domNode.className = classes.join(" ");
|
||||
// Add a keyboard event handler
|
||||
domNode.addEventListener("keydown",function (event) {
|
||||
if($tw.utils.checkKeyDescriptor(event,self.keyInfo)) {
|
||||
if($tw.keyboardManager.checkKeyDescriptors(event,self.keyInfoArray)) {
|
||||
self.invokeActions(this,event);
|
||||
self.dispatchMessage(event);
|
||||
event.preventDefault();
|
||||
@@ -68,7 +68,7 @@ KeyboardWidget.prototype.execute = function() {
|
||||
this.message = this.getAttribute("message");
|
||||
this.param = this.getAttribute("param");
|
||||
this.key = this.getAttribute("key");
|
||||
this.keyInfo = $tw.utils.parseKeyDescriptor(this.key);
|
||||
this.keyInfoArray = $tw.keyboardManager.parseKeyDescriptors(this.key);
|
||||
this["class"] = this.getAttribute("class");
|
||||
// Make child widgets
|
||||
this.makeChildWidgets();
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/*\
|
||||
title: $:/core/modules/widgets/wikify.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
Widget to wikify text into a variable
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var WikifyWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
WikifyWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
WikifyWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
this.renderChildren(parent,nextSibling);
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
WikifyWidget.prototype.execute = function() {
|
||||
// Get our parameters
|
||||
this.wikifyName = this.getAttribute("name");
|
||||
this.wikifyText = this.getAttribute("text");
|
||||
this.wikifyType = this.getAttribute("type");
|
||||
this.wikifyMode = this.getAttribute("mode","block");
|
||||
this.wikifyOutput = this.getAttribute("output","text");
|
||||
// Create the parse tree
|
||||
this.wikifyParser = this.wiki.parseText(this.wikifyType,this.wikifyText,{
|
||||
parseAsInline: this.wikifyMode === "inline"
|
||||
});
|
||||
// Create the widget tree
|
||||
this.wikifyWidgetNode = this.wiki.makeWidget(this.wikifyParser,{
|
||||
document: $tw.fakeDocument,
|
||||
parentWidget: this
|
||||
});
|
||||
// Render the widget tree to the container
|
||||
this.wikifyContainer = $tw.fakeDocument.createElement("div");
|
||||
this.wikifyWidgetNode.render(this.wikifyContainer,null);
|
||||
this.wikifyResult = this.getResult();
|
||||
// Set context variable
|
||||
this.setVariable(this.wikifyName,this.wikifyResult);
|
||||
// Construct the child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
/*
|
||||
Return the result string
|
||||
*/
|
||||
WikifyWidget.prototype.getResult = function() {
|
||||
var result;
|
||||
switch(this.wikifyOutput) {
|
||||
case "text":
|
||||
result = this.wikifyContainer.textContent;
|
||||
break;
|
||||
case "html":
|
||||
result = this.wikifyContainer.innerHTML;
|
||||
break;
|
||||
case "parsetree":
|
||||
result = JSON.stringify(this.wikifyParser.tree,0,$tw.config.preferences.jsonSpaces);
|
||||
break;
|
||||
case "widgettree":
|
||||
result = JSON.stringify(this.getWidgetTree(),0,$tw.config.preferences.jsonSpaces);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/*
|
||||
Return a string of the widget tree
|
||||
*/
|
||||
WikifyWidget.prototype.getWidgetTree = function() {
|
||||
var copyNode = function(widgetNode,resultNode) {
|
||||
var type = widgetNode.parseTreeNode.type;
|
||||
resultNode.type = type;
|
||||
switch(type) {
|
||||
case "element":
|
||||
resultNode.tag = widgetNode.parseTreeNode.tag;
|
||||
break;
|
||||
case "text":
|
||||
resultNode.text = widgetNode.parseTreeNode.text;
|
||||
break;
|
||||
}
|
||||
if(Object.keys(widgetNode.attributes || {}).length > 0) {
|
||||
resultNode.attributes = {};
|
||||
$tw.utils.each(widgetNode.attributes,function(attr,attrName) {
|
||||
resultNode.attributes[attrName] = widgetNode.getAttribute(attrName);
|
||||
});
|
||||
}
|
||||
if(Object.keys(widgetNode.children || {}).length > 0) {
|
||||
resultNode.children = [];
|
||||
$tw.utils.each(widgetNode.children,function(widgetChildNode) {
|
||||
var node = {};
|
||||
resultNode.children.push(node);
|
||||
copyNode(widgetChildNode,node);
|
||||
});
|
||||
}
|
||||
},
|
||||
results = {};
|
||||
copyNode(this.wikifyWidgetNode,results);
|
||||
return results;
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
WikifyWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
// Refresh ourselves entirely if any of our attributes have changed
|
||||
if(changedAttributes.name || changedAttributes.text || changedAttributes.type || changedAttributes.mode || changedAttributes.output) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
// Refresh the widget tree
|
||||
if(this.wikifyWidgetNode.refresh(changedTiddlers)) {
|
||||
// Check if there was any change
|
||||
var result = this.getResult();
|
||||
if(result !== this.wikifyResult) {
|
||||
// If so, save the change
|
||||
this.wikifyResult = result;
|
||||
this.setVariable(this.wikifyName,this.wikifyResult);
|
||||
// Refresh each of our child widgets
|
||||
$tw.utils.each(this.children,function(childWidget) {
|
||||
childWidget.refreshSelf();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Just refresh the children
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
}
|
||||
};
|
||||
|
||||
exports.wikify = WikifyWidget;
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user