1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2025-12-05 00:08:06 +00:00

Introduce text-slicer plugin and edition

A first pass at a plugin that splits formatted text into individual
tiddlers according to lists and headings.
This commit is contained in:
Jermolene
2015-08-01 13:15:24 +01:00
parent 8f746f9dde
commit 8488a13761
12 changed files with 403 additions and 5 deletions

View File

@@ -0,0 +1,23 @@
title: $:/plugins/tiddlywiki/text-slicer/macros
tags: $:/tags/Macro
\define display-heading-tiddler(level:"h1")
<$level$><$view field="title"/></$level$>
<$list filter='[tag<currentTiddler>]'>
<$tiddler>
<$transclude mode='block'/>
</$tiddler>
</$list>
\end
\define display-list-tiddler(type:"ol")
<$type$>
<$list filter='[tag<currentTiddler>]'>
<li>
<$tiddler>
<$transclude mode='block'/>
</$tiddler>
</li>
</$list>
</$type$>
\end

View File

@@ -0,0 +1,7 @@
{
"title": "$:/plugins/tiddlywiki/text-slicer",
"description": "Tools for slicing text into tiddlers",
"author": "JeremyRuston",
"core-version": ">=5.0.0",
"list": "readme"
}

View File

@@ -0,0 +1,3 @@
title: $:/plugins/tiddlywiki/text-slicer/readme
This plugin contains tools to help slice up long texts into individual tiddlers.

View File

@@ -0,0 +1,13 @@
title: $:/plugins/tiddlywiki/text-slicer/ui/slice-button
tags: $:/tags/ViewToolbar
caption: {{$:/plugins/tiddlywiki/text-slicer/text-slicer-icon}} Slice tiddler
description: Slice this tiddler by headings and lists
<$button message="tm-slice-tiddler" param=<<currentTiddler>> tooltip={{$:/language/Buttons/Clone/Hint}} aria-label={{$:/language/Buttons/Clone/Caption}} class=<<tv-config-toolbar-class>>>
<$list filter="[<tv-config-toolbar-icons>prefix[yes]]">
{{$:/plugins/tiddlywiki/text-slicer/text-slicer-icon}}
</$list>
<$list filter="[<tv-config-toolbar-text>prefix[yes]]">
<span class="tc-btn-text">Slice tiddler</span>
</$list>
</$button>

View File

@@ -0,0 +1,157 @@
/*\
title: $:/plugins/tiddlywiki/text-slicer/slicer.js
type: application/javascript
module-type: startup
Setup the root widget event handlers
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
// Export name and synchronous status
exports.name = "slicer";
exports.platforms = ["browser"];
exports.after = ["startup"];
exports.synchronous = true;
var SLICER_OUTPUT_TITLE = "$:/Import";
// Install the root widget event handlers
exports.startup = function() {
$tw.rootWidget.addEventListener("tm-slice-tiddler",function(event) {
// Slice up and output the tiddler
outputTiddlers(sliceTiddler(event.param));
});
};
var currentId = 0;
function nextId() {
return ++currentId;
}
// Slice a tiddler into individual tiddlers
function sliceTiddler(title) {
var tiddlers = {},
parser = $tw.wiki.parseTiddler(title),
parentStack = [],
addTiddler = function(fields) {
if(fields.title) {
tiddlers[fields.title] = $tw.utils.extend({},tiddlers[fields.title],fields);
return fields.title;
} else {
return null;
}
},
addToList = function(parent,child) {
var parentTiddler = tiddlers[parent] || {},
parentList = parentTiddler.list || [];
parentList.push(child);
addTiddler($tw.utils.extend({title: parent},parentTiddler,{list: parentList}));
},
convertTypeToLevel = function(type) {
if(type.charAt(0) === "h") {
return parseInt(type.charAt(1),10);
} else {
return null;
}
},
popParentStackUntil = function(type) {
// Pop the stack to remove any entries at the same or lower level
var newLevel = convertTypeToLevel(type),
topIndex = parentStack.length - 1;
do {
var topLevel = convertTypeToLevel(parentStack[parentStack.length - 1].type);
if(topLevel !== null && topLevel < newLevel ) {
break;
}
parentStack.length--;
} while(true);
return parentStack[parentStack.length - 1].title;
},
processNodeList = function(nodeList) {
$tw.utils.each(nodeList,function(parseTreeNode) {
var parentTitle,
text = $tw.utils.getParseTreeText(parseTreeNode);
if(parseTreeNode.type === "element" && (parseTreeNode.tag === "h1" || parseTreeNode.tag === "h2" || parseTreeNode.tag === "h3" || parseTreeNode.tag === "h4")) {
parentTitle = popParentStackUntil(parseTreeNode.tag);
addToList(parentTitle,text);
parentStack.push({type: parseTreeNode.tag, title: addTiddler({
title: text,
text: "<<display-heading-tiddler level:'" + parseTreeNode.tag + "'>>",
list: [],
tags: [parentTitle]
})});
} else if(parseTreeNode.type === "element" && (parseTreeNode.tag === "ul" || parseTreeNode.tag === "ol")) {
var listTitle = title + "-list-" + nextId();
parentTitle = parentStack[parentStack.length - 1].title;
addToList(parentTitle,listTitle);
parentStack.push({type: parseTreeNode.tag, title: addTiddler({
title: listTitle,
text: "<<display-list-tiddler type:'" + parseTreeNode.tag + "'>>",
list: [],
tags: [parentTitle]
})});
processNodeList(parseTreeNode.children);
parentStack.pop();
} else if(parseTreeNode.type === "element" && parseTreeNode.tag === "li") {
var listItemTitle = title + "-listitem-" + nextId();
parentTitle = parentStack[parentStack.length - 1].title;
addToList(parentTitle,listItemTitle);
addTiddler({
title: listItemTitle,
text: text,
list: [],
tags: [parentTitle]
});
} else if(parseTreeNode.type === "element" && parseTreeNode.tag === "p") {
parentTitle = parentStack[parentStack.length - 1].title;
addToList(parentTitle,addTiddler({
title: title + "-para-" + nextId(),
text: text,
tags: [parentTitle]
}));
}
});
};
if(parser) {
parentStack.push({type: "h0", title: addTiddler({
title: "Sliced up " + title,
text: "<div class='tc-table-of-contents'>\n\n<<toc-selective-expandable 'Sliced up " + title + "'>>\n\n</div>\n<<display-heading-tiddler level:'h1'>>",
list: []
})});
processNodeList(parser.tree);
}
return tiddlers;
}
// Output to the output tiddler
function outputTiddlers(tiddlers) {
// Get the current slicer output tiddler
var slicerOutputTiddler = $tw.wiki.getTiddler(SLICER_OUTPUT_TITLE),
slicerOutputData = $tw.wiki.getTiddlerData(SLICER_OUTPUT_TITLE,{}),
newFields = new Object({
title: SLICER_OUTPUT_TITLE,
type: "application/json",
"plugin-type": "import",
"status": "pending"
});
// Process each tiddler
slicerOutputData.tiddlers = slicerOutputData.tiddlers || {};
$tw.utils.each(tiddlers,function(tiddlerFields) {
var title = tiddlerFields.title;
if(title) {
slicerOutputData.tiddlers[title] = tiddlerFields;
}
});
// Save the slicer output tiddler
newFields.text = JSON.stringify(slicerOutputData,null,$tw.config.preferences.jsonSpaces);
$tw.wiki.addTiddler(new $tw.Tiddler(slicerOutputTiddler,newFields));
// TBD: Navigate to $:/Import
}
})();

View File

@@ -0,0 +1,21 @@
title: $:/plugins/tiddlywiki/text-slicer/text-slicer-icon
tags: $:/tags/Image
<svg class="tc-image-text-slicer tc-image-button" width="22pt" height="22pt" viewBox="0 0 128 128">
<g fill-rule="evenodd">
<path d="M80,51.0155285 L59.5940359,64.2673166 L125.897873,107.325532 C128.030065,108.710193 128.646102,111.578842 127.255156,113.720711 C125.867041,115.858221 123.001365,116.472016 120.860813,115.081925 L51.1036068,69.7810657 L26.8517133,85.5304295 L26.8517087,85.5304319 C28.1651844,86.2022039 29.4191834,87.0428514 30.5829398,88.0544894 C38.2922474,94.7560882 39.1219848,106.423679 32.4362103,114.114783 C25.7504358,121.805887 14.080916,122.608039 6.3716084,115.90644 C-1.33769921,109.204841 -2.1674367,97.5372504 4.51833784,89.8461466 C5.83807302,88.3279649 7.35199779,87.0782085 8.99132065,86.1016058 L42.6131777,64.2673166 L42.6131777,64.2673166 L8.54310096,42.14195 C8.24323991,41.947218 7.97336572,41.7231352 7.73484365,41.4758511 C7.26854012,41.1408688 6.81356667,40.7813413 6.3716084,40.3971528 C-1.33769921,33.695554 -2.1674367,22.0279631 4.51833784,14.3368593 C11.2041124,6.64575553 22.8736321,5.84360327 30.5829398,12.5452021 C38.2922474,19.246801 39.1219848,30.9143918 32.4362103,38.6054956 C30.8132523,40.4724953 28.8966192,41.9335527 26.8142483,42.9798736 L51.1036068,58.7535674 L80,39.9880303 L80,51.0155285 Z M13.0048429,34.0671776 C12.7764349,33.9024698 12.5534894,33.725961 12.336801,33.5375966 C8.48191699,30.186597 8.06702347,24.3524532 11.4101104,20.5066717 C14.7531973,16.6608901 20.5883056,16.25979 24.4431896,19.6107896 C28.2980736,22.9617891 28.7129671,28.7959329 25.3698802,32.6417145 C22.5492464,35.8864825 17.954628,36.6790998 14.2721287,34.8349262 L13.5801614,34.3855571 C13.3934198,34.2642857 13.2011595,34.1582654 13.0048429,34.0671776 L13.0048429,34.0671776 Z M11.4101104,96.0159589 C8.06702347,99.8617405 8.48191699,105.695884 12.336801,109.046884 C16.191685,112.397883 22.0267933,111.996783 25.3698802,108.151002 C28.7129671,104.30522 28.2980736,98.4710764 24.4431896,95.1200768 C20.5883056,91.7690773 14.7531973,92.1701774 11.4101104,96.0159589 Z"></path>
<g transform="translate(81.000000, 0.000000)">
<circle transform="translate(5.000000, 52.000000) rotate(-90.000000) translate(-5.000000, -52.000000) " cx="5" cy="52" r="4"></circle>
<circle transform="translate(5.000000, 112.000000) rotate(-90.000000) translate(-5.000000, -112.000000) " cx="5" cy="112" r="4"></circle>
<circle transform="translate(5.000000, 124.000000) rotate(-90.000000) translate(-5.000000, -124.000000) " cx="5" cy="124" r="4"></circle>
<circle transform="translate(5.000000, 40.000000) rotate(-90.000000) translate(-5.000000, -40.000000) " cx="5" cy="40" r="4"></circle>
<circle transform="translate(5.000000, 100.316987) rotate(-90.000000) translate(-5.000000, -100.316987) " cx="5" cy="100.316987" r="4"></circle>
<circle transform="translate(5.000000, 28.000000) rotate(-90.000000) translate(-5.000000, -28.000000) " cx="5" cy="28" r="4"></circle>
<circle transform="translate(5.000000, 88.316987) rotate(-90.000000) translate(-5.000000, -88.316987) " cx="5" cy="88.3169873" r="4"></circle>
<circle transform="translate(5.000000, 16.000000) rotate(-90.000000) translate(-5.000000, -16.000000) " cx="5" cy="16" r="4"></circle>
<circle transform="translate(5.000000, 76.316987) rotate(-90.000000) translate(-5.000000, -76.316987) " cx="5" cy="76.3169873" r="4"></circle>
<circle transform="translate(5.000000, 4.000000) rotate(-90.000000) translate(-5.000000, -4.000000) " cx="5" cy="4" r="4"></circle>
<circle transform="translate(5.000000, 64.316987) rotate(-90.000000) translate(-5.000000, -64.316987) " cx="5" cy="64.3169873" r="4"></circle>
</g>
</g>
</svg>