mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-30 21:39:57 +00:00
260 lines
7.3 KiB
JavaScript
260 lines
7.3 KiB
JavaScript
/*\
|
|
title: $:/plugins/tiddlywiki/text-slicer/modules/slicer.js
|
|
type: application/javascript
|
|
module-type: library
|
|
|
|
Slice a tiddler or DOM document into individual tiddlers
|
|
|
|
var slicer = new textSlicer.Slicer(doc,{
|
|
sourceTiddlerTitle: tiddler to slice -or-
|
|
sourceText: text to slice -or-
|
|
sourceDoc: DOM document to
|
|
baseTiddlerTitle: "MySlicedTiddlers-",
|
|
role: "sliced-content"
|
|
});
|
|
|
|
\*/
|
|
(function(){
|
|
|
|
/*jslint node: true, browser: true */
|
|
/*global $tw: false */
|
|
"use strict";
|
|
|
|
var DOMParser = $tw.browser ? window.DOMParser : require("$:/plugins/tiddlywiki/xmldom/dom-parser").DOMParser;
|
|
|
|
function Slicer(options) {
|
|
// Marshal parameters
|
|
this.sourceDoc = options.sourceDoc;
|
|
this.sourceTiddlerTitle = options.sourceTiddlerTitle;
|
|
this.sourceText = options.sourceText;
|
|
this.wiki = options.wiki;
|
|
if(options.baseTiddlerTitle) {
|
|
this.baseTiddlerTitle = options.baseTiddlerTitle
|
|
} else {
|
|
if(this.sourceTiddlerTitle) {
|
|
this.baseTiddlerTitle = "Sliced up " + this.sourceTiddlerTitle;
|
|
} else {
|
|
this.baseTiddlerTitle = "SlicedTiddler";
|
|
}
|
|
}
|
|
this.role = options.role || "sliced-html";
|
|
// Initialise state
|
|
this.extractedTiddlers = {}; // Hashmap of created tiddlers
|
|
this.parentStack = []; // Stack of parent heading or list
|
|
this.containerStack = []; // Stack of elements containing other elements
|
|
this.slicers = $tw.modules.applyMethods("slicer");
|
|
this.anchors = Object.create(null); // Hashmap of HTML anchor ID to tiddler title
|
|
// Get the DOM document for the source text
|
|
if(!this.sourceDoc) {
|
|
if(this.sourceTiddlerTitle) {
|
|
this.sourceDoc = this.parseTiddlerText(this.sourceTiddlerTitle);
|
|
} else {
|
|
this.sourceDoc = this.parseHtmlText(this.sourceText);
|
|
}
|
|
}
|
|
// Create parent tiddler
|
|
console.log("Slicing to",this.baseTiddlerTitle)
|
|
var sliceTiddler = {
|
|
title: this.baseTiddlerTitle,
|
|
text: "Sliced at " + (new Date()),
|
|
"toc-type": "document",
|
|
tags: [],
|
|
list: [],
|
|
role: this.role
|
|
};
|
|
this.addTiddler(sliceTiddler);
|
|
// Slice the text into subordinate tiddlers
|
|
this.parentStack.push({type: "h0", title: sliceTiddler.title});
|
|
this.currentTiddler = sliceTiddler.title;
|
|
this.containerStack.push(sliceTiddler.title);
|
|
this.processNodeList(this.sourceDoc.childNodes);
|
|
this.containerStack.pop();
|
|
}
|
|
|
|
Slicer.prototype.parseTiddlerText = function(title) {
|
|
var tiddler = this.wiki.getTiddler(title);
|
|
if(tiddler) {
|
|
if(tiddler.fields.type === "text/html") {
|
|
return this.parseHtmlText(tiddler.fields.text);
|
|
} else {
|
|
return this.parseWikiText(tiddler);
|
|
}
|
|
}
|
|
};
|
|
|
|
Slicer.prototype.parseWikiText = function(tiddler) {
|
|
var widgetNode = this.wiki.makeTranscludeWidget(tiddler.fields.title,{
|
|
document: $tw.fakeDocument,
|
|
parseAsInline: false,
|
|
importPageMacros: true}),
|
|
container = $tw.fakeDocument.createElement("div");
|
|
widgetNode.render(container,null);
|
|
return container;
|
|
};
|
|
|
|
Slicer.prototype.parseHtmlText = function(text) {
|
|
text = text || "";
|
|
if($tw.browser) {
|
|
this.iframe = document.createElement("iframe");
|
|
document.body.appendChild(this.iframe);
|
|
this.iframe.contentWindow.document.open();
|
|
this.iframe.contentWindow.document.write(text);
|
|
this.iframe.contentWindow.document.close();
|
|
return this.iframe.contentWindow.document;
|
|
} else {
|
|
return new DOMParser().parseFromString(text);
|
|
}
|
|
};
|
|
|
|
Slicer.prototype.addToList = function(parent,child) {
|
|
var parentTiddler = this.getTiddler(parent) || {},
|
|
parentList = parentTiddler.list || [];
|
|
parentList.push(child);
|
|
this.addTiddler($tw.utils.extend({title: parent},parentTiddler,{list: parentList}));
|
|
};
|
|
|
|
Slicer.prototype.insertBeforeListItem = function(parent,child,beforeSibling) {
|
|
var parentTiddler = this.getTiddler(parent) || {},
|
|
parentList = parentTiddler.list || [],
|
|
parentListSiblingPosition = parentList.indexOf(beforeSibling);
|
|
if(parentListSiblingPosition !== -1) {
|
|
parentList.splice(parentListSiblingPosition,0,child)
|
|
this.addTiddler($tw.utils.extend({title: parent},parentTiddler,{list: parentList}));
|
|
}
|
|
|
|
else {debugger;}
|
|
};
|
|
|
|
Slicer.prototype.popParentStackUntil = function(type) {
|
|
// Pop the stack to remove any entries at the same or lower level
|
|
var newLevel = this.convertTypeToLevel(type),
|
|
topIndex = this.parentStack.length - 1;
|
|
do {
|
|
var topLevel = this.convertTypeToLevel(this.parentStack[this.parentStack.length - 1].type);
|
|
if(topLevel !== null && topLevel < newLevel ) {
|
|
break;
|
|
}
|
|
this.parentStack.length--;
|
|
} while(true);
|
|
return this.parentStack[this.parentStack.length - 1].title;
|
|
};
|
|
|
|
Slicer.prototype.getTopContainer = function() {
|
|
return this.containerStack[this.containerStack.length-1];
|
|
};
|
|
|
|
Slicer.prototype.appendToCurrentContainer = function(newText) {
|
|
var title = this.containerStack[this.containerStack.length-1];
|
|
if(title) {
|
|
var tiddler = this.getTiddler(title) || {},
|
|
text = tiddler.text || "";
|
|
this.addTiddler($tw.utils.extend({title: title},tiddler,{text: text + newText}));
|
|
}
|
|
else {debugger;}
|
|
};
|
|
|
|
Slicer.prototype.convertTypeToLevel = function(type) {
|
|
if(type.charAt(0) === "h") {
|
|
return parseInt(type.charAt(1),10);
|
|
} else {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
Slicer.prototype.isBlank = function(s) {
|
|
return (/^[\s\xA0]*$/g).test(s);
|
|
};
|
|
|
|
Slicer.prototype.registerAnchor = function(id) {
|
|
this.anchors[id] = this.currentTiddler;
|
|
}
|
|
|
|
Slicer.prototype.processNodeList = function(domNodeList) {
|
|
$tw.utils.each(domNodeList,this.processNode.bind(this));
|
|
}
|
|
|
|
Slicer.prototype.processNode = function(domNode) {
|
|
var nodeType = domNode.nodeType,
|
|
tagName = (domNode.tagName || "").toLowerCase(),
|
|
hasProcessed = false;
|
|
for(var slicerTitle in this.slicers) {
|
|
var slicer = this.slicers[slicerTitle];
|
|
if(slicer.bind(this)(domNode,tagName)) {
|
|
hasProcessed = true;
|
|
break;
|
|
}
|
|
}
|
|
if(!hasProcessed) {
|
|
if(nodeType === 1 && domNode.hasChildNodes()) {
|
|
this.processNodeList(domNode.childNodes);
|
|
}
|
|
}
|
|
};
|
|
|
|
Slicer.prototype.makeUniqueTitle = function(rawText) {
|
|
// Remove characters other than lowercase alphanumeric and spaces
|
|
var prefix = this.baseTiddlerTitle,
|
|
self = this,
|
|
cleanText;
|
|
if(rawText) {
|
|
// Replace non alpha characters with spaces
|
|
cleanText = rawText.toLowerCase().replace(/[^\s\xA0]/mg,function($0,$1,$2) {
|
|
if(($0 >= "a" && $0 <= "z") || ($0 >= "0" && $0 <= "9")) {
|
|
return $0;
|
|
} else {
|
|
return " ";
|
|
}
|
|
});
|
|
// Split on word boundaries
|
|
var words = cleanText.split(/[\s\xA0]+/mg);
|
|
// Remove common words
|
|
words = words.filter(function(word) {
|
|
return word && ("the and a of on i".split(" ").indexOf(word) === -1);
|
|
});
|
|
// Accumulate the number of words that will fit
|
|
var c = 0,
|
|
s = "";
|
|
while(c < words.length && (s.length + words[c].length + 1) < 50) {
|
|
s += "-" + words[c++];
|
|
}
|
|
prefix = prefix + s;
|
|
}
|
|
// Check for duplicates
|
|
var baseTitle = prefix;
|
|
c = 0;
|
|
var title = baseTitle;
|
|
while(this.getTiddler(title)) {
|
|
title = baseTitle + "-" + (++c);
|
|
}
|
|
return title;
|
|
};
|
|
|
|
Slicer.prototype.addTiddler = function(fields) {
|
|
if(fields.title) {
|
|
this.extractedTiddlers[fields.title] = Object.assign({},fields);
|
|
}
|
|
return fields.title;
|
|
};
|
|
|
|
Slicer.prototype.addTiddlers = function(fieldsArray) {
|
|
var self = this;
|
|
(fieldsArray || []).forEach(function(fields) {
|
|
self.addTiddler(fields);
|
|
});
|
|
};
|
|
|
|
Slicer.prototype.getTiddler = function(title) {
|
|
return this.extractedTiddlers[title];
|
|
};
|
|
|
|
Slicer.prototype.getTiddlers = function() {
|
|
var self = this;
|
|
return Object.keys(this.extractedTiddlers).map(function(title) {
|
|
return self.extractedTiddlers[title]
|
|
})
|
|
};
|
|
|
|
exports.Slicer = Slicer;
|
|
|
|
})();
|