mirror of
https://gitlab.com/octtspacc/OcttKB
synced 2025-01-10 05:47:33 +01:00
224 lines
6.4 KiB
JavaScript
224 lines
6.4 KiB
JavaScript
|
/*\
|
||
|
module-type: library
|
||
|
|
||
|
Utility methods for relink.
|
||
|
|
||
|
\*/
|
||
|
|
||
|
var macroFilter = "[[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]]";
|
||
|
|
||
|
/**This works nearly identically to $tw.modules.getModulesByTypeAsHashmap
|
||
|
* except that this also takes care of migrating V1 relink modules.
|
||
|
*/
|
||
|
exports.getModulesByTypeAsHashmap = function(moduleType, nameField) {
|
||
|
var results = Object.create(null);
|
||
|
$tw.modules.forEachModuleOfType(moduleType, function(title, module) {
|
||
|
var key = module[nameField];
|
||
|
if (key !== undefined) {
|
||
|
results[key] = module;
|
||
|
} else {
|
||
|
for (var entry in module) {
|
||
|
results[entry] = {
|
||
|
relink: module[entry],
|
||
|
report: function() {}};
|
||
|
results[entry][nameField] = entry;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
return results;
|
||
|
};
|
||
|
|
||
|
exports.getTiddlerRelinkReferences = function(wiki, title, context) {
|
||
|
var tiddler = wiki.getTiddler(title),
|
||
|
references = Object.create(null),
|
||
|
options = {settings: context, wiki: wiki};
|
||
|
if (tiddler) {
|
||
|
try {
|
||
|
for (var relinker in getRelinkOperators()) {
|
||
|
getRelinkOperators()[relinker].report(tiddler, function(title, blurb) {
|
||
|
references[title] = references[title] || [];
|
||
|
references[title].push(blurb || '');
|
||
|
}, options);
|
||
|
}
|
||
|
} catch (e) {
|
||
|
if (e.message) {
|
||
|
e.message = e.message + "\nWhen reporting '" + title + "' Relink references";
|
||
|
}
|
||
|
throw e;
|
||
|
}
|
||
|
}
|
||
|
return references;
|
||
|
};
|
||
|
|
||
|
/** Returns a pair like this,
|
||
|
* { title: {field: entry, ... }, ... }
|
||
|
*/
|
||
|
exports.getRelinkResults = function(wiki, fromTitle, toTitle, context, tiddlerList, options) {
|
||
|
options = options || {};
|
||
|
options.wiki = options.wiki || wiki;
|
||
|
fromTitle = (fromTitle || "").trim();
|
||
|
toTitle = (toTitle || "").trim();
|
||
|
var changeList = Object.create(null);
|
||
|
if(fromTitle && toTitle !== undefined) {
|
||
|
if (tiddlerList === undefined) {
|
||
|
tiddlerList = wiki.getRelinkableTitles();
|
||
|
}
|
||
|
for (var i = 0; i < tiddlerList.length; i++) {
|
||
|
var title = tiddlerList[i];
|
||
|
var tiddler = wiki.getTiddler(title);
|
||
|
if(tiddler) {
|
||
|
try {
|
||
|
var entries = Object.create(null),
|
||
|
operators = getRelinkOperators();
|
||
|
options.settings = new Contexts.tiddler(wiki, context, title);
|
||
|
for (var operation in operators) {
|
||
|
operators[operation].relink(tiddler, fromTitle, toTitle, entries, options);
|
||
|
}
|
||
|
for (var field in entries) {
|
||
|
// So long as there is one key,
|
||
|
// add it to the change list.
|
||
|
if (tiddler.fields["plugin-type"]) {
|
||
|
// We never change plugins, even if they have links
|
||
|
changeList[title] = {};
|
||
|
changeList[title][field] = {impossible: true};
|
||
|
} else {
|
||
|
changeList[title] = entries;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
} catch (e) {
|
||
|
// Should we test for instanceof Error instead?: yes
|
||
|
// Does that work in the testing environment?: no
|
||
|
if (e.message) {
|
||
|
e.message = e.message + "\nWhen relinking '" + title + "'";
|
||
|
}
|
||
|
throw e;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return changeList;
|
||
|
};
|
||
|
|
||
|
var Contexts = $tw.modules.applyMethods('relinkcontext');
|
||
|
|
||
|
exports.getContext = function(name) {
|
||
|
return Contexts[name];
|
||
|
};
|
||
|
|
||
|
exports.getWikiContext = function(wiki) {
|
||
|
// This gives a fresh context every time. It is up to the indexer or
|
||
|
// the cache to preserve those contexts for as long as needed.
|
||
|
var whitelist = new Contexts.whitelist(wiki);
|
||
|
return new Contexts.import(wiki, whitelist, macroFilter);
|
||
|
};
|
||
|
|
||
|
/** Returns the Relink indexer, or a dummy object which pretends to be one.
|
||
|
*/
|
||
|
exports.getIndexer = function(wiki) {
|
||
|
if (!wiki._relink_indexer) {
|
||
|
wiki._relink_indexer = (wiki.getIndexer && wiki.getIndexer("RelinkIndexer")) || new (require('$:/plugins/flibbles/relink/js/utils/backupIndexer.js'))(wiki);
|
||
|
}
|
||
|
return wiki._relink_indexer;
|
||
|
};
|
||
|
|
||
|
/**Relinking supports a cache that persists throughout a whole relink op.
|
||
|
* This is because the Tiddlywiki caches may get wiped multiple times
|
||
|
* throughout the course of a relink.
|
||
|
*/
|
||
|
exports.getCacheForRun = function(options, cacheName, initializer) {
|
||
|
options.cache = options.cache || Object.create(null);
|
||
|
if (!$tw.utils.hop(options.cache, cacheName)) {
|
||
|
options.cache[cacheName] = initializer();
|
||
|
}
|
||
|
return options.cache[cacheName];
|
||
|
};
|
||
|
|
||
|
/**Returns a specific relinker.
|
||
|
* This is useful for wikitext rules which need to parse a filter or a list
|
||
|
*/
|
||
|
exports.getType = function(name) {
|
||
|
var Handler = getFieldTypes()[name];
|
||
|
return Handler ? new Handler() : undefined;
|
||
|
};
|
||
|
|
||
|
exports.getTypes = function() {
|
||
|
// We don't return fieldTypes, because we don't want it modified,
|
||
|
// and we need to filter out legacy names.
|
||
|
var rtn = Object.create(null);
|
||
|
for (var type in getFieldTypes()) {
|
||
|
var typeObject = getFieldTypes()[type];
|
||
|
rtn[typeObject.typeName] = typeObject;
|
||
|
}
|
||
|
return rtn;
|
||
|
};
|
||
|
|
||
|
exports.getDefaultType = function(wiki) {
|
||
|
var tiddler = wiki.getTiddler("$:/config/flibbles/relink/settings/default-type");
|
||
|
var defaultType = tiddler && tiddler.fields.text;
|
||
|
// make sure the default actually exists, otherwise default
|
||
|
return fieldTypes[defaultType] ? defaultType : "title";
|
||
|
};
|
||
|
|
||
|
exports.touchModifyField = function(wiki) {
|
||
|
var tiddler = wiki.getTiddler("$:/config/flibbles/relink/touch-modify");
|
||
|
return tiddler && tiddler.fields.text.trim() === "yes";
|
||
|
};
|
||
|
|
||
|
/**Given some text, and a param or attribute within that text, this returns
|
||
|
* what type of quotation that attribute is using.
|
||
|
*
|
||
|
* param: An object in the form {end:, ...}
|
||
|
*/
|
||
|
exports.determineQuote = function(text, param) {
|
||
|
var pos = param.end-1;
|
||
|
if (text[pos] === "'") {
|
||
|
return "'";
|
||
|
}
|
||
|
if (text[pos] === '"') {
|
||
|
if (text.substr(pos-2, 3) === '"""') {
|
||
|
return '"""';
|
||
|
} else {
|
||
|
return '"';
|
||
|
}
|
||
|
}
|
||
|
if (text.substr(pos-1,2) === ']]' && text.substr((pos-param.value.length)-3, 2) === '[[') {
|
||
|
return "[[";
|
||
|
}
|
||
|
return '';
|
||
|
};
|
||
|
|
||
|
var fieldTypes;
|
||
|
|
||
|
function getFieldTypes() {
|
||
|
if (!fieldTypes) {
|
||
|
fieldTypes = Object.create(null);
|
||
|
$tw.modules.forEachModuleOfType("relinkfieldtype", function(title, exports) {
|
||
|
function NewType() {};
|
||
|
NewType.prototype = exports;
|
||
|
NewType.typeName = exports.name;
|
||
|
fieldTypes[exports.name] = NewType;
|
||
|
// For legacy, if the NewType doesn't have a report method, we add one
|
||
|
if (!exports.report) {
|
||
|
exports.report = function() {};
|
||
|
}
|
||
|
// Also for legacy, some of the field types can go by other names
|
||
|
if (exports.aliases) {
|
||
|
$tw.utils.each(exports.aliases, function(alias) {
|
||
|
fieldTypes[alias] = NewType;
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
return fieldTypes;
|
||
|
}
|
||
|
|
||
|
var relinkOperators;
|
||
|
|
||
|
function getRelinkOperators() {
|
||
|
if (!relinkOperators) {
|
||
|
relinkOperators = exports.getModulesByTypeAsHashmap('relinkoperator', 'name');
|
||
|
}
|
||
|
return relinkOperators;
|
||
|
};
|