mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-23 18:17:20 +00:00
Added wikitext image support
We’ve added a parser to recognise the `[img[URL or tiddler title]]` format, and an associated image widget.
This commit is contained in:
parent
ace57dd205
commit
ad4b03506a
137
core/modules/parsers/wikiparser/rules/image.js
Normal file
137
core/modules/parsers/wikiparser/rules/image.js
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/parsers/wikiparser/rules/image.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: wikirule
|
||||||
|
|
||||||
|
Wiki text inline rule for embedding images. For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
[img[http://tiddlywiki.com/fractalveg.jpg]]
|
||||||
|
[img width=23 height=24 [http://tiddlywiki.com/fractalveg.jpg]]
|
||||||
|
[img 23x24 [http://tiddlywiki.com/fractalveg.jpg]]
|
||||||
|
[img width={{!!width}} height={{!!height}} [http://tiddlywiki.com/fractalveg.jpg]]
|
||||||
|
[img {{!!width}}x{{!!height}} [http://tiddlywiki.com/fractalveg.jpg]]
|
||||||
|
[img[Description of image|http://tiddlywiki.com/fractalveg.jpg]]
|
||||||
|
[img[TiddlerTitle]]
|
||||||
|
[img[Description of image|TiddlerTitle]]
|
||||||
|
```
|
||||||
|
|
||||||
|
Generates the `<$image>` widget.
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
exports.name = "image";
|
||||||
|
exports.types = {inline: true};
|
||||||
|
|
||||||
|
exports.init = function(parser) {
|
||||||
|
this.parser = parser;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.findNextMatch = function(startPos) {
|
||||||
|
// Find the next tag
|
||||||
|
this.nextImage = this.findNextImage(this.parser.source,startPos);
|
||||||
|
return this.nextImage ? this.nextImage.start : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.parse = function() {
|
||||||
|
// Move past the match
|
||||||
|
this.parser.pos = this.nextImage.end;
|
||||||
|
var node = {
|
||||||
|
type: "element",
|
||||||
|
tag: "$image",
|
||||||
|
attributes: this.nextImage.attributes
|
||||||
|
};
|
||||||
|
return [node];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Find the next image from the current position
|
||||||
|
*/
|
||||||
|
exports.findNextImage = function(source,pos) {
|
||||||
|
// A regexp for finding candidate HTML tags
|
||||||
|
var reLookahead = /(\[img)/g;
|
||||||
|
// Find the next candidate
|
||||||
|
reLookahead.lastIndex = pos;
|
||||||
|
var match = reLookahead.exec(source);
|
||||||
|
while(match) {
|
||||||
|
// Try to parse the candidate as a tag
|
||||||
|
var tag = this.parseImage(source,match.index);
|
||||||
|
// Return success
|
||||||
|
if(tag) {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
// Look for the next match
|
||||||
|
reLookahead.lastIndex = match.index + 1;
|
||||||
|
match = reLookahead.exec(source);
|
||||||
|
}
|
||||||
|
// Failed
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Look for an image at the specified position. Returns null if not found, otherwise returns {type: "element", name: "$image", attributes: [], isSelfClosing:, start:, end:,}
|
||||||
|
*/
|
||||||
|
exports.parseImage = function(source,pos) {
|
||||||
|
var token,
|
||||||
|
node = {
|
||||||
|
type: "element",
|
||||||
|
name: "$image",
|
||||||
|
start: pos,
|
||||||
|
attributes: {}
|
||||||
|
};
|
||||||
|
// Skip whitespace
|
||||||
|
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||||
|
// Look for the `[img`
|
||||||
|
token = $tw.utils.parseTokenString(source,pos,"[img");
|
||||||
|
if(!token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
pos = token.end;
|
||||||
|
// Skip whitespace
|
||||||
|
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||||
|
// Process attributes
|
||||||
|
if(source.charAt(pos) !== "[") {
|
||||||
|
var attribute = $tw.utils.parseAttribute(source,pos);
|
||||||
|
while(attribute) {
|
||||||
|
node.attributes[attribute.name] = attribute;
|
||||||
|
pos = attribute.end;
|
||||||
|
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||||
|
if(source.charAt(pos) !== "[") {
|
||||||
|
// Get the next attribute
|
||||||
|
attribute = $tw.utils.parseAttribute(source,pos);
|
||||||
|
} else {
|
||||||
|
attribute = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Skip whitespace
|
||||||
|
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||||
|
// Look for the `[` after the attributes
|
||||||
|
token = $tw.utils.parseTokenString(source,pos,"[");
|
||||||
|
if(!token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
pos = token.end;
|
||||||
|
// Skip whitespace
|
||||||
|
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||||
|
// Get the source up to the terminating `]]`
|
||||||
|
token = $tw.utils.parseTokenRegExp(source,pos,/(?:([^|\]]*?)\|)?([^\]]+?)\]\]/g);
|
||||||
|
if(!token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
pos = token.end;
|
||||||
|
if(token.match[1]) {
|
||||||
|
node.attributes.tooltip = {type: "string", value: token.match[1].trim()};
|
||||||
|
}
|
||||||
|
node.attributes.source = {type: "string", value: (token.match[2] || "").trim()};
|
||||||
|
// Update the end position
|
||||||
|
node.end = pos;
|
||||||
|
return node;
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
123
core/modules/widgets/image.js
Normal file
123
core/modules/widgets/image.js
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/widgets/image.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: widget
|
||||||
|
|
||||||
|
The image widget displays an image referenced with an external URI or with a local tiddler title.
|
||||||
|
|
||||||
|
```
|
||||||
|
<$image src="TiddlerTitle" width="320" height="400" class="classnames">
|
||||||
|
```
|
||||||
|
|
||||||
|
The image source can be the title of an existing tiddler or the URL of an external image.
|
||||||
|
|
||||||
|
External images always generate an HTML `<img>` tag.
|
||||||
|
|
||||||
|
Tiddlers that have a _canonical_uri field generate an HTML `<img>` tag with the src attribute containing the URI.
|
||||||
|
|
||||||
|
Tiddlers that contain image data generate an HTML `<img>` tag with the src attribute containing a base64 representation of the image.
|
||||||
|
|
||||||
|
Tiddlers that contain wikitext could be rendered to a DIV of the usual size of a tiddler, and then transformed to the size requested.
|
||||||
|
|
||||||
|
The width and height attributes are interpreted as a number of pixels, and do not need to include the "px" suffix.
|
||||||
|
|
||||||
|
\*/
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||||
|
|
||||||
|
var ImageWidget = function(parseTreeNode,options) {
|
||||||
|
this.initialise(parseTreeNode,options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Inherit from the base widget class
|
||||||
|
*/
|
||||||
|
ImageWidget.prototype = new Widget();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Render this widget into the DOM
|
||||||
|
*/
|
||||||
|
ImageWidget.prototype.render = function(parent,nextSibling) {
|
||||||
|
this.parentDomNode = parent;
|
||||||
|
this.computeAttributes();
|
||||||
|
this.execute();
|
||||||
|
// Create element
|
||||||
|
// Determine what type of image it is
|
||||||
|
var tag = "img", src = "",
|
||||||
|
tiddler = this.wiki.getTiddler(this.imageSource);
|
||||||
|
if(!tiddler) {
|
||||||
|
// The source isn't the title of a tiddler, so we'll assume it's a URL
|
||||||
|
src = this.imageSource;
|
||||||
|
} else {
|
||||||
|
// Check if it is an image tiddler
|
||||||
|
if(this.wiki.isImageTiddler(this.imageSource)) {
|
||||||
|
// Render the appropriate element for the image type
|
||||||
|
var type = tiddler.fields.type,
|
||||||
|
text = tiddler.fields.text;
|
||||||
|
switch(type) {
|
||||||
|
case "application/pdf":
|
||||||
|
tag = "embed";
|
||||||
|
src = "data:application/pdf;base64," + text;
|
||||||
|
break;
|
||||||
|
case "image/svg+xml":
|
||||||
|
src = "data:image/svg+xml," + encodeURIComponent(text);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
src = "data:" + type + ";base64," + text;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Create the element and assign the attributes
|
||||||
|
var domNode = this.document.createElement(tag);
|
||||||
|
domNode.setAttribute("src",src);
|
||||||
|
if(this.imageClass) {
|
||||||
|
domNode.setAttribute("class",this.imageClass);
|
||||||
|
}
|
||||||
|
if(this.imageWidth) {
|
||||||
|
domNode.setAttribute("width",parseInt(this.imageWidth,10) + "px");
|
||||||
|
}
|
||||||
|
if(this.imageHeight) {
|
||||||
|
domNode.setAttribute("height",parseInt(this.imageHeight,10) + "px");
|
||||||
|
}
|
||||||
|
if(this.imageTooltip) {
|
||||||
|
domNode.setAttribute("title",this.imageTooltip);
|
||||||
|
}
|
||||||
|
// Insert element
|
||||||
|
parent.insertBefore(domNode,nextSibling);
|
||||||
|
this.domNodes.push(domNode);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Compute the internal state of the widget
|
||||||
|
*/
|
||||||
|
ImageWidget.prototype.execute = function() {
|
||||||
|
// Get our parameters
|
||||||
|
this.imageSource = this.getAttribute("source");
|
||||||
|
this.imageWidth = this.getAttribute("width");
|
||||||
|
this.imageHeight = this.getAttribute("height");
|
||||||
|
this.imageClass = this.getAttribute("class");
|
||||||
|
this.imageTooltip = this.getAttribute("tooltip");
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||||
|
*/
|
||||||
|
ImageWidget.prototype.refresh = function(changedTiddlers) {
|
||||||
|
var changedAttributes = this.computeAttributes();
|
||||||
|
if(changedAttributes.source || changedAttributes.width || changedAttributes.height || changedAttributes["class"] || changedAttributes.tooltip || changedTiddlers[this.imageSource]) {
|
||||||
|
this.refreshSelf();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.image = ImageWidget;
|
||||||
|
|
||||||
|
})();
|
20
editions/tw5.com/tiddlers/widgets/ImageWidget.tid
Normal file
20
editions/tw5.com/tiddlers/widgets/ImageWidget.tid
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
title: ImageWidget
|
||||||
|
created: 20140416160234142
|
||||||
|
modified: 20140416160234142
|
||||||
|
tags: widget
|
||||||
|
|
||||||
|
! Introduction
|
||||||
|
|
||||||
|
The image widget displays images that can be specified as a remote URL or the title of a local tiddler containing the image.
|
||||||
|
|
||||||
|
! Content and Attributes
|
||||||
|
|
||||||
|
Any content of the `<$image>` widget is ignored.
|
||||||
|
|
||||||
|
|!Attribute |!Description |
|
||||||
|
|source |The URL of the image, or the title of an image tiddler |
|
||||||
|
|width |The width of the image as a number |
|
||||||
|
|height |The height of the image |
|
||||||
|
|tooltip |The tooltip to be displayed over the image |
|
||||||
|
|class |CSS classes to be assigned to the `<img>` element |
|
||||||
|
|
@ -1,10 +1,44 @@
|
|||||||
created: 20131205160221762
|
created: 20131205160221762
|
||||||
modified: 20131205160234142
|
modified: 20140416160234142
|
||||||
tags: wikitext
|
tags: wikitext
|
||||||
title: Images in WikiText
|
title: Images in WikiText
|
||||||
type: text/vnd.tiddlywiki
|
type: text/vnd.tiddlywiki
|
||||||
|
|
||||||
To display an image stored in a tiddler just transclude that tiddler:
|
! Image Formatting
|
||||||
|
|
||||||
|
Images can be included in WikiText with the following syntax:
|
||||||
|
|
||||||
|
```
|
||||||
|
[img[Motovun Jack.jpg]]
|
||||||
|
[img[http://tiddlywiki.com/favicon.ico]]
|
||||||
|
```
|
||||||
|
|
||||||
|
If the image source is the title of an image tiddler then that tiddler is directly displayed. Otherwise it is interpreted as a URL and an HTML `<img>` tag is generated with the `src` attribute containing the URL.
|
||||||
|
|
||||||
|
A tooltip can also be specified:
|
||||||
|
|
||||||
|
```
|
||||||
|
[img[An explanatory tooltip|Motovun Jack.jpg]]
|
||||||
|
```
|
||||||
|
|
||||||
|
Attributes can be provided to specify CSS classes and the image width and height:
|
||||||
|
|
||||||
|
```
|
||||||
|
[img width=32 [Motovun Jack.jpg]]
|
||||||
|
[img width=32 class="tw-image" [Motovun Jack.jpg]]
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that attributes can be specified as transclusions or variable references:
|
||||||
|
|
||||||
|
```
|
||||||
|
[img width={{!!mywidth}} class=<<image-classes>> [Motovun Jack.jpg]]
|
||||||
|
```
|
||||||
|
|
||||||
|
The image syntax is a shorthand for invoking the ImageWidget.
|
||||||
|
|
||||||
|
! Displaying Images via Transclusion
|
||||||
|
|
||||||
|
You can also display an image stored in a tiddler by transcluding that tiddler. The disadvantage of this approach is that there is no direct way to control the size of the image.
|
||||||
|
|
||||||
```
|
```
|
||||||
{{Motovun Jack.jpg}}
|
{{Motovun Jack.jpg}}
|
||||||
@ -13,3 +47,4 @@ To display an image stored in a tiddler just transclude that tiddler:
|
|||||||
Renders as:
|
Renders as:
|
||||||
|
|
||||||
{{Motovun Jack.jpg}}
|
{{Motovun Jack.jpg}}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user